diff --git a/arch/aarch64/code.c b/arch/aarch64/code.c index ac0b233fb..2645c68a7 100644 --- a/arch/aarch64/code.c +++ b/arch/aarch64/code.c @@ -1,5 +1,6 @@ /* $Id$ */ /* + * Copyright (c) 2025, 2026 Hakan Candar (hakan@candar.tr). * Copyright (c) 2020 Puresoftware Ltd. * * Permission to use, copy, modify, and distribute this software for any @@ -20,13 +21,15 @@ */ #include +#include #include "pass1.h" -#include "pass2.h" #ifdef LANG_CXX #define p1listf listf #define p1tfree tfree +#define sss sap +#define ssdesc attr #else #define NODE P1ND #define talloc p1alloc @@ -38,11 +41,12 @@ #define n_qual pqual #undef n_df #define n_df pdf -#define sap sss #define n_ap pss #endif static int rvnr; +int p1maxstacksize = 0; /* XXX - remove, move calculation to pass2 */ + /* * Print out assembler segment name. @@ -56,15 +60,18 @@ setseg(int seg, char *name) case LDATA: name = ".data"; break; case UDATA: break; #ifdef MACHOABI + case PICLDATA: + case PICDATA: name = ".section .data.rel.rw,\"aw\""; break; + case PICRDATA: name = ".section .data.rel.ro,\"aw\""; break; case RDATA: name = ".const_data"; break; case STRNG: name = ".cstring"; break; #else case RDATA: name = ".section .rodata"; break; case STRNG: name = ".section .rodata"; break; -#endif case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break; case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; +#endif case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; @@ -99,16 +106,47 @@ defloc(struct symtab *sp) printf(LABFMT ":\n", sp->soffset); } +/* + * Create a node on stack storage. + * + * This is almost equivalent to cstknode(), with the + * exception that this never creates TEMP nodes, only + * stack nodes. + * + * XXX - I suggest this to be moved to ccom/trees.c + * & cxxcom/trees.c as a generic routine. + */ +static NODE * +mkstknode(TWORD t, union dimfun *df, struct ssdesc *ss) +{ + struct symtab s; + NODE *n; + + s.stype = t; + s.squal = 0; + s.sdf = df; + s.sap = 0; + s.sss = ss; + s.sclass = AUTO; + s.soffset = NOOFFSET; + s.sname = "mkstknode"; /* or else nametree() accesses invalid string */ + + oalloc(&s, &autooff); + n = nametree(&s); + n->n_sp = 0; + return n; +} + /* Put a symbol in a temporary * used by bfcode() and its helpers */ static void -putintemp(struct symtab *sym) +putintemp(struct symtab *sym, NODE *q) { NODE *p; - p = tempnode(0, sym->stype, sym->sdf, sym->sap); - p = buildtree(ASSIGN, p, nametree(sym)); + p = tempnode(0, sym->stype, sym->sdf, sym->sss); + p = buildtree(ASSIGN, p, q); sym->soffset = regno(p->n_left); sym->sflags |= STNODE; ecomp(p); @@ -117,151 +155,77 @@ putintemp(struct symtab *sym) /* setup a 64-bit parameter (double/ldouble/longlong) * used by bfcode() */ static void -param_64bit(struct symtab *sym, int *argofsp, int dotemps) +param_64bit(struct symtab *sym, int *regp, int *stackofsp, int dotemps) { - int argofs = *argofsp; - NODE *p, *q; - int navail; - -#if ALLONGLONG == 64 - /* alignment */ - ++argofs; - argofs &= ~1; - *argofsp = argofs; -#endif - - navail = NARGREGS - argofs; + NODE *q; - if (navail < 2) { - /* half in and half out of the registers */ - if (features(FEATURE_BIGENDIAN)) { - cerror("param_64bit"); - p = q = NULL; - } else { - q = block(REG, NIL, NIL, INT, 0, 0); - regno(q) = R0 + argofs; - if (dotemps) { - q = block(SCONV, q, NIL, - ULONGLONG, 0, 0); - p = nametree(sym); - p->n_type = ULONGLONG; - p->n_df = 0; - p->n_ap = NULL; - p = block(LS, p, bcon(32), ULONGLONG, 0, 0); - q = block(PLUS, p, q, ULONGLONG, 0, 0); - p = tempnode(0, ULONGLONG, 0, 0); - sym->soffset = regno(p); - sym->sflags |= STNODE; - } else { - p = nametree(sym); - regno(p) = sym->soffset; - p->n_type = INT; - p->n_df = 0; - p->n_ap = NULL; - } + if (*regp >= NARGREGS) { + sym->soffset = *stackofsp + ARGINIT; + q = nametree(sym); + *stackofsp += SZLONG; + if (dotemps) { + putintemp(sym, q); } - p = buildtree(ASSIGN, p, q); - ecomp(p); - *argofsp = argofs + 2; - return; - } - - q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); - regno(q) = R16 + argofs; - if (dotemps) { - p = tempnode(0, sym->stype, sym->sdf, sym->sap); - sym->soffset = regno(p); - sym->sflags |= STNODE; } else { - p = nametree(sym); + q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sss); + regno(q) = R0 + (*regp)++; + putintemp(sym, q); } - p = buildtree(ASSIGN, p, q); - ecomp(p); - *argofsp = argofs + 2; } -/* setup a 32-bit param on the stack +/* setup a 32-bit param * used by bfcode() */ static void -param_32bit(struct symtab *sym, int *argofsp, int dotemps) +param_32bit(struct symtab *sym, int *regp, int *stackofsp, int dotemps) { - NODE *p, *q; - - q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); - regno(q) = R0 + (*argofsp)++; - if (dotemps) { - p = tempnode(0, sym->stype, sym->sdf, sym->sap); - sym->soffset = regno(p); - sym->sflags |= STNODE; - } else { - p = nametree(sym); - } - p = buildtree(ASSIGN, p, q); - ecomp(p); + /* On aarch64, setup of 32-bit and 64-bit args + are equivalent. + Each argument either occupies one register, + or 8-byte aligned stack. + */ + param_64bit(sym, regp, stackofsp, dotemps); } -/* setup a double param on the stack +/* setup a double param * used by bfcode() */ static void -param_double(struct symtab *sym, int *argofsp, int dotemps) +param_double(struct symtab *sym, int *fregp, int *stackofsp, int dotemps) { - NODE *p, *q, *t; - int tmpnr; - - /* - * we have to dump the float from the general register - * into a temp, since the register allocator doesn't like - * floats to be in CLASSA. This may not work for -xtemps. - */ - - t = tempnode(0, ULONGLONG, 0, 0); - tmpnr = regno(t); - q = block(REG, NIL, NIL, INT, 0, 0); - q->n_rval = R16 + (*argofsp)++; - p = buildtree(ASSIGN, t, q); - ecomp(p); + NODE *q; - if (dotemps) { - sym->soffset = tmpnr; - sym->sflags |= STNODE; + /* Only hard-float ABI reaches here. + soft-float ABI parameters are handled + by param_64bit. + */ + if (*fregp >= NARGREGS) { + sym->soffset = *stackofsp + ARGINIT; + q = nametree(sym); + *stackofsp += SZLONG; + if (dotemps) { + putintemp(sym, q); + } } else { - q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); - p = nametree(sym); - p = buildtree(ASSIGN, p, q); - ecomp(p); + q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sss); + regno(q) = V0 + (*fregp)++; + putintemp(sym, q); } } -/* setup a float param on the stack +/* setup a float param * used by bfcode() */ static void -param_float(struct symtab *sym, int *argofsp, int dotemps) +param_float(struct symtab *sym, int *fregp, int *stackofsp, int dotemps) { - NODE *p, *q, *t; - int tmpnr; - - /* - * we have to dump the float from the general register - * into a temp, since the register allocator doesn't like - * floats to be in CLASSA. This may not work for -xtemps. - */ - - t = tempnode(0, INT, 0, 0); - tmpnr = regno(t); - q = block(REG, NIL, NIL, INT, 0, 0); - q->n_rval = R0 + (*argofsp)++; - p = buildtree(ASSIGN, t, q); - ecomp(p); - - if (dotemps) { - sym->soffset = tmpnr; - sym->sflags |= STNODE; - } else { - q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); - p = nametree(sym); - p = buildtree(ASSIGN, p, q); - ecomp(p); - } + /* Only hard-float ABI reaches here. + soft-float ABI parameters are handled + by param_32bit. + + On aarch64, setup of 32-bit and 64-bit FP args + are equivalent. + Each argument either occupies one register, + or 8-byte aligned stack. + */ + param_double(sym, fregp, stackofsp, dotemps); } /* setup the hidden pointer to struct return parameter @@ -271,10 +235,10 @@ param_retstruct(void) { NODE *p, *q; - p = tempnode(0, PTR-FTN+cftnsp->stype, 0, cftnsp->sap); + p = tempnode(0, PTR-FTN+cftnsp->stype, 0, cftnsp->sss); rvnr = regno(p); - q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); - regno(q) = R0; + q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sss); + regno(q) = R8; p = buildtree(ASSIGN, p, q); ecomp(p); } @@ -284,32 +248,101 @@ param_retstruct(void) * push the registers out to memory * used by bfcode() */ static void -param_struct(struct symtab *sym, int *argofsp) +param_struct(struct symtab *sym, int *regp, int *fregp, int *stackofsp) { - int argofs = *argofsp; - NODE *p, *q; + int reg = *regp; + NODE *p, *q, *s; int navail; - int sz; - int off; + int sz, szb; int num; int i; - navail = NARGREGS - argofs; - sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT; - off = ARGINIT/SZINT + argofs; - num = sz > navail ? navail : sz; - for (i = 0; i < num; i++) { - q = block(REG, NIL, NIL, INT, 0, 0); - regno(q) = R0 + argofs++; - p = block(REG, NIL, NIL, INT, 0, 0); - regno(p) = SP; - p = block(PLUS, p, bcon(4*off++), INT, 0, 0); - p = block(UMUL, p, NIL, INT, 0, 0); - p = buildtree(ASSIGN, p, q); - ecomp(p); + navail = NARGREGS - reg; + navail = navail < 0 ? 0 : navail; + sz = tsize(sym->stype, sym->sdf, sym->sss); + szb = sz / SZCHAR; + num = (sz+SZLONGLONG-1) / SZLONGLONG; /* ceil(sz/8) */ + + /* XXX - HFA structs are not handled yet */ + + if (szb > 16) { + /* + * the struct is larger than 16 bytes. it was copied by the caller + * and lives in their stack frame. obtain the pointer to it. + */ + /* + * XXX: Unnecessary copy. + * For ABI reasons, this C "struct by value" parameter is actually + * passed indirectly (hidden pointer). Our IR/symbol model cannot + * currently represent "indirect-by-ABI" params, so we materialize + * a local stack copy and treat it as the canonical object. + * + * Proper fix: represent indirect struct params explicitly (e.g. param + * becomes a PTR-to-struct with implicit deref at uses), or perform a + * dedicated IR lowering pass that rewrites references to use the hidden + * pointer instead of forcing a memcpy. + */ + s = cstknode(sym->stype, sym->sdf, sym->sss); + sym->soffset = AUTOINIT - autooff; + + if (navail == 0) { + /* + * we have no free argument register left, read pointer + * from stack. + */ + q = block(REG, NIL, NIL, INCREF(PTR+STRTY), 0, sym->sss); + regno(q) = FPREG; + q = block(PLUS, q, bcon(ARGINIT/SZCHAR + *stackofsp), INCREF(PTR+STRTY), 0, sym->sss); + *stackofsp += SZLONGLONG; + q = buildtree(UMUL, q, 0); + + /* XXX - perform unnecessary copy */ + q = buildtree(UMUL, q, 0); + p = buildtree(ASSIGN, s, q); + ecomp(p); + } else { + /* + * we have at least one free argument register, read the + * pointer from the available register. + */ + q = block(REG, NIL, NIL, PTR+STRTY, 0, sym->sss); + regno(q) = R0 + reg++; + + /* XXX - perform unnecessary copy */ + q = buildtree(UMUL, q, 0); + p = buildtree(ASSIGN, s, q); + ecomp(p); + } + } else { + /* + * the struct is <=16 bytes in size. it was packed by the caller. + */ + if (navail < num) { + /* + * we are over available argument registers. + * the caller pushed the struct to the call stack. + */ + sym->soffset = ARGINIT + *stackofsp; + *stackofsp += num * SZLONGLONG; + } else { + /* + * we have enough free argument registers. + * reconstruct the packed struct in the stack. + */ + for (i = 0; i < num; i++) { + s = mkstknode(LONGLONG, 0, 0); /* 8-byte chunk */ + q = block(REG, NIL, NIL, LONGLONG, 0, 0); + regno(q) = R0 + reg + num-i-1; + p = buildtree(ASSIGN, s, q); + ecomp(p); + if (i == num - 1) + sym->soffset = AUTOINIT - autooff; + } + reg += num; + } } - *argofsp = argofs; + *regp = reg; } @@ -322,20 +355,28 @@ param_struct(struct symtab *sym, int *argofsp) void bfcode(struct symtab **sp, int cnt) { - int saveallargs = 0; - int i, argofs = 0; + int saveallargs, i, reg, freg, stackofs; + saveallargs = i = reg = freg = stackofs = 0; + p1maxstacksize = 0; +#if defined(MACHOABI) + /* + * On aarch64 Darwin ABI, varargs are already spilled + * to memory by caller. No need to spill from callee side. + */ + saveallargs = 0; +#else /* * Detect if this function has ellipses and save all * argument registers onto stack. */ if (cftnsp->sdf->dlst) saveallargs = pr_hasell(cftnsp->sdf->dlst); +#endif /* if returning a structure, move the hidden argument into a TEMP */ if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { param_retstruct(); - ++argofs; } /* recalculate the arg offset and create TEMP moves */ @@ -344,40 +385,32 @@ bfcode(struct symtab **sp, int cnt) if (sp[i] == NULL) continue; - if ((argofs >= NARGREGS) && !xtemps) - break; - - if (argofs > NARGREGS) { - putintemp(sp[i]); - } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) { - param_struct(sp[i], &argofs); + if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) { + param_struct(sp[i], ®, &freg, &stackofs); } else if (DEUNSIGN(sp[i]->stype) == LONGLONG || DEUNSIGN(sp[i]->stype) == LONG) { - param_64bit(sp[i], &argofs, xtemps && !saveallargs); + param_64bit(sp[i], ®, &stackofs, xtemps && !saveallargs); } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) { if (features(FEATURE_HARDFLOAT)) - param_double(sp[i], &argofs, - xtemps && !saveallargs); + param_double(sp[i], &freg, &stackofs, xtemps && !saveallargs); else - param_64bit(sp[i], &argofs, - xtemps && !saveallargs); + param_64bit(sp[i], ®, &stackofs, xtemps && !saveallargs); } else if (sp[i]->stype == FLOAT) { if (features(FEATURE_HARDFLOAT)) - param_float(sp[i], &argofs, - xtemps && !saveallargs); + param_float(sp[i], &freg, &stackofs, xtemps && !saveallargs); else - param_32bit(sp[i], &argofs, - xtemps && !saveallargs); + param_32bit(sp[i], ®, &stackofs, xtemps && !saveallargs); } else { - param_32bit(sp[i], &argofs, xtemps && !saveallargs); + param_32bit(sp[i], ®, &stackofs, xtemps && !saveallargs); } } /* if saveallargs, save the rest of the args onto the stack */ - while (saveallargs && argofs < NARGREGS) { + /* XXX - investigate, rewrite for FP regs */ + while (saveallargs && reg < NARGREGS) { NODE *p, *q; - int off = ARGINIT/SZINT + argofs; + int off = ARGINIT/SZINT + reg; q = block(REG, NIL, NIL, INT, 0, 0); - regno(q) = R0 + argofs++; + regno(q) = R0 + reg++; p = block(REG, NIL, NIL, INT, 0, 0); regno(p) = SPREG; p = block(PLUS, p, bcon(4*off), INT, 0, 0); @@ -394,38 +427,67 @@ bfcode(struct symtab **sp, int cnt) void efcode(void) { - NODE *p, *q; - int tempnr; + NODE *p, *q, *t; + int tempnr, sz, szb, num, i; if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; + sz = tsize(DECREF(cftnsp->stype), cftnsp->sdf, cftnsp->sss); + szb = sz / SZCHAR; + num = (sz+SZLONGLONG-1) / SZLONGLONG; + /* * 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->sap); + q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sss); q->n_rval = R0; - p = tempnode(0, PTR+STRTY, 0, cftnsp->sap); + p = tempnode(0, PTR+STRTY, 0, cftnsp->sss); tempnr = regno(p); p = buildtree(ASSIGN, p, q); ecomp(p); /* get the address from the tempnode */ - q = tempnode(tempnr, PTR+STRTY, 0, cftnsp->sap); - q = buildtree(UMUL, q, NIL); + q = tempnode(tempnr, PTR+STRTY, 0, cftnsp->sss); - /* now, get the structure destination */ - p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->sap); - p = buildtree(UMUL, p, NIL); - - /* struct assignment */ - p = buildtree(ASSIGN, p, q); - ecomp(p); + if (szb > 16) { + /* + * Struct exceeds 16 bytes in size. + * We want to copy the contents from there to the address + * we placed into the tempnode "rvnr". + */ + q = buildtree(UMUL, q, NIL); + /* get the structure destination */ + p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->sss); + p = buildtree(UMUL, p, NIL); + + /* struct assignment */ + p = buildtree(ASSIGN, p, q); + ecomp(p); + } else { + /* + * Struct is <= 16 bytes in size. + * We want to place the contents from there to + * R0, and if >8 bytes R1. + */ + for (i = 0; i < num; i++) { + /* divide struct to 8-byte chunk */ + t = block(SCONV, tcopy(q), NIL, PTR+LONGLONG, 0, 0); + t = block(PLUS, t, bcon(8*i), PTR+LONGLONG, 0, 0); + t = buildtree(UMUL, t, NIL); + + /* get return register (R0 or R1) */ + p = block(REG, NIL, NIL, LONGLONG, 0, 0); + regno(p) = R0 + num-i-1; + + /* register assignment */ + p = buildtree(ASSIGN, p, t); + ecomp(p); + } + } } /* @@ -445,6 +507,9 @@ ejobcode(int flag) void bjobcode(void) { + /* aarch64 names for some asm constant printouts */ + astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; + astypnames[LONG] = astypnames[ULONG] = "\t.quad"; } /* @@ -531,7 +596,7 @@ reverse(NODE *p) /* push arg onto the stack */ /* called by moveargs() */ static NODE * -pusharg(NODE *p, int *regp) +pusharg(NODE *p, int *stackofsp) { NODE *q; int sz; @@ -544,248 +609,188 @@ pusharg(NODE *p, int *regp) q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = SP; - if (szty(p->n_type) == 1) { - ++(*regp); - q = block(MINUSEQ, q, bcon(4), INT, 0, 0); - } else { - (*regp) += 2; - q = block(MINUSEQ, q, bcon(8), INT, 0, 0); - } + q = block(PLUS, q, bcon(*stackofsp), INT, 0, 0); + *stackofsp += SZLONG / 8; q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_ap); return buildtree(ASSIGN, q, p); } -/* setup call stack with 32-bit argument */ + +/* setup call stack with 64-bit argument */ /* called from moveargs() */ static NODE * -movearg_32bit(NODE *p, int *regp) +movearg_64bit(NODE *p, int *regp) { int reg = *regp; NODE *q; q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); - regno(q) = reg++; + regno(q) = R0 + reg++; q = buildtree(ASSIGN, q, p); *regp = reg; return q; } -/* setup call stack with 64-bit argument */ +/* setup call stack with 32-bit argument */ /* called from moveargs() */ static NODE * -movearg_64bit(NODE *p, int *regp) +movearg_32bit(NODE *p, int *regp) { - int reg = *regp; - NODE *q, *r; - -#if ALLONGLONG == 64 - /* alignment */ - ++reg; - reg &= ~1; - *regp = reg; -#endif - - if (reg > R3) { - q = pusharg(p, regp); - } else if (reg == R3) { - /* half in and half out of the registers */ - r = tcopy(p); - if (!features(FEATURE_BIGENDIAN)) { - q = block(SCONV, p, NIL, INT, 0, 0); - q = movearg_32bit(q, regp); /* little-endian */ - r = buildtree(RS, r, bcon(32)); - r = block(SCONV, r, NIL, INT, 0, 0); - r = pusharg(r, regp); /* little-endian */ - } else { - q = buildtree(RS, p, bcon(32)); - q = block(SCONV, q, NIL, INT, 0, 0); - q = movearg_32bit(q, regp); /* big-endian */ - r = block(SCONV, r, NIL, INT, 0, 0); - r = pusharg(r, regp); /* big-endian */ - } - q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_ap)); - } else { - q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); - regno(q) = R16 + (reg - R0); - q = buildtree(ASSIGN, q, p); - *regp = reg + 2; - } - - return q; + /* On aarch64, passing of 32-bit and 64-bit args + are equivalent. + Each argument either occupies one register, + or 8-byte aligned stack. + */ + return movearg_64bit(p, regp); } + /* setup call stack with float/double argument */ /* called from moveargs() */ static NODE * -movearg_float(NODE *p, int *regp) +movearg_double(NODE *p, int *regp) { - NODE *q, *r; - TWORD ty = INCREF(p->n_type); - int tmpnr; - - /* - * Floats are passed in the general registers for - * compatibily with libraries compiled to handle soft-float. - */ - - if (xtemps) { - /* bounce on TOS */ - r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap); - regno(r) = SP; - r = block(PLUS, r, bcon(-4), ty, p->n_df, p->n_ap); - r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap); - r = buildtree(ASSIGN, r, p); - ecomp(r); - - /* bounce into temp */ - r = block(REG, NIL, NIL, PTR+INT, 0, 0); - regno(r) = SP; - r = block(PLUS, r, bcon(-8), PTR+INT, 0, 0); - r = block(UMUL, r, NIL, INT, 0, 0); - q = tempnode(0, INT, 0, 0); - tmpnr = regno(q); - r = buildtree(ASSIGN, q, r); - ecomp(r); - } else { - /* copy directly into temp */ - q = tempnode(0, p->n_type, p->n_df, p->n_ap); - tmpnr = regno(q); - r = buildtree(ASSIGN, q, p); - ecomp(r); - } + /* Only hard-float ABI reaches here. + soft-float ABI parameters are handled + by movearg_64bit. + */ + int reg = *regp; + NODE *q; - /* copy from temp to register parameter */ - r = tempnode(tmpnr, INT, 0, 0); - q = block(REG, NIL, NIL, INT, 0, 0); - regno(q) = (*regp)++; - p = buildtree(ASSIGN, q, r); + q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); + regno(q) = V0 + reg++; + q = buildtree(ASSIGN, q, p); - return p; + *regp = reg; + return q; } /* setup call stack with float/double argument */ /* called from moveargs() */ static NODE * -movearg_double(NODE *p, int *regp) +movearg_float(NODE *p, int *regp) { - NODE *q, *r; - TWORD ty = INCREF(p->n_type); - int tmpnr; - - if (xtemps) { - /* bounce on TOS */ - r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap); - regno(r) = SP; - r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_ap); - r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap); - r = buildtree(ASSIGN, r, p); - ecomp(r); - - /* bounce into temp */ - r = block(REG, NIL, NIL, PTR+LONGLONG, 0, 0); - regno(r) = SP; - r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, 0); - r = block(UMUL, r, NIL, LONGLONG, 0, 0); - q = tempnode(0, LONGLONG, 0, 0); - tmpnr = regno(q); - r = buildtree(ASSIGN, q, r); - ecomp(r); - } else { - /* copy directly into temp */ - q = tempnode(0, p->n_type, p->n_df, p->n_ap); - tmpnr = regno(q); - r = buildtree(ASSIGN, q, p); - ecomp(r); - } - - /* copy from temp to register parameter */ - r = tempnode(tmpnr, LONGLONG, 0, 0); - q = block(REG, NIL, NIL, LONGLONG, 0, 0); - regno(q) = R16 - R0 + (*regp); - p = buildtree(ASSIGN, q, r); - - (*regp) += 2; - - return p; + /* Only hard-float ABI reaches here. + soft-float ABI parameters are handled + by movearg_32bit. + + On aarch64, passing of 32-bit and 64-bit FP args + are equivalent. + Each argument either occupies one register, + or 8-byte aligned stack. + */ + return movearg_double(p, regp); } - /* setup call stack with a structure */ /* called from moveargs() */ static NODE * -movearg_struct(NODE *p, int *regp) +movearg_struct(NODE *p, int *regp, int *fregp, int *stackofsp) { int reg = *regp; - NODE *l, *q, *t, *r; - int tmpnr; + NODE *l, *q, *t, *r, *s; int navail; int num; - int sz; - int ty; + int sz, szb; int i; assert(p->n_op == STARG); - navail = NARGREGS - (reg - R0); + navail = NARGREGS - reg; navail = navail < 0 ? 0 : navail; - sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT; - num = sz > navail ? navail : sz; + sz = tsize(p->n_type, p->n_df, p->n_ap); + szb = sz / SZCHAR; + num = (sz+SZLONGLONG-1) / SZLONGLONG; /* ceil(sz/8) */ /* remove STARG node */ l = p->n_left; nfree(p); - ty = l->n_type; - /* - * put it into a TEMP, rather than tcopy(), since the tree - * in p may have side-affects - */ - t = tempnode(0, ty, l->n_df, l->n_ap); - tmpnr = regno(t); - q = buildtree(ASSIGN, t, l); - - /* copy structure into registers */ - for (i = 0; i < num; i++) { - t = tempnode(tmpnr, ty, 0, 0); - t = block(SCONV, t, NIL, PTR+INT, 0, 0); - t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); - t = buildtree(UMUL, t, NIL); - - r = block(REG, NIL, NIL, INT, 0, 0); - regno(r) = reg++; - r = buildtree(ASSIGN, r, t); - - q = block(CM, q, r, INT, 0, 0); - } + /* XXX - HFA structs are not handled yet */ + + if (szb > 16) { + /* + * the struct is larger than 16 bytes. create a copy of it + * and obtain a pointer to it. + */ + t = buildtree(UMUL, l, NIL); + s = cstknode(t->n_type, t->n_df, t->n_ap); /* free real estate */ + t = buildtree(ASSIGN, s, t); + t = nfree(t); + q = tcopy(s->n_left); /* pointer to copied struct */ + + if (navail == 0) { + /* + * we have no free argument register left, push the pointer + * to the stack. + */ + q = pusharg(q, stackofsp); + } else { + /* + * we have at least one free argument register, move the + * pointer to the available register. + */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, q->n_ap); + regno(r) = R0 + reg++; + q = buildtree(ASSIGN, r, q); + } + q = block(CM, q, t, INT, 0, 0); - /* put the rest of the structure on the stack */ - for (i = num; i < sz; i++) { - t = tempnode(tmpnr, ty, 0, 0); - t = block(SCONV, t, NIL, PTR+INT, 0, 0); - t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); - t = buildtree(UMUL, t, NIL); - r = pusharg(t, ®); - q = block(CM, q, r, INT, 0, 0); + } else { + q = NULL; + if (navail < 2) { + /* + * we have less than 2 free argument registers, and the struct + * is <=16 bytes in size. push the struct on the stack. + */ + for (i = 0; i < num; i++) { + t = block(SCONV, tcopy(l), NIL, PTR+LONGLONG, 0, 0); + t = block(PLUS, t, bcon(8*i), PTR+LONGLONG, 0, 0); + t = buildtree(UMUL, t, NIL); + r = pusharg(t, stackofsp); + + if (i == 0) + q = r; + else + q = block(CM, q, r, INT, 0, 0); + } + } else { + /* + * we have >=2 free argument registers, and the struct + * is <=16 bytes in size. pack the struct in registers. + */ + for (i = 0; i < num; i++) { + t = block(SCONV, tcopy(l), NIL, PTR+LONGLONG, 0, 0); + t = block(PLUS, t, bcon(8*i), PTR+LONGLONG, 0, 0); + t = buildtree(UMUL, t, NIL); + + r = block(REG, NIL, NIL, LONGLONG, 0, 0); + regno(r) = R0 + reg++; + r = buildtree(ASSIGN, r, t); + + if (i == 0) + q = r; + else + q = block(CM, q, r, INT, 0, 0); + } + } + p1tfree(l); } - q = reverse(q); - *regp = reg; return q; } - static NODE * -moveargs(NODE *p, int *regp) +moveargs(NODE *p, int vararg, int *idxp, int *regp, int *fregp, int *stackofsp) { NODE *r, **rp; - int reg; if (p->n_op == CM) { - p->n_left = moveargs(p->n_left, regp); + p->n_left = moveargs(p->n_left, vararg, idxp, regp, fregp, stackofsp); r = p->n_right; rp = &p->n_right; } else { @@ -793,58 +798,36 @@ moveargs(NODE *p, int *regp) rp = &p; } - reg = *regp; + int isfp = features(FEATURE_HARDFLOAT) + && (r->n_type == DOUBLE || r->n_type == LDOUBLE + || r->n_type == FLOAT); - if (reg > R3 && r->n_op != STARG) { - *rp = pusharg(r, regp); - } else if (r->n_op == STARG) { - *rp = movearg_struct(r, regp); + if (r->n_op == STARG) { + *rp = movearg_struct(r, regp, fregp, stackofsp); + } else if ((*idxp >= vararg) + || (isfp && *fregp >= NARGREGS) + || (!isfp && *regp >= NARGREGS)) { + *rp = pusharg(r, stackofsp); } else if (DEUNSIGN(r->n_type) == LONGLONG) { *rp = movearg_64bit(r, regp); } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) { - *rp = movearg_double(r, regp); + if (features(FEATURE_HARDFLOAT)) + *rp = movearg_double(r, fregp); + else + *rp = movearg_64bit(r, regp); } else if (r->n_type == FLOAT) { - *rp = movearg_float(r, regp); + if (features(FEATURE_HARDFLOAT)) + *rp = movearg_float(r, fregp); + else + *rp = movearg_32bit(r, regp); } else { *rp = movearg_32bit(r, regp); } + (*idxp)++; return straighten(p); } -/* - * Fixup arguments to pass pointer-to-struct as first argument. - * - * called from funcode(). - */ -static NODE * -retstruct(NODE *p) -{ - NODE *l, *r, *t, *q; - TWORD ty; - - l = p->n_left; - r = p->n_right; - - ty = DECREF(l->n_type) - FTN; - - /* structure assign */ - q = tempnode(0, ty, l->n_df, l->n_ap); - q = buildtree(ADDROF, q, NIL); - - /* insert hidden assignment at beginning of list */ - if (r->n_op != CM) { - p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap); - } else { - for (t = r; t->n_left->n_op == CM; t = t->n_left) - ; - t->n_left = block(CM, q, t->n_left, INCREF(ty), - l->n_df, l->n_ap); - } - - return p; -} - NODE * builtin_frame_address(const struct bitable *bt, NODE *a) { @@ -866,6 +849,64 @@ builtin_cfa(const struct bitable *bt, NODE *a) return NULL; } +/* + * Sort arglist so that register assignments ends up last. + * Copied over from amd64/code.c. + * + * XXX - This routine creates an absurd amount of read/write + * instructions when -xtemps is disabled. It works, but it + * is suboptimal. + */ +static int +argsort(NODE *p) +{ + NODE *q, *r; + int rv = 0; + + if (p->n_op != CM) { + if (p->n_op == ASSIGN && p->n_left->n_op == REG && + coptype(p->n_right->n_op) != LTYPE) { + q = tempnode(0, p->n_type, p->n_df, p->n_ap); + r = tcopy(q); + p->n_right = buildtree(COMOP, + buildtree(ASSIGN, q, p->n_right), r); + } + return rv; + } + if (p->n_right->n_op == CM) { + /* fixup for small structs in regs */ + q = p->n_right->n_left; + p->n_right->n_left = p->n_left; + p->n_left = p->n_right; + p->n_right = p->n_left->n_right; + p->n_left->n_right = q; + } + if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG && + coptype(p->n_right->n_right->n_op) != LTYPE) { + /* move before everything to avoid reg trashing */ + q = tempnode(0, p->n_right->n_type, + p->n_right->n_df, p->n_right->n_ap); + r = tcopy(q); + p->n_right->n_right = buildtree(COMOP, + buildtree(ASSIGN, q, p->n_right->n_right), r); + } + if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) { + if (p->n_left->n_op == CM && + p->n_left->n_right->n_op == STASG) { + q = p->n_left->n_right; + p->n_left->n_right = p->n_right; + p->n_right = q; + rv = 1; + } else if (p->n_left->n_op == STASG) { + q = p->n_left; + p->n_left = p->n_right; + p->n_right = q; + rv = 1; + } + } + return rv | argsort(p->n_left); +} + /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. @@ -873,17 +914,29 @@ builtin_cfa(const struct bitable *bt, NODE *a) NODE * funcode(NODE *p) { - int reg = R0; + int reg, freg, stackofs, idx; + reg = freg = stackofs = idx = 0; + int vararg = INT_MAX; + +#if defined(MACHOABI) + if (p->n_left->n_df) + vararg = pr_ellidx(p->n_left->n_df->dlst); + if (vararg < 0) + vararg = INT_MAX; +#endif - if (p->n_type == STRTY+FTN || p->n_type == UNIONTY+FTN) { - p = retstruct(p); - reg = R1; - } + p->n_right = moveargs(p->n_right, vararg, &idx, ®, &freg, &stackofs); - p->n_right = moveargs(p->n_right, ®); + /* Must sort arglist so that STASG ends up first */ + /* This avoids registers being clobbered */ + while (argsort(p->n_right)) + ; if (p->n_right == NULL) p->n_op += (UCALL - CALL); + if (stackofs > p1maxstacksize) + p1maxstacksize = stackofs; + return p; } diff --git a/arch/aarch64/local.c b/arch/aarch64/local.c index 9c21b4a31..b53b51456 100644 --- a/arch/aarch64/local.c +++ b/arch/aarch64/local.c @@ -19,7 +19,6 @@ * We define location operations which operate on the expression tree * during the first pass (before sending to the backend for code generation.) */ - #include #include "pass1.h" @@ -30,6 +29,7 @@ #ifdef LANG_CXX #define p1listf listf #define p1tfree tfree +#define sss sap #else #define NODE P1ND #define talloc p1alloc @@ -45,6 +45,7 @@ #endif extern void defalign(int); +static NODE * stret(NODE *p); static char * getsoname(struct symtab *sp) @@ -54,9 +55,49 @@ getsoname(struct symtab *sp) ap->sarg(0) : sp->sname; } -#ifndef LANG_CXX -#define sap sss -#endif +#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) + +/* + * Make a symtab entry for PIC use. + */ +static struct symtab * +picsymtab(char *p, char *s, char *s2) +{ + struct symtab *sp = IALLOC(sizeof(struct symtab)); + size_t len = strlen(p) + strlen(s) + strlen(s2) + 1; + + sp->sname = IALLOC(len); + strlcpy(sp->sname, p, len); + strlcat(sp->sname, s, len); + strlcat(sp->sname, s2, len); + sp->sap = attr_new(ATTR_SONAME, 1); + sp->sap->sarg(0) = sp->sname; + sp->sclass = EXTERN; + sp->sflags = sp->slevel = 0; + return sp; +} + +/* + * Create a reference for an extern variable or function. + */ +static NODE * +picext(NODE *p) +{ + struct symtab *sp; + char *c; + if (ISFTN(p->n_type)) + return p; + if (attr_find(p->n_sp->sap, ATTR_AARCH64_BEENHERE)) + return p; + + c = getexname(p->n_sp); + /* prefix got symbols with '@'. handle instrs in local2.c */ + sp = picsymtab("", "@", c); + p->n_sp = sp; + + sp->sap = attr_add(sp->sap, attr_new(ATTR_AARCH64_BEENHERE, 1)); + return p; +} /* * clocal() is called to do local transformations on @@ -68,10 +109,26 @@ clocal(NODE *p) struct symtab *q; NODE *l, *r, *t; int o; - int ty; - int tmpnr, isptrvoid = 0; + int ty, tyl; char *n; + /* + * Canonicalize LONG to LONGLONG as a safety net. + * + * The frontend normally normalizes target types via ctype(), mapping + * LONG/ULONG to LONGLONG/ULONGLONG for backends that do not support C long + * natively. However, some IR nodes (notably ICONs and SCONVs originating + * from INTPTR handling on trees.c) are constructed without passing their types + * through ctype(), allowing raw LONG to leak into pass2. + * + * This backend mandates that all integer types are already canonicalized + * (i.e. no LONG survives past pass1), so we defensively rewrite LONG here + * to avoid inconsistent IR. This is a workaround; the proper fix is to + * ensure all IR construction paths apply ctype() consistently. + */ + if (p->n_type == LONG) + p->n_type = LONGLONG; + o = p->n_op; switch (o) { case STASG: @@ -97,29 +154,9 @@ clocal(NODE *p) } return r; - case CALL: case STCALL: case USTCALL: - if (p->n_type == VOID) - break; - /* - * if the function returns void*, ecode() invokes - * delvoid() to convert it to uchar*. - * We just let this happen on the ASSIGN to the temp, - * and cast the pointer back to void* on access - * from the temp. - */ - if (p->n_type == PTR+VOID) - isptrvoid = 1; - r = tempnode(0, p->n_type, p->n_df, p->n_ap); - tmpnr = regno(r); - r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap); - - p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); - if (isptrvoid) { - p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0); - } - p = buildtree(COMOP, r, p); + p = stret(p); break; case NAME: @@ -134,7 +171,7 @@ clocal(NODE *p) /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); - r->n_rval = SPREG; + r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case REGISTER: @@ -142,6 +179,13 @@ clocal(NODE *p) slval(p, 0); p->n_rval = q->soffset; break; + case EXTERN: + case EXTDEF: + if (kflag == 0 || statinit) + break; + if (blevel > 0) + p = picext(p); + break; case STATIC: if (q->slevel > 0) { slval(p, 0); @@ -184,23 +228,26 @@ clocal(NODE *p) nfree(p); return l; } - if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && - tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) { - 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; - } + + /* fix LONG that slipped due to INTPTR in trees.c */ + if (l->n_type == LONG) + l->n_type = LONGLONG; + + /* (u)longlong to (u)longlong conversion is free. */ + ty = DEUNSIGN(p->n_type); + tyl = DEUNSIGN(l->n_type); + if ((ty == LONGLONG || ISPTR(p->n_type)) && + (tyl == LONGLONG || ISPTR(l->n_type))) { + if (l->n_op == NAME || l->n_op == UMUL || l->n_op == TEMP) { + l->n_type = p->n_type; + nfree(p); + return l; } } if (l->n_op == ICON) { CONSZ val = glval(l); - CONSZ lval; + CONSZ lval = 0; if (!ISPTR(p->n_type)) /* Pointers don't need to be conv'd */ switch (p->n_type) { @@ -259,6 +306,14 @@ clocal(NODE *p) p->n_left->n_type = INT; return p; } + if ((p->n_type == FLOAT || p->n_type == DOUBLE || + p->n_type == LDOUBLE) && + (DEUNSIGN(l->n_type) == CHAR || + DEUNSIGN(l->n_type) == SHORT)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); + p->n_left->n_type = INT; + return p; + } break; case PCONV: @@ -267,8 +322,8 @@ clocal(NODE *p) slval(l, (unsigned)glval(l)); goto delp; } - if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) { - p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); + if (l->n_type < LONGLONG) { + p->n_left = block(SCONV, l, NIL, LONGLONG, 0, 0); break; } if (l->n_op == SCONV) @@ -292,6 +347,59 @@ clocal(NODE *p) return p; } +/* + * Handle the return value from a call returning a struct. + * + * XXX - This routine would ideally live under code.c, but + * funcode() only gets invoked for function calls that take + * arguments. This routine applies to all struct returning calls. + */ +static NODE * +stret(NODE *p) +{ + NODE *l, *t, *r; + int tmpnr, sz, szb, i, num; + + sz = tsize(DECREF(p->n_type), p->n_df, p->n_ap); + szb = sz / SZCHAR; + num = (sz+SZLONGLONG-1) / SZLONGLONG; + + if (szb > 16) { + t = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); + regno(t) = R8; + l = cstknode(DECREF(p->n_type), p->n_df, p->n_ap); + l = buildtree(ADDROF, l, NIL); + l = buildtree(ASSIGN, t, l); + + r = tempnode(0, p->n_type, p->n_df, p->n_ap); + tmpnr = regno(r); + t = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); + regno(t) = R8; + r = buildtree(ASSIGN, r, t); + + r = buildtree(COMOP, l, r); + r = buildtree(COMOP, r, p); + + p = tempnode(tmpnr, p->n_type, p->n_df, p->n_ap); + p = buildtree(COMOP, r, p); + } else { + r = p; + for (i = 0; i < num; i++) { + l = cstknode(LONGLONG, 0, 0); + t = block(REG, NIL, NIL, LONGLONG, 0, 0); + regno(t) = R0 + num-i-1; + l = buildtree(ASSIGN, l, t); + p = buildtree(COMOP, p, l); + } + t = block(REG, NIL, NIL, PTR+STRTY, r->n_df, r->n_ap); + regno(t) = FPREG; + t = block(PLUS, t, bcon((AUTOINIT-autooff)/SZCHAR), PTR+STRTY, r->n_df, r->n_ap); + p = buildtree(COMOP, p, t); + } + + return p; +} + /* * Called before sending the tree to the backend. */ @@ -307,15 +415,17 @@ myp2tree(NODE *p) sp = IALLOC(sizeof(struct symtab)); sp->sclass = STATIC; + sp->sss = 0; sp->sap = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); + sp->sname = NULL; defloc(sp); - inval(0, tsize(sp->stype, sp->sdf, sp->sap), p); + inval(0, tsize(sp->stype, sp->sdf, sp->sss), p); p->n_op = NAME; slval(p, 0); @@ -385,50 +495,32 @@ spalloc(NODE *t, NODE *p, OFFSZ off) int ninval(CONSZ off, int fsz, NODE *p) { - union { float f; double d; int i[2]; } u; struct symtab *q; TWORD t; - int i, j; + U_CONSZ uval; t = p->n_type; if (t > BTMASK) - t = p->n_type = INT; /* pointer */ + t = p->n_type = LONGLONG; /* pointer */ + + if (t == FLOAT || t == DOUBLE) /* non-integer value */ + return 0; - if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) + if (p->n_op == ICON && p->n_sp != NULL + && !(DEUNSIGN(t) == INT || DEUNSIGN(t) == LONGLONG)) uerror("element not constant"); - switch (t) { - case LONGLONG: - case ULONGLONG: - i = (glval(p) >> 32); - j = (glval(p) & 0xffffffff); - p->n_type = INT; - if (features(FEATURE_BIGENDIAN)) { - slval(p, i); - ninval(off+32, 32, p); - slval(p, j); - ninval(off, 32, p); - } else { - slval(p, j); - ninval(off, 32, p); - slval(p, i); - ninval(off+32, 32, p); - } - break; - case INT: - case UNSIGNED: - printf("\t.word 0x%x", (int)glval(p)); - if ((q = p->n_sp) != NULL) { - if ((q->sclass == STATIC && q->slevel > 0)) { - printf("+" LABFMT, q->soffset); - } else - printf("+%s", getexname(q)); - } - printf("\n"); - break; - default: - return 0; + uval = (glval(p) & SZMASK(sztable[t])); + + printf("%s 0x%llx", astypnames[t], uval); + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0)) { + printf("+" LABFMT, q->soffset); + } else + printf("+%s", getexname(q)); } + printf("\n"); + return 1; } @@ -438,7 +530,26 @@ ninval(CONSZ off, int fsz, NODE *p) char * exname(char *p) { +#ifdef MACHOABI + +#define NCHNAM 256 + static char text[NCHNAM+1]; + int i; + + if (p == NULL) + return ""; + + text[0] = '_'; + for (i=1; *p && istype, sp->sdf, sp->sap); + off = tsize(sp->stype, sp->sdf, sp->sss); off = (off+(SZCHAR-1))/SZCHAR; printf(" .%scomm ", sp->sclass == STATIC ? "l" : ""); if (sp->slevel == 0) diff --git a/arch/aarch64/local2.c b/arch/aarch64/local2.c index 96468156e..6485c1a86 100644 --- a/arch/aarch64/local2.c +++ b/arch/aarch64/local2.c @@ -1,6 +1,7 @@ /* $Id$ */ /* + * Copyright (c) 2025, 2026 Hakan Candar (hakan@candar.tr). * Copyright (c) 2020 Puresoftware Ltd. * * Permission to use, copy, modify, and distribute this software for any @@ -21,53 +22,105 @@ #include #include +#include "pass1.h" /* for astypnames, talign and defalign */ #include "pass2.h" +#define SZFPSP 16 + extern void defalign(int); -int isConverstion=0; -int addStack=0; +static int isShrink=0; +static int isExtend=0; +#ifndef MACHOABI #define exname(x) x +#endif /* In a 32-bit context,registers are specified by using w0-w30 in A64 instruction set */ char *wnames[] = { - "w0", "w1", "w2", "w3","w4","w5", "w6", "w7", - "w8", "w9", "w10","w11","w12","w13","w14", - "w15", "w16","w17","w18","w19","w20", "w21", - "w22","w23","w24","w25","w26","w27","w28", - "w29","w30", + "w0", "w1", "w2", "w3", "w4", "w5", "w6", + "w7", "w8", "w9", "w10", "w11", "w12", "w13", + "w14", "w15", "w16", "w17", "w18", "w19", "w20", + "w21", "w22", "w23", "w24", "w25", "w26", "w27", + "w28", "w29", "w30", "sp", + + "s0", "s1", "s2", "s3", "s4", "s5", "s6", + "s7", "s8", "s9", "s10", "s11", "s12", "s13", + "s14", "s15", "s16", "s17", "s18", "s19", "s20", + "s21", "s22", "s23", "s24", "s25", "s26", "s27", + "s28", "s29", "s30", "s31" }; /* In a 64-bit context,registers are specified by using x0-x30 in A64 instruction set */ char *rnames[] = { - "x0", "x1", "x2", "x3","x4","x5", "x6", "x7", - "x8", "x9", "x10","x11","x12","x13","x14", - "x15", "x16","x17","x18","x19","x20", "x21", - "x22","x23","x24","x25","x26","x27","x28", - "x29","x30","sp", + "x0", "x1", "x2", "x3", "x4", "x5", "x6", + "x7", "x8", "x9", "x10", "x11", "x12", "x13", + "x14", "x15", "x16", "x17", "x18", "x19", "x20", + "x21", "x22", "x23", "x24", "x25", "x26", "x27", + "x28", "x29", "x30", "sp", + + "d0", "d1", "d2", "d3", "d4", "d5", "d6", + "d7", "d8", "d9", "d10", "d11", "d12", "d13", + "d14", "d15", "d16", "d17", "d18", "d19", "d20", + "d21", "d22", "d23", "d24", "d25", "d26", "d27", + "d28", "d29", "d30", "d31" }; +extern int p1maxstacksize; + /* - * Handling of integer constants. We have 8 bits + an even - * number of rotates available as a simple immediate. + * Handling of integer constants for 12-bit immediates. + * We have 8 bits + an even number of rotates available + * as a simple immediate. * If a constant isn't trivially representable, use an ldr * and a subsequent sequence of orr operations. */ static int -trepresent(const unsigned int val) +t12represent(long long val) { - int i; -#define rotate_left(v, n) (v << n | v >> (32 - n)) + unsigned long long i = (unsigned long long)val; +#define rotate_left32(v, n) (v << n | v >> (32 - n)) for (i = 0; i < 32; i += 2) - if (rotate_left(val, i) <= 0xff) + if (rotate_left32(val, i) <= 0xff) return 1; return 0; +#undef rotate_left32 +} + +/* + * Handling of integer constants for 16-bit immediates. + * + * Return 1 if VAL can be synthesized with a single "mov" pseudo-op, + * i.e. either MOVZ or MOVN (one 16-bit chunk at shift 0/16/32/48). + * Return 0 otherwise. + */ +static int +t16represent(long long val) +{ + unsigned long long u = (unsigned long long)val; + int nz_z = 0; /* halfwords that are non-zero (MOVZ pattern) */ + int nz_n = 0; /* halfwords that are not 0xFFFF (MOVN pattern) */ + + for (int shift = 0; shift <= 48; shift += 16) { + unsigned hw = (unsigned)((u >> shift) & 0xFFFFULL); + + /* MOVZ: all halfwords must be 0 except possibly one */ + if (hw != 0) + if (++nz_z > 1) + nz_z = 2; /* clamp */ + + /* MOVN: all halfwords must be 0xFFFF except possibly one */ + if (hw != 0xFFFFU) + if (++nz_n > 1) + nz_n = 2; /* clamp */ + } + + return (nz_z <= 1) || (nz_n <= 1); } /* @@ -116,34 +169,97 @@ static TWORD ftype; /* * calculate stack size and offsets + * 0 - total stack size + * 1 - permanent register end offset (0 means no permregs saved) + * 2 - max function call stack end offset (0 means no funcalls) */ -static int -offcalc(struct interpass_prolog *ipp) +static void +offcalc(struct interpass_prolog *ipp, int *values) { - int addto; +#define SETALIGN(x,y) x = (x) + (((y) - ((x) % (y))) % (y)) + int i, prcount; #ifdef PCC_DEBUG if (x2debug) printf("offcalc: p2maxautooff=%d\n", p2maxautooff); #endif - addto = p2maxautooff; + values[0] = p2maxautooff; + values[1] = values[2] = 0; + prcount = 0; + + /* count used permanent registers */ + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(p2env.p_regs, i)) + prcount++; + + /* calculate permanent register save area */ + if (prcount) { + values[0] += prcount * SZLONGLONG/SZCHAR; + SETALIGN(values[0], ALSTACK/SZCHAR); + values[1] = values[0]; + } + + /* XXX - move calculation from pass1 to pass2. + * it works, but it is hacky. we are crossing + * the pass1-pass2 boundary informally. + */ + if (p1maxstacksize) { + values[0] += p1maxstacksize; + SETALIGN(values[0], ALSTACK/SZCHAR); + values[2] = values[0]; + } + + SETALIGN(values[0], ALSTACK/SZCHAR); #ifdef PCC_DEBUG if (x2debug) - printf("offcalc: addto=%d\n", addto); + printf("offcalc: total=%d proff=%d funoff=%d autos=%d\n", + values[0], values[1], values[2], p2maxautooff); #endif +#undef SETALIGN +} - addto -= AUTOINIT / SZCHAR; +/* + * print instructions to move stack down + */ +static void +movspdown(int val) +{ + int vals[4], nc, i; + if (t12represent(val)) { + printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], val); + } else { + nc = encode_constant(val, vals); + for (i = 0; i < nc; i++) + printf("\tsub %s,%s,#%d\n", + rnames[SP], rnames[SP], vals[i]); + } +} - return addto; +/* + * print instructions to move stack up + */ +static void +movspup(int val) +{ + int vals[4], nc, i; + if (t12represent(val)) { + printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], val); + } else { + nc = encode_constant(val, vals); + for (i = 0; i < nc; i++) + printf("\tadd %s,%s,#%d\n", + rnames[SP], rnames[SP], vals[i]); + } } +static int fframe[4]; + void prologue(struct interpass_prolog *ipp) { - int addto; - int vals[4], nc, i; + int i, pi; #ifdef PCC_DEBUG if (x2debug) @@ -159,30 +275,30 @@ prologue(struct interpass_prolog *ipp) #endif ftype = ipp->ipp_type; - printf("%s:\n", exname(ipp->ipp_name)); - addto = offcalc(ipp); - if (addto < 64){ - addto = 64; - } - if((addto % 16)){ - addto = addto + (16 - (addto % 16)); - } - if (trepresent(addto)) { - printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], addto); - } else { - nc = encode_constant(addto, vals); - for (i = 0; i < nc; i++) - printf("\tsub %s,%s,#%d\n", - rnames[SP], rnames[SP], vals[i]); - } - printf("\tstp %s,%s,[%s]\n", rnames[FP],rnames[LR],rnames[SP]); - printf("\tmov %s,%s\n", rnames[FP], rnames[SP]); - addStack=addto; + printf("%s:\n", ipp->ipp_name); + + offcalc(ipp, fframe); + + printf("\tstp %s,%s,[%s,#%d]!\n", rnames[FP], rnames[LR], rnames[SP], -SZFPSP); + printf("\tmov %s,%s\n", rnames[FP], rnames[SP]); + + if (fframe[1]) { + /* save permanent registers */ + movspdown(fframe[1]); + for (i = 0, pi = 0; i < MAXREGS; i++) + if (TESTBIT(p2env.p_regs, i)) + printf("\tstr %s,[%s,#%d]\n", + rnames[i], rnames[SP], pi++ * (SZLONGLONG/SZCHAR)); + } + + movspdown(fframe[0] - fframe[1]); } void eoftn(struct interpass_prolog *ipp) { + int i, pi; + if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ @@ -190,17 +306,21 @@ eoftn(struct interpass_prolog *ipp) if (ftype == STRTY || ftype == UNIONTY) { assert(0); } else { - if (addStack == 0){ - printf("\tldp %s,%s,[%s],#%d \n", rnames[FP], rnames[LR], - rnames[SP], 64); - printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], 64); - } - else{ - printf("\tldp %s,%s,[%s] \n", rnames[FP], rnames[LR], - rnames[SP]); - printf("\tadd %s,%s,%d\n", rnames[SP], rnames[SP], addStack); - } + movspup(fframe[0] - fframe[1]); + + if (fframe[1]) { + /* load permanent registers */ + for (i = 0, pi = 0; i < MAXREGS; i++) + if (TESTBIT(p2env.p_regs, i)) + printf("\tldr %s,[%s,#%d]\n", + rnames[i], rnames[SP], pi++ * (SZLONGLONG/SZCHAR)); + movspup(fframe[1]); + } + + printf("\tldp %s,%s,[%s],#%d\n", rnames[FP], rnames[LR], + rnames[SP], SZFPSP); } + printf("\tret\n"); #ifndef MACHOABI printf("\t.size %s,.-%s\n", exname(ipp->ipp_name), @@ -341,7 +461,7 @@ stasg(NODE *p) int val = getlval(l); /* R0 = dest, R1 = src, R2 = len */ - load_constant_into_reg(R2, attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); + load_64constant_into_reg(R2, attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); if (l->n_op == OREG) { if (R2TEST(regno(l))) { int r = regno(l); @@ -350,11 +470,11 @@ stasg(NODE *p) printf("\tadd %s,%s,%s\n", rnames[R0], rnames[R0], rnames[R2UPK1(r)]); } else { - if (trepresent(val)) { + if (t12represent(val)) { printf("\tadd %s,%s,#%d\n", rnames[R0], rnames[regno(l)], val); } else { - load_constant_into_reg(R0, val); + load_64constant_into_reg(R0, val); printf("\tadd %s,%s,%s\n", rnames[R0], rnames[R0], rnames[regno(l)]); } @@ -514,49 +634,6 @@ emul(NODE *p) printf("\tbl __%s" COM "emulated operation\n", exname(ch)); } -static void -halfword(NODE *p) -{ - NODE *r = getlr(p, 'R'); - NODE *l = getlr(p, 'L'); - int idx0 = 0; - CONSZ lval; - - if (features(FEATURE_BIGENDIAN)) { - idx0 = 1; - } - - if (p->n_op == ASSIGN && r->n_op == OREG) { - /* load */ - lval = getlval(r); - expand(p, 0, "\tldrh A1,"); - printf("[%s,#" CONFMT "]\n", rnames[r->n_rval], lval+idx0); - } else if (p->n_op == ASSIGN && l->n_op == OREG) { - /* store */ - lval = getlval(l); - expand(p, 0, "\tstrh AR,"); - printf("[%s,#" CONFMT "]\n", rnames[l->n_rval], lval+idx0); - } else if (p->n_op == SCONV || p->n_op == UMUL) { - /* load */ - lval = getlval(l); - expand(p, 0, "\tldrh A1,"); - printf("[%s,#" CONFMT "]\n", rnames[l->n_rval], lval+idx0); - } else if (p->n_op == NAME || p->n_op == ICON || p->n_op == OREG) { - /* load */ - lval = getlval(p); - switch (p->n_type) { - case SHORT: - expand(p, 0, "\tldrsh A1,"); - break; - default: - expand(p, 0, "\tldrh A1,"); - } - printf("[%s,#" CONFMT "]\n", rnames[p->n_rval], lval+idx0); - } else { - comperr("halfword"); - } -} - static void bfext(NODE *p) { @@ -587,25 +664,67 @@ argsiz(NODE *p) return 0; } +static void +addrload(NODE *p) +{ + NODE *l = getlr(p, 'L'); + + if (l->n_op == NAME) { + if (kflag) { /* PIC load */ + if (l->n_name[0] != '@') { /* non-extern/got */ +#ifdef MACHOABI + expand(p, 0, "\tadrp ZXA1,AL@page\n"); + expand(p, 0, "\tadd ZXA1,ZXA1,AL@pageoff\n"); +#else + expand(p, 0, "\tadrp ZXA1,AL\n"); + expand(p, 0, "\tadd ZXA1,ZXA1,:lo12:AL\n"); +#endif + } else { /* got */ +#ifdef MACHOABI + expand(p, 0, "\tadrp ZXA1,AL@gotpage\n"); + expand(p, 0, "\tldr ZXA1,[ZXA1,AL@gotpageoff]\n"); +#else + expand(p, 0, "\tadrp ZXA1,:got:AL\n"); + expand(p, 0, "\tldr ZXA1,[ZXA1,:got_lo12:AL]\n"); +#endif + } + } else { /* non-PIC load from near pool */ + expand(p, 0, "\tadr ZXA1,AL\n"); + } + } else { + comperr("addrload"); + } +} + void zzzcode(NODE *p, int c) { - int pr; - switch (c) { + case 'A': /* load address of NAME */ + addrload(p); + break; + case 'B': /* bit-field sign extension */ bfext(p); break; case 'C': /* remove from stack after subroutine call */ +/* XXX - we use a fixed stack that can hold the + * maximum stack space required by any subroutine call, + * so we don't need to move the SP mid-function. + * however, we might want to change this in the future. + */ +#if 0 pr = p->n_qual; + 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); +#endif break; - case 'D': - isConverstion= 1; + case 'W': + isShrink = 1; break; case 'E': /* print out emulated ops */ emul(p); @@ -615,10 +734,6 @@ zzzcode(NODE *p, int c) fpemul(p); break; - case 'H': /* do halfword access */ - halfword(p); - break; - case 'I': /* init constant */ if (p->n_name[0] != '\0') comperr("named init"); @@ -626,7 +741,7 @@ zzzcode(NODE *p, int c) getlval(p) & 0xffffffff); break; case 'J': /* init longlong constant */ - load_64constant_into_reg(DECRA(p->n_reg, 1)-R16, + load_64constant_into_reg(DECRA(p->n_reg, 1), getlval(p) & 0xffffffffffffffff); break; @@ -634,6 +749,10 @@ zzzcode(NODE *p, int c) stasg(p); break; + case 'X': + isExtend = 1; + break; + default: comperr("zzzcode %c", c); } @@ -753,12 +872,15 @@ adrput(FILE *io, NODE *p) p = p->n_left; switch (p->n_op) { case NAME: + const char *name; if (p->n_name[0] != '\0') { - fputs(p->n_name, io); + /* skip GOT prefix '@' if exists */ + name = p->n_name[0] == '@' ? p->n_name+1 : p->n_name; + fputs(name, io); if (getlval(p) != 0) fprintf(io, "+%lld", getlval(p)); } else - fprintf(io, "#" CONFMT, getlval(p)); + fprintf(io, LABFMT, (int)getlval(p)); return; case OREG: @@ -776,6 +898,7 @@ adrput(FILE *io, NODE *p) case REG: switch (p->n_type) { + case FLOAT: case CHAR: case UCHAR: case INT: @@ -783,31 +906,24 @@ adrput(FILE *io, NODE *p) case USHORT: case BOOL: case UNSIGNED: - if (!ISPTR(p->n_type)) { - if (isConverstion) { - fprintf(io, "%s", wnames[0]); - isConverstion = 0; - } - else - fprintf(io, "%s", wnames[p->n_rval]); - } - else + if (isExtend) fprintf(io, "%s", rnames[p->n_rval]); + else + fprintf(io, "%s", wnames[p->n_rval]); break; case DOUBLE: case LDOUBLE: - if (features(FEATURE_HARDFLOAT)) { - fprintf(io, "%s", rnames[p->n_rval]); - break; - } - /* FALLTHROUGH */ case LONGLONG: case ULONGLONG: - fprintf(io, "%s", rnames[p->n_rval-R16]); + default: /* PTR */ + if (isShrink) + fprintf(io, "%s", wnames[p->n_rval]); + else + fprintf(io, "%s", rnames[p->n_rval]); break; - default: - fprintf(io, "%s", rnames[p->n_rval]); } + isExtend = 0; + isShrink = 0; return; default: @@ -913,7 +1029,7 @@ prtaddr(NODE *p, void *arg) p->n_op = ADDROF; } - if (p->n_op != ADDROF || l->n_op != NAME) + if (p->n_op != NAME || kflag) return; /* if we passed 1k nodes printout list */ @@ -928,8 +1044,8 @@ prtaddr(NODE *p, void *arg) /* write address to byte stream */ SLIST_FOREACH(el, &aslist, link) { - if (el->num == getlval(l) && el->name[0] == l->n_name[0] && - strcmp(el->name, l->n_name) == 0) { + if (el->num == getlval(p) && el->name[0] == p->n_name[0] && + strcmp(el->name, p->n_name) == 0) { found = 1; break; } @@ -938,25 +1054,25 @@ prtaddr(NODE *p, void *arg) /* we know that this is text segment */ lab = prtnumber++; if (nodcnt <= 1000 && notfirst == 0) { - if (getlval(l)) + if (getlval(p)) printf(PRTLAB ":\n\t.dword %s+%lld\n", - lab, l->n_name, getlval(l)); + lab, p->n_name, getlval(p)); else printf(PRTLAB ":\n\t.dword %s\n", - lab, l->n_name); + lab, p->n_name); } el = tmpalloc(sizeof(struct addrsymb)); - el->num = getlval(l); - el->name = l->n_name; + el->num = getlval(p); + el->name = p->n_name; el->str = tmpalloc(32); snprintf(el->str, 32, PRTLAB, lab); SLIST_INSERT_LAST(&aslist, el, link); } - nfree(l); - p->n_op = NAME; setlval(p, 0); - p->n_name = el->str; + p->n_left = mklnode(NAME, getlval(p), 0, PTR|p->n_type); + p->n_left->n_name = el->str; + p->n_op = UMUL; } void @@ -969,11 +1085,6 @@ myreader(struct interpass *ipole) DLIST_FOREACH(ip, ipole, qelem) { switch (ip->type) { - case IP_NODE: - lineno = ip->lineno; - ipbase = ip; - walkf(ip->ip_node, prtaddr, 0); - break; case IP_EPILOG: ipbase = ip; if (notfirst) @@ -983,19 +1094,27 @@ myreader(struct interpass *ipole) break; } } + if (x2debug) printip(ipole); } -/* - * Remove some PCONVs after OREGs are created. - */ static void -pconv2(NODE *p, void *arg) +fixtree2(NODE *p, void *arg) { NODE *q; - if (p->n_op == PLUS) { + if (p->n_op == PLUS || p->n_op == MINUS) { + /* + * Convert INT ICONs that slipped into PTR additions to LONGLONG. + */ + if (ISPTR(p->n_left->n_type) && + p->n_right->n_type == INT && p->n_right->n_op == ICON) + p->n_right->n_type = LONGLONG; + + /* + * Remove some PCONVs after OREGs are created. + */ if (p->n_type == (PTR+SHORT) || p->n_type == (PTR+USHORT)) { if (p->n_right->n_op != ICON) return; @@ -1011,17 +1130,84 @@ pconv2(NODE *p, void *arg) */ } } + + /* Remove unnecessary UMUL & ADDROF combinations. */ + if (p->n_op == ADDROF && p->n_left->n_op == UMUL) { + q = p->n_left; + *p = *p->n_left->n_left; + q = nfree(q); + nfree(q); + } } void mycanon(NODE *p) { - walkf(p, pconv2, 0); +} + +static unsigned int lastimmtype; + +/* + * Put big immediates in literal pools. + */ +static void +immput(NODE *p, void *arg) +{ + /* + * Late legalization: pass2 and backend rewrites may introduce new ICON nodes + * (e.g. TEMP -> stack/OREG lowering). After these transformations, some ICON + * values may no longer be representable as immediate operands in AArch64 + * instructions. Convert such ICONs to literal-pool loads here so the backend + * never emits an unencodable immediate. + * + * Float literals are handled earlier in pass1; integers require a pass2 sweep + * to catch ICONs generated after pass1 has finished. + */ + int lab; + TWORD t; + U_CONSZ uval; + + if (p->n_op == ICON && !t16represent(getlval(p))) { + t = p->n_type; + uval = (glval(p) & SZMASK(sztable[t])); + + if (lastimmtype != t) + defalign(talign(t, NULL)); + + lab = getlab2(); + deflab(lab); + printf("%s 0x%llx\n", astypnames[t], uval); + + p->n_op = NAME; + setlval(p,lab); + p->n_name = ""; + lastimmtype = p->n_type; + } } void myoptim(struct interpass *ipp) { + lastimmtype = 0; + struct interpass *ip; + + DLIST_FOREACH(ip, ipp, qelem) + if (ip->type == IP_NODE) + walkf(ip->ip_node, prtaddr, 0); + + DLIST_FOREACH(ip, ipp, qelem) + if (ip->type == IP_NODE) + walkf(ip->ip_node, immput, 0); + + DLIST_FOREACH(ip, ipp, qelem) + if (ip->type == IP_NODE) + walkf(ip->ip_node, fixtree2, 0); + +#ifndef ALFTN +#define ALFTN ALINT +#endif + if (lastimmtype != 0) + defalign(ALFTN); } /* @@ -1030,7 +1216,7 @@ myoptim(struct interpass *ipp) void rmove(int s, int d, TWORD t) { - switch (t) { + switch (t) { case DOUBLE: case LDOUBLE: if (features(FEATURE_HARDFLOAT)) { @@ -1040,8 +1226,7 @@ rmove(int s, int d, TWORD t) /* FALLTHROUGH */ case LONGLONG: case ULONGLONG: - #define LONGREG(x, y) rnames[(x)-(R16-(y))] - printf("\tmov %s,%s\n",LONGREG(d,0), LONGREG(s,0)); + printf("\tmov %s,%s\n",rnames[d], rnames[s]); break; case FLOAT: if (features(FEATURE_HARDFLOAT)) { @@ -1084,6 +1269,7 @@ rmove(int s, int d, TWORD t) int COLORMAP(int c, int *r) { + /* XXX - investigate */ int num = 0; /* number of registers used */ switch (c) { case CLASSA: @@ -1108,20 +1294,11 @@ COLORMAP(int c, int *r) int gclass(TWORD t) { - if (t == DOUBLE || t == LDOUBLE) { - if (features(FEATURE_HARDFLOAT)) + if (features(FEATURE_HARDFLOAT)) { + if (t == DOUBLE || t == LDOUBLE || t == FLOAT) return CLASSC; - else - return CLASSB; } - if (t == FLOAT) { - if (features(FEATURE_HARDFLOAT)) - return CLASSC; - else - return CLASSA; - } - if (DEUNSIGN(t) == LONGLONG || DEUNSIGN(t) == LONG || t == LONGLONG || t == LONG) - return CLASSB; + return CLASSA; } @@ -1129,8 +1306,8 @@ int retreg(int t) { int c = gclass(t); - if (c == CLASSB) - return R16; + if (c == CLASSC) + return V0; return R0; } @@ -1165,9 +1342,9 @@ special(NODE *p, int shape) * default to ARMv2 */ #ifdef TARGET_BIG_ENDIAN -#define DEFAULT_FEATURES FEATURE_BIGENDIAN | FEATURE_MUL +#define DEFAULT_FEATURES FEATURE_BIGENDIAN | FEATURE_EXTEND | FEATURE_FPSIMD #else -#define DEFAULT_FEATURES FEATURE_MUL +#define DEFAULT_FEATURES FEATURE_EXTEND | FEATURE_FPSIMD #endif static int fset = DEFAULT_FEATURES; @@ -1178,8 +1355,16 @@ static int fset = DEFAULT_FEATURES; void mflags(char *str) { - //Handling needs to be done for ARMv8 + if (strcasecmp(str, "soft-float") == 0) { + fset &= ~FEATURE_HARDFLOAT; + } else if (strcasecmp(str, "hard-float") == 0) { + fset |= FEATURE_HARDFLOAT; + } else { + fprintf(stderr, "unknown m option '%s'\n", str); + exit(1); + } } + int features(int mask) { diff --git a/arch/aarch64/macdefs.h b/arch/aarch64/macdefs.h index 722c63dca..f26a4b037 100644 --- a/arch/aarch64/macdefs.h +++ b/arch/aarch64/macdefs.h @@ -1,5 +1,6 @@ /* $Id$ */ /* + * Copyright (c) 2025, 2026 Hakan Candar (hakan@candar.tr). * Copyright (c) 2020 Puresoftware Ltd. * * Permission to use, copy, modify, and distribute this software for any @@ -28,11 +29,15 @@ * Storage space requirements */ #define SZCHAR 8 -#define SZBOOL 32 +#define SZBOOL 8 /* XXX - investigate */ #define SZINT 32 #define SZFLOAT 32 #define SZDOUBLE 64 +#ifndef MACHOABI +#define SZLDOUBLE 128 +#else #define SZLDOUBLE 64 +#endif #define SZLONG 64 #define SZSHORT 16 #define SZLONGLONG 64 @@ -42,17 +47,21 @@ * Alignment constraints */ #define ALCHAR 8 -#define ALBOOL 32 +#define ALBOOL 8 #define ALINT 32 #define ALFLOAT 32 -#define ALDOUBLE 32 -#define ALLDOUBLE 32 -#define ALLONG 32 -#define ALLONGLONG 32 +#define ALDOUBLE 64 +#ifndef MACHOABI +#define ALLDOUBLE 128 +#else +#define ALLDOUBLE 64 +#endif +#define ALLONG 64 +#define ALLONGLONG 64 #define ALSHORT 16 -#define ALPOINT 32 +#define ALPOINT 64 #define ALSTRUCT 32 -#define ALSTACK 32 +#define ALSTACK 128 /* * Min/max values. @@ -63,7 +72,7 @@ #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 -#define MIN_INT -1 +#define MIN_INT (-0x7fffffff-1) #define MAX_INT 0x7fffffff #define MAX_UNSIGNED 0xffffffff #define MIN_LONG 0x8000000000000000L @@ -73,7 +82,7 @@ #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL -#define BOOL_TYPE INT /* what used to store _Bool */ +#define BOOL_TYPE UCHAR /* what used to store _Bool */ /* * Use large-enough types. @@ -96,8 +105,7 @@ typedef long long OFFSZ; #define STOFARG(p) #define STOSTARG(p) -#define szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \ - (t) == LONG || (t) == ULONG || (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1) +#define szty(t) (t < LONG || t == FLOAT ? 1 : t == LDOUBLE ? 4 : 2) #define R0 0 #define R1 1 @@ -137,18 +145,111 @@ typedef long long OFFSZ; #define SP R31 #define LR R30 +#define V0 32 +#define V1 33 +#define V2 34 +#define V3 35 +#define V4 36 +#define V5 37 +#define V6 38 +#define V7 39 +#define V8 40 +#define V9 41 +#define V10 42 +#define V11 43 +#define V12 44 +#define V13 45 +#define V14 46 +#define V15 47 +#define V16 48 +#define V17 49 +#define V18 50 +#define V19 51 +#define V20 52 +#define V21 53 +#define V22 54 +#define V23 55 +#define V24 56 +#define V25 57 +#define V26 58 +#define V27 59 +#define V28 60 +#define V29 61 +#define V30 62 +#define V31 63 + #define NUMCLASS 3 -#define MAXREGS 34 +#define MAXREGS 64 #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, \ - SCREG, SCREG, SCREG, SCREG, \ - SCREG, SCREG, SCREG, SCREG, \ +/* x0 */ SAREG|TEMPREG, \ +/* x1 */ SAREG|TEMPREG, \ +/* x2 */ SAREG|TEMPREG, \ +/* x3 */ SAREG|TEMPREG, \ +/* x4 */ SAREG|TEMPREG, \ +/* x5 */ SAREG|TEMPREG, \ +/* x6 */ SAREG|TEMPREG, \ +/* x7 */ SAREG|TEMPREG, \ +/* x8 */ SAREG|TEMPREG, \ +/* x9 */ SAREG|TEMPREG, \ +/* x10 */ SAREG|TEMPREG, \ +/* x11 */ SAREG|TEMPREG, \ +/* x12 */ SAREG|TEMPREG, \ +/* x13 */ SAREG|TEMPREG, \ +/* x14 */ SAREG|TEMPREG, \ +/* x15 */ SAREG|TEMPREG, \ +/* x16 */ 0, /* IP0 scratch (not allocatable) */ \ +/* x17 */ 0, /* IP1 scratch */ \ +/* x18 */ 0, /* platform register */ \ +/* x19 */ SAREG|PERMREG, \ +/* x20 */ SAREG|PERMREG, \ +/* x21 */ SAREG|PERMREG, \ +/* x22 */ SAREG|PERMREG, \ +/* x23 */ SAREG|PERMREG, \ +/* x24 */ SAREG|PERMREG, \ +/* x25 */ SAREG|PERMREG, \ +/* x26 */ SAREG|PERMREG, \ +/* x27 */ SAREG|PERMREG, \ +/* x28 */ SAREG|PERMREG, \ +/* x29 */ 0, /* FP (frame pointer) */ \ +/* x30 */ 0, /* LR */ \ +/* x31 */ 0, /* SP/WZR */ \ + \ + /* class B empty for now */ \ + \ +/* v0 */ SCREG|TEMPREG, \ +/* v1 */ SCREG|TEMPREG, \ +/* v2 */ SCREG|TEMPREG, \ +/* v3 */ SCREG|TEMPREG, \ +/* v4 */ SCREG|TEMPREG, \ +/* v5 */ SCREG|TEMPREG, \ +/* v6 */ SCREG|TEMPREG, \ +/* v7 */ SCREG|TEMPREG, \ +/* v8 */ SCREG|PERMREG, /* callee-saved */ \ +/* v9 */ SCREG|PERMREG, /* callee-saved */ \ +/* v10 */ SCREG|PERMREG, /* callee-saved */ \ +/* v11 */ SCREG|PERMREG, /* callee-saved */ \ +/* v12 */ SCREG|PERMREG, /* callee-saved */ \ +/* v13 */ SCREG|PERMREG, /* callee-saved */ \ +/* v14 */ SCREG|PERMREG, /* callee-saved */ \ +/* v15 */ SCREG|PERMREG, /* callee-saved */ \ +/* v16 */ SCREG|TEMPREG, \ +/* v17 */ SCREG|TEMPREG, \ +/* v18 */ SCREG|TEMPREG, \ +/* v19 */ SCREG|TEMPREG, \ +/* v20 */ SCREG|TEMPREG, \ +/* v21 */ SCREG|TEMPREG, \ +/* v22 */ SCREG|TEMPREG, \ +/* v23 */ SCREG|TEMPREG, \ +/* v24 */ SCREG|TEMPREG, \ +/* v25 */ SCREG|TEMPREG, \ +/* v26 */ SCREG|TEMPREG, \ +/* v27 */ SCREG|TEMPREG, \ +/* v28 */ SCREG|TEMPREG, \ +/* v29 */ SCREG|TEMPREG, \ +/* v30 */ SCREG|TEMPREG, \ +/* v31 */ 0 /* unusable due to class size limit */ + /* no overlapping registers at all */ #define ROVERLAP \ @@ -156,10 +257,21 @@ typedef long long OFFSZ; { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ - { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, + { -1 }, { -1 }, { -1 }, { -1 }, \ + \ + /* class B empty for now */ \ + \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 } + + +#define STACK_DOWN /* stack grows negatively for temporaries */ #define ARGINIT (16*8) /* # bits above fp where arguments start */ -#define AUTOINIT (32*8) /* # bits above fp where automatics start */ +#define AUTOINIT 0 /* # bits above fp where automatics start */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_LE @@ -171,7 +283,7 @@ typedef long long OFFSZ; /* 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 : x < 26 ? CLASSB : CLASSC) +#define GCLASS(x) (x < 32 ? CLASSA : CLASSC ) #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 */ @@ -183,15 +295,15 @@ int COLORMAP(int c, int *r); int retreg(int ty); int features(int f); +/* + * aarch64-specific symbol table flags. + */ +#define ATTR_P1_TARGET ATTR_AARCH64_BEENHERE + #define FEATURE_BIGENDIAN 0x00010000 -#define FEATURE_HALFWORDS 0x00020000 /* ldrsh/ldrh, ldrsb */ #define FEATURE_EXTEND 0x00040000 /* sxth, sxtb, uxth, uxtb */ -#define FEATURE_MUL 0x00080000 -#define FEATURE_MULL 0x00100000 -#define FEATURE_DIV 0x00200000 -#define FEATURE_FPA 0x10000000 -#define FEATURE_VFP 0x20000000 -#define FEATURE_HARDFLOAT (FEATURE_FPA|FEATURE_VFP) +#define FEATURE_FPSIMD 0x10000000 +#define FEATURE_HARDFLOAT (FEATURE_FPSIMD) #undef NODE #ifdef LANG_CXX @@ -208,12 +320,18 @@ NODE *arm_builtin_va_copy(const struct bitable *bt, NODE *a); #undef NODE #define COM "\t// " -#define NARGREGS 4 +#define NARGREGS 8 /* floating point definitions */ #define USE_IEEEFP_32 #define FLT_PREFIX IEEEFP_32 #define USE_IEEEFP_64 #define DBL_PREFIX IEEEFP_64 +#ifndef MACHOABI +#define USE_IEEEFP_128 +#define LDBL_PREFIX IEEEFP_128 +#define DEFAULT_FPI_DEFS { &fpi_binary32, &fpi_binary64, &fpi_binary128 } +#else #define LDBL_PREFIX IEEEFP_64 #define DEFAULT_FPI_DEFS { &fpi_binary32, &fpi_binary64, &fpi_binary64 } +#endif diff --git a/arch/aarch64/order.c b/arch/aarch64/order.c index 5e6f07d65..165e1b225 100644 --- a/arch/aarch64/order.c +++ b/arch/aarch64/order.c @@ -32,10 +32,7 @@ int notoff(TWORD ty, int r, CONSZ off, char *cp) { if (cp && cp[0]) return 1; - if (DEUNSIGN(ty) == INT || ty == UCHAR) - return !(off < 4096 && off > -4096); - else - return !(off < 256 && off > -256); + return !(off < 256 && off >= -256); } /* @@ -52,10 +49,23 @@ offstar(NODE *p, int shape) r = p->n_right; if( p->n_op == PLUS || p->n_op == MINUS ){ + if (r->n_op == OREG || r->n_op == NAME) { + /* OREG/NAMEs in PLUS/MINUS instructions + * should be moved into AREG first. + * one case is runtime array indexing i.e. arr[idx]. + */ + r = mkbinode(SCONV, r, NULL, LONGLONG); + p->n_right = r; + (void)geninsn(p->n_right, INAREG); + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + (void)geninsn(p, INAREG); + return; + } if( r->n_op == ICON ){ if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); - /* Converted in ormake() */ + (void)geninsn(p, INAREG); return; } /* usually for arraying indexing: */ @@ -65,6 +75,7 @@ offstar(NODE *p, int shape) (void)geninsn(p->n_left, INAREG); if (isreg(r->n_left) == 0) (void)geninsn(r->n_left, INAREG); + /* Converted in ormake() */ return; } } @@ -72,8 +83,7 @@ offstar(NODE *p, int shape) } /* - * Unable to convert to OREG (notoff() returned failure). Output - * suitable instructions to replace OREG. + * Do the actual conversion of offstar-found OREGs into real OREGs. */ void myormake(NODE *q) @@ -89,13 +99,7 @@ myormake(NODE *q) * This handles failed OREGs conversions, due to the offset * being too large for an OREG. */ - if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_right->n_op == ICON) { - if (isreg(p->n_left) == 0) - (void)geninsn(p->n_left, INAREG); - if (isreg(p->n_right) == 0) - (void)geninsn(p->n_right, INAREG); - (void)geninsn(p, INAREG); - } else if (p->n_op == REG) { + if (p->n_op == REG) { q->n_op = OREG; setlval(q, getlval(p)); q->n_rval = p->n_rval; @@ -303,7 +307,7 @@ setorder(NODE *p) int * livecall(NODE *p) { - static int r[] = { R3, R2, R1, R0, -1 }; + static int r[] = { R3, R2, R1, R0, -1 }; /* XXX - investigate */ int num = 1; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) diff --git a/arch/aarch64/table.c b/arch/aarch64/table.c index f1981982a..f97dd6175 100644 --- a/arch/aarch64/table.c +++ b/arch/aarch64/table.c @@ -1,5 +1,6 @@ /* $Id$ */ /* + * Copyright (c) 2025, 2026 Hakan Candar (hakan@candar.tr). * Copyright (c) 2020 Puresoftware Ltd. * * Permission to use, copy, modify, and distribute this software for any @@ -28,8 +29,8 @@ #include "pass2.h" -#define TUWORD TUNSIGNED|TULONG -#define TSWORD TINT|TLONG +#define TUWORD TUNSIGNED +#define TSWORD TINT #define TWORD TUWORD|TSWORD #define XSL(c) NEEDS(NREG(c, 1), NSL(c)) @@ -43,8 +44,8 @@ struct optab table[] = { /* PCONVs are not necessary */ { PCONV, INAREG, - SAREG, TWORD|TPOINT, - SAREG, TWORD|TPOINT, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TLONGLONG|TULONGLONG|TPOINT, 0, RLEFT, COM "pointer conversion\n", }, @@ -73,9 +74,21 @@ struct optab table[] = { { SCONV, INAREG, SAREG, TCHAR, - SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TUCHAR, + XSL(A), RESC1, + " and A1,AL,#255" COM "convert char to uchar\n", }, + +{ SCONV, INAREG, + SAREG, TCHAR, + SAREG, TUSHORT, + XSL(A), RESC1, + " and A1,AL,#65535" COM "convert char to ushort\n", }, + +{ SCONV, INAREG, + SAREG, TCHAR, + SAREG, TUWORD, XSL(A), RESC1, - " and A1,AL,#255" COM "convert char to uchar/ushort/uint\n", }, + " mov A1,AL" COM "convert char to uint\n", }, { SCONV, INAREG | FEATURE_EXTEND, SAREG, TUCHAR, @@ -87,8 +100,8 @@ struct optab table[] = { SAREG, TUCHAR, SAREG, TCHAR, XSL(A), RESC1, - " mov A1,AL,lsl #24" COM "convert uchar to char\n" - " mov A1,A1,lsr #24\n", }, + " lsl A1,AL,#24" COM "convert uchar to char\n" + " asr A1,A1,#24\n", }, { SCONV, INAREG, SAREG, TUCHAR, @@ -102,18 +115,17 @@ struct optab table[] = { 0, RLEFT, COM "convert short to int\n", }, -{ SCONV, INAREG | FEATURE_EXTEND, +{ SCONV, INAREG, SAREG, TSHORT, - SAREG, TUWORD|TUSHORT, + SAREG, TUSHORT, XSL(A), RESC1, - " uxth A1,AL" COM "convert short to uint\n", }, + " and A1,AL,#65535" COM "convert short to ushort\n", }, { SCONV, INAREG, SAREG, TSHORT, - SAREG, TUWORD|TUSHORT, + SAREG, TUWORD, XSL(A), RESC1, - " mov A1,AL,lsl #16" COM "convert short to uint\n" - " mov A1,AL,lsr #16\n", }, + " mov A1,AL" COM "convert short to uint\n", }, { SCONV, INAREG | FEATURE_EXTEND, SAREG, TUSHORT, @@ -125,8 +137,8 @@ struct optab table[] = { SAREG, TUSHORT, SAREG, TSHORT, XSL(A), RESC1, - " mov A1,AL,lsl #16" COM "convert ushort to short\n" - " mov A1,A1,lsr #16\n", }, + " lsl A1,AL,#16" COM "convert ushort to short\n" + " asr A1,A1,#16\n", }, { SCONV, INAREG | FEATURE_EXTEND, SAREG, TSHORT|TUSHORT, @@ -138,14 +150,8 @@ struct optab table[] = { SAREG, TSHORT|TUSHORT, SAREG, TCHAR, XSL(A), RESC1, - " mov A1,AL,lsl #24" COM "convert (u)short to char\n" - " mov A1,A1,lsr #24\n", }, - -{ SCONV, INAREG, - SAREG, TSHORT|TUSHORT, - SAREG, TCHAR, - XSL(A), RESC1, - " sxtb A1,AL" COM "convert (u)short to char\n", }, + " lsl A1,AL,#24" COM "convert (u)short to char\n" + " asr A1,A1,#24\n", }, { SCONV, INAREG, SAREG, TSHORT|TUSHORT, @@ -169,8 +175,8 @@ struct optab table[] = { SAREG, TWORD, SAREG, TCHAR, XSL(A), RESC1, - " mov A1,AL,lsl #24" COM "convert (u)int to char\n" - " mov A1,A1,lsr #24\n", }, + " lsl A1,AL,#24" COM "convert (u)int to char\n" + " asr A1,A1,#24\n", }, { SCONV, INAREG | FEATURE_EXTEND, SAREG, TWORD, @@ -182,94 +188,87 @@ struct optab table[] = { SAREG, TWORD, SAREG, TSHORT, XSL(A), RESC1, - " and A1,AL,65535" COM "convert (u)int to short\n", }, + " lsl A1,AL,#16" COM "convert (u)int to short\n" + " asr A1,A1,#16\n", }, { SCONV, INAREG, SAREG, TWORD, SAREG, TUCHAR, XSL(A), RESC1, - " and A1,AL,#255" COM "convert uchar to char\n", }, - -{ SCONV, INAREG | FEATURE_EXTEND, - SAREG, TWORD, - SAREG, TUSHORT, - XSL(A), RESC1, - " uxth A1,AL" COM "convert int to ushort\n", }, + " and A1,AL,#255" COM "convert (u)int to uchar\n", }, { SCONV, INAREG, SAREG, TWORD, SAREG, TUSHORT, XSL(A), RESC1, - " mov A1,AL,lsl #16" COM "convert int to ushort\n" - " mov A1,AL,lsr #16\n", }, + " and A1,AL,#65535" COM "convert (u)int to ushort\n", }, { SCONV, INAREG, - SAREG, TPOINT|TWORD, - SAREG, TWORD|TPOINT, + SAREG, TWORD, + SAREG, TWORD, 0, RLEFT, - COM "convert between pointers and words\n", }, + COM "convert between words\n", }, -{ SCONV, INBREG, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, +{ SCONV, INAREG, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TLONGLONG|TULONGLONG|TPOINT, 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, - XSL(B), RESC1, - " sxtw A1,AL" COM "convert (u)char/(u)short/(u)int to (u)longlong\n", }, - { SCONV, INAREG | FEATURE_EXTEND, - SBREG, TLONGLONG|TULONGLONG, - SAREG, TCHAR, - NAREG, RESC1, - " sxtb A1,AL" COM "convert (u)longlong to char\n", }, + SAREG, TCHAR|TSHORT|TSWORD, + SAREG, TLONGLONG, + XSL(A), RESC1, + " sxtw A1,AL" COM "convert char/short/int to longlong\n", }, { SCONV, INAREG, - SBREG, TLONGLONG|TULONGLONG, - SAREG, TCHAR, - NAREG, RESC1, - "ZD\n", }, + SAREG, TCHAR|TSHORT|TSWORD, + SAREG, TLONGLONG, + XSL(A), RESC1, + " lsl A1,ZXAL,#32" COM "convert char/short/int to longlong\n" + " asr A1,A1,#32\n", }, { SCONV, INAREG | FEATURE_EXTEND, - SBREG, TLONGLONG|TULONGLONG, - SAREG, TSHORT, - NAREG, RESC1, - " sxth A1,AL" COM "convert (u)longlong to short\n", }, + SAREG, TCHAR|TSHORT|TSWORD, + SAREG, TULONGLONG, + XSL(A), RESC1, + " sxtw A1,AL" COM "convert char to ulonglong\n", }, +{ SCONV, INAREG, + SAREG, TCHAR|TSHORT|TSWORD, + SAREG, TULONGLONG, + XSL(A), RESC1, + " lsl A1,ZXAL,#32" COM "convert char/short/int to ulonglong\n" + " asr A1,A1,#32\n", }, { SCONV, INAREG, - SBREG, TLONGLONG|TULONGLONG, - SAREG, TSHORT, - NAREG, RESC1, - "ZD", }, + SAREG, TUCHAR|TUSHORT|TUWORD, + SAREG, TLONGLONG|TULONGLONG, + 0, RLEFT, + COM "convert uchar/ushort/uint to (u)longlong\n", }, { SCONV, INAREG, - SBREG, TLONGLONG|TULONGLONG, - SAREG, TWORD, - NAREG, RESC1, - "ZD\n", }, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TCHAR|TSHORT|TSWORD, + XSL(A), RESC1, + " mov A1,ZWAL" COM "convert (u)longlong to char/short/int\n", }, { SCONV, INAREG, - SBREG, TLONGLONG|TULONGLONG, + SAREG, TLONGLONG|TULONGLONG|TPOINT, SAREG, TUCHAR, - NAREG, RESC1, - COM "ZD\n", }, - -{ SCONV, INAREG | FEATURE_EXTEND, - SBREG, TLONGLONG|TULONGLONG, - SAREG, TUSHORT, - NAREG, RESC1, - " uxth A1,AL" COM "convert (u)longlong to ushort\n", }, + XSL(A), RESC1, + " and ZXA1,AL,#255" COM "convert (u)longlong to uchar\n", }, { SCONV, INAREG, - SBREG, TLONGLONG|TULONGLONG, + SAREG, TLONGLONG|TULONGLONG|TPOINT, SAREG, TUSHORT, - NAREG, RESC1, - "ZD\n", }, + XSL(A), RESC1, + " and ZXA1,AL,#65535" COM "convert (u)longlong to ushort\n", }, +{ SCONV, INAREG, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TUWORD, + XSL(A), RESC1, + " mov A1,ZWAL" COM "convert (u)longlong to uint\n", }, /* conversions on load from memory */ @@ -288,287 +287,124 @@ struct optab table[] = { " ldrb A1,AL" COM "convert uchar to int/long\n", }, /* short */ -{ SCONV, INAREG | FEATURE_HALFWORDS, +{ SCONV, INAREG, SOREG, TSHORT, SAREG, TWORD, XSL(A), RESC1, " ldrsh A1,AL" COM "convert short to int/long\n", }, /* ushort */ -{ SCONV, INAREG | FEATURE_HALFWORDS, - SOREG, TSHORT, +{ SCONV, INAREG, + SOREG, TUSHORT, SAREG, TWORD, XSL(A), RESC1, " ldrh A1,AL" COM "convert ushort to int/long\n", }, -/* short */ -{ SCONV, INAREG, - SOREG, TSHORT|TUSHORT, - SAREG, TWORD, - NEEDS(NREG(A, 2), NSL(A)), RESC1, - "ZH", }, - -{ SCONV, INAREG | FEATURE_FPA, - SCREG, TFLOAT, - SAREG, TWORD, - NAREG, RESC1, - " fix AL,AR" COM "convert float to int\n", }, - -{ SCONV, INAREG | FEATURE_VFP, +{ SCONV, INAREG | FEATURE_FPSIMD, SCREG, TFLOAT, - SAREG, TSWORD, + SAREG, TSWORD|TLONGLONG, NAREG, RESC1, - " ftosis AL,AR" COM "convert float to int\n", }, + " fcvtzs A1,AL" COM "convert float to int/long\n", }, -{ SCONV, INAREG | FEATURE_VFP, +{ SCONV, INAREG | FEATURE_FPSIMD, SCREG, TFLOAT, - SAREG, TSWORD, + SAREG, TUWORD|TULONGLONG, NAREG, RESC1, - " ftouis AL,AR" COM "convert float to int\n", }, + " fcvtzu A1,AL" COM "convert float to uint/ulong\n", }, { SCONV, INAREG, SAREG, TFLOAT, - SAREG, TWORD, + SAREG, TWORD|TLONGLONG|TULONGLONG, NEEDS(NREG(A, 1), NLEFT(R0), NRES(R0)), RESC1, "ZF", }, -{ SCONV, INBREG | FEATURE_FPA, - SCREG, TFLOAT, - SBREG, TULONGLONG|TLONGLONG, - NBREG, RESC1, - COM "unimplemented\n", }, - -{ SCONV, INBREG | FEATURE_VFP, - SCREG, TFLOAT, - SBREG, TULONGLONG|TLONGLONG, - NBREG, RESC1, - COM "unimplemented\n", }, - -{ SCONV, INBREG, - SAREG, TFLOAT, - SBREG, TULONGLONG|TLONGLONG, - NEEDS(NREG(B, 1), NLEFT(R0), NRES(R16)), RESC1, - "ZF", }, - -{ SCONV, INAREG | FEATURE_FPA, +{ SCONV, INAREG | FEATURE_FPSIMD, SCREG, TDOUBLE|TLDOUBLE, - SAREG, TWORD, + SAREG, TSWORD|TLONGLONG, NAREG, RESC1, - " fix AL,AR" COM "convert double/ldouble to int\n", }, + " fcvtzs A1,AL" COM "convert (l)double to int/long\n", }, -{ SCONV, INAREG | FEATURE_VFP, +{ SCONV, INAREG | FEATURE_FPSIMD, SCREG, TDOUBLE|TLDOUBLE, - SAREG, TSWORD, - NAREG, RESC1, - " ftosid AL,AR" COM "convert double/ldouble to int\n", }, - -{ SCONV, INAREG | FEATURE_VFP, - SCREG, TDOUBLE|TLDOUBLE, - SAREG, TUWORD, + SAREG, TUWORD|TULONGLONG, NAREG, RESC1, - " ftouid AL,AR" COM "convert double/ldouble to int\n", }, + " fcvtzu A1,AL" COM "convert (l)double to uint/ulong\n", }, { SCONV, INAREG, - SBREG, TDOUBLE|TLDOUBLE, - SAREG, TWORD, - NEEDS(NREG(A, 1), NLEFT(R16), NRES(R0)), RESC1, + SAREG, TDOUBLE|TLDOUBLE, + SAREG, TWORD|TLONGLONG|TULONGLONG, + NEEDS(NREG(A, 1), NLEFT(R0), NRES(R0)), RESC1, "ZF", }, -{ SCONV, INBREG | FEATURE_FPA, - SCREG, TDOUBLE|TLDOUBLE, - SBREG, TLONGLONG|TULONGLONG, - NBREG, RESC1, - COM "unimplemented\n", }, - -{ SCONV, INBREG | FEATURE_VFP, - SCREG, TDOUBLE|TLDOUBLE, - SBREG, TULONGLONG|TLONGLONG, - NBREG, RESC1, - COM "unimplemented\n", }, - -{ SCONV, INBREG, - SBREG, TDOUBLE|TLDOUBLE, - SBREG, TULONGLONG|TLONGLONG, - NEEDS(NREG(B, 1), NLEFT(R16), NRES(R16)), RESC1, - "ZF", }, - -{ SCONV, INCREG | FEATURE_FPA, - SAREG, TWORD, +{ SCONV, INCREG | FEATURE_FPSIMD, + SAREG, TSWORD|TLONGLONG, SCREG, TFLOAT, NCREG, RESC1, - " flts AL,AR" COM "convert int to float\n" }, + " scvtf A1,AL" COM "convert int/long to float\n" }, -{ SCONV, INCREG | FEATURE_VFP, - SAREG, TSWORD, +{ SCONV, INCREG | FEATURE_FPSIMD, + SAREG, TUWORD|TULONGLONG, SCREG, TFLOAT, NCREG, RESC1, - " fsitos AL,AR" COM "convert int to float\n" }, - -{ SCONV, INCREG | FEATURE_VFP, - SAREG, TUWORD, - SCREG, TFLOAT, - NCREG, RESC1, - " fuitos AL,AR" COM "convert int to float\n" }, + " ucvtf A1,AL" COM "convert uint/ulong to float\n" }, { SCONV, INAREG, - SAREG, TWORD, + SAREG, TWORD|TLONGLONG|TULONGLONG, SAREG, TFLOAT, NEEDS(NREG(A, 1), NLEFT(R0), NRES(R0)), RESC1, "ZF", }, -{ SCONV, INCREG | FEATURE_FPA, - SBREG, TULONGLONG|TLONGLONG, - SCREG, TFLOAT, +{ SCONV, INCREG | FEATURE_FPSIMD, + SAREG, TSWORD|TLONGLONG, + SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, - COM "unimplemented\n", }, + " scvtf A1,AL" COM "convert int/long to (l)double\n" }, -{ SCONV, INCREG | FEATURE_VFP, - SBREG, TULONGLONG|TLONGLONG, - SCREG, TFLOAT, +{ SCONV, INCREG | FEATURE_FPSIMD, + SAREG, TUWORD|TULONGLONG, + SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, - COM "unimplemented\n", }, + " ucvtf A1,AL" COM "convert uint/ulong to (l)double\n" }, { SCONV, INAREG, - SBREG, TULONGLONG|TLONGLONG, - SAREG, TFLOAT, - NAREG, RESC1, - COM "unimplemented\n", }, - -{ SCONV, INCREG | FEATURE_FPA, - SAREG, TWORD, - SCREG, TDOUBLE, - NCREG, RESC1, - " fltd AL,AR" COM "convert int to double\n" }, - -{ SCONV, INCREG | FEATURE_VFP, - SAREG, TSWORD, - SCREG, TDOUBLE, - NCREG, RESC1, - " fsitod AL,AR" COM "convert int to double\n" }, - -{ SCONV, INCREG | FEATURE_VFP, - SAREG, TUWORD, - SCREG, TDOUBLE, - NCREG, RESC1, - " fuitod AL,AR" COM "convert int to double\n" }, - -{ SCONV, INBREG, - SAREG, TWORD, - SBREG, TDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R0), NRES(R16)), RESC1, - "ZF", }, - -{ SCONV, INCREG | FEATURE_FPA, - SBREG, TLONGLONG|TULONGLONG, - SCREG, TDOUBLE, - NCREG, RESC1, - COM "unimplemented\n", }, - -{ SCONV, INCREG | FEATURE_VFP, - SBREG, TLONGLONG|TULONGLONG, - SCREG, TDOUBLE, - NCREG, RESC1, - COM "unimplemented\n", }, - -{ SCONV, INBREG, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R16), NRES(R16)), RESC1, - "ZF", }, - -{ SCONV, INCREG | FEATURE_FPA, - SAREG, TWORD, - SCREG, TLDOUBLE, - NCREG, RESC1, - " flte AL,AR" COM "convert int to ldouble\n" }, - -{ SCONV, INCREG | FEATURE_VFP, - SAREG, TSWORD, - SCREG, TLDOUBLE, - NCREG, RESC1, - " fsitod AL,AR" COM "convert int to ldouble\n" }, - -{ SCONV, INCREG | FEATURE_VFP, - SAREG, TUWORD, - SCREG, TLDOUBLE, - NCREG, RESC1, - " fuitod AL,AR" COM "convert uint to ldouble\n" }, - -{ SCONV, INBREG, - SAREG, TWORD, - SBREG, TLDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R0), NRES(R16)), RESC1, - "ZF", }, - -{ SCONV, INCREG | FEATURE_FPA, - SBREG, TLONGLONG|TULONGLONG, - SCREG, TLDOUBLE, - NCREG, RESC1, - COM "unimplemented\n", }, - -{ SCONV, INCREG | FEATURE_VFP, - SBREG, TLONGLONG|TULONGLONG, - SCREG, TLDOUBLE, - NCREG, RESC1, - COM "unimplemented\n", }, - -{ SCONV, INBREG, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R16), NRES(R16)), RESC1, + SAREG, TWORD|TLONGLONG|TULONGLONG, + SAREG, TDOUBLE|TLDOUBLE, + NEEDS(NREG(A, 1), NLEFT(R0), NRES(R0)), RESC1, "ZF", }, -{ SCONV, INCREG | FEATURE_FPA, +{ SCONV, INCREG | FEATURE_FPSIMD, SCREG, TDOUBLE|TLDOUBLE, SCREG, TFLOAT, NCREG, RESC1, - COM "unimplemented\n", }, - -{ SCONV, INCREG | FEATURE_VFP, - SCREG, TDOUBLE|TLDOUBLE, - SCREG, TFLOAT, - NCREG, RESC1, - " fcvtds AL,AR" COM "convert float to double\n" }, + " fcvt A1,AL" COM "convert double to float\n" }, { SCONV, INAREG, - SBREG, TDOUBLE|TLDOUBLE, + SAREG, TDOUBLE|TLDOUBLE, SAREG, TFLOAT, - NEEDS(NREG(A, 1), NLEFT(R16), NRES(R0)), RESC1, + NEEDS(NREG(A, 1), NLEFT(R0), NRES(R0)), RESC1, "ZF", }, -{ SCONV, INCREG | FEATURE_FPA, +{ SCONV, INCREG | FEATURE_FPSIMD, SCREG, TFLOAT, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, - COM "unimplemented\n", }, + " fcvt A1,AL" COM "convert float to double\n" }, -{ SCONV, INCREG | FEATURE_VFP, - SCREG, TFLOAT, - SCREG, TDOUBLE|TLDOUBLE, - NCREG, RESC1, - " fcvtsd AL,AR" COM "convert float to double\n" }, - -{ SCONV, INBREG, +{ SCONV, INAREG, SAREG, TFLOAT, - SBREG, TDOUBLE|TLDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R0), NRES(R16)), RESC1, + SAREG, TDOUBLE|TLDOUBLE, + NEEDS(NREG(A, 1), NLEFT(R0), NRES(R0)), RESC1, "ZF", }, -{ SCONV, INCREG | FEATURE_FPA, - SCREG, TDOUBLE|TLDOUBLE, - SCREG, TDOUBLE|TLDOUBLE, - 0, RLEFT, - COM "convert (l)double to (l)double", }, - -{ SCONV, INCREG | FEATURE_VFP, +{ SCONV, INCREG | FEATURE_FPSIMD, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RLEFT, COM "convert (l)double to (l)double", }, -{ SCONV, INBREG, - SBREG, TDOUBLE|TLDOUBLE, - SBREG, TDOUBLE|TLDOUBLE, +{ SCONV, INAREG, + SAREG, TDOUBLE|TLDOUBLE, + SAREG, TDOUBLE|TLDOUBLE, 0, RLEFT, COM "convert (l)double to (l)double", }, @@ -591,30 +427,32 @@ struct optab table[] = { { CALL, INAREG, SCON|SNAME, TANY, - SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, XSL(A), RESC1, /* should be 0 */ " bl CL" COM "call (args, result in r0) to scon/sname (CL)\n" "ZC", }, -{ CALL, INBREG, +{ CALL, INAREG, SCON|SNAME, TANY, - SBREG, TLONGLONG|TULONGLONG, - XSL(B), RESC1, /* should be 0 */ - " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n" + SAREG, TLONGLONG|TULONGLONG|TPOINT, + XSL(A), RESC1, /* should be 0 */ + " bl CL" COM "call (args, result in r0) to scon/sname (CL)\n" "ZC", }, -{ CALL, INCREG | FEATURE_FPA, +/* XXX - investigate */ +{ CALL, INCREG | FEATURE_FPSIMD, SCON|SNAME, TANY, SCREG, TFLOAT, XSL(C), RESC1, /* should be 0 */ " bl CL" COM "call (args, result r0) to scon/sname (CL)\n" "ZC", }, -{ CALL, INCREG | FEATURE_FPA, +/* XXX - investigate */ +{ CALL, INCREG | FEATURE_FPSIMD, SCON|SNAME, TANY, SCREG, TDOUBLE|TLDOUBLE, XSL(C), RESC1, /* should be 0 */ - " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n" + " bl CL" COM "call (args, result in r0) to scon/sname (CL)\n" "ZC", }, { CALL, INAREG, @@ -624,36 +462,36 @@ struct optab table[] = { " bl CL" COM "call (args, result r0) to scon/sname (CL)\n" "ZC", }, -{ CALL, INBREG, +{ CALL, INAREG, SCON|SNAME, TANY, - SBREG, TDOUBLE|TLDOUBLE, - XSL(B), RESC1, /* should be 0 */ - " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n" + SAREG, TDOUBLE|TLDOUBLE, + XSL(A), RESC1, /* should be 0 */ + " bl CL" COM "call (args, result in r0) to scon/sname (CL)\n" "ZC", }, { UCALL, INAREG, SCON|SNAME, TANY, - SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, XSL(A), RESC1, /* should be 0 */ " bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", }, -{ UCALL, INBREG, +{ UCALL, INAREG, SCON|SNAME, TANY, - SBREG, TLONGLONG|TULONGLONG, - XSL(B), RESC1, /* should be 0 */ - " bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", }, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + XSL(A), RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", }, -{ UCALL, INCREG | FEATURE_FPA, +{ UCALL, INCREG | FEATURE_FPSIMD, SCON|SNAME, TANY, SCREG, TFLOAT, XSL(C), RESC1, /* should be 0 */ " bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", }, -{ UCALL, INCREG | FEATURE_FPA, +{ UCALL, INCREG | FEATURE_FPSIMD, SCON|SNAME, TANY, SCREG, TDOUBLE|TLDOUBLE, XSL(C), RESC1, /* should be 0 */ - " bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", }, + " bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", }, { CALL, FOREFF, SAREG, TANY, @@ -685,21 +523,6 @@ struct optab table[] = { " mov lr,pc\n" " mov pc,AL\n", }, -{ CALL, INBREG, - SAREG, TANY, - SANY, TANY, - NBREG, RESC1, - " mov lr,pc\n" - " mov pc,AL\n" - "ZC", }, - -{ UCALL, INBREG, - SAREG, TANY, - SANY, TANY, - NBREG, RESC1, - " mov lr,pc\n" - " mov pc,AL\n", }, - /* struct return */ { USTCALL, FOREFF, SCON, TANY, @@ -747,40 +570,34 @@ struct optab table[] = { */ { PLUS, INAREG, - SAREG, TWORD|TPOINT, + SAREG, TWORD, SCCON, TANY, NAREG, RESC1, " add A1,AL,AR" COM "addition of constant\n", }, -{ PLUS, INBREG, - SBREG, TLONGLONG|TULONGLONG, - SSCON, TANY, - XSL(B), RESC1, +{ PLUS, INAREG, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SCCON, TANY, + XSL(A), RESC1, " adds A1,AL,AR" COM "64-bit addition of constant\n", }, { PLUS, INAREG, - SAREG, TWORD|TPOINT, - SAREG, TWORD|TPOINT, + SAREG, TWORD, + SAREG, TWORD, XSL(A), RESC1, " add A1,AL,AR" COM "addition\n", }, -{ PLUS, INBREG, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, - XSL(B), RESC1, +{ PLUS, INAREG, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + XSL(A), RESC1, " adds A1,AL,AR" COM "64-bit addition\n", }, -{ PLUS, INCREG | FEATURE_FPA, +{ PLUS, INCREG | FEATURE_FPSIMD, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, - " adfs A1,AL,AR" COM "float add\n", }, - -{ PLUS, INCREG | FEATURE_VFP, - SCREG, TFLOAT, - SCREG, TFLOAT, - NCREG, RESC1, - " fadds A1,AL,AR" COM "float add\n", }, + " fadd A1,AL,AR" COM "float add\n", }, { PLUS, INAREG, SAREG, TFLOAT, @@ -788,77 +605,47 @@ struct optab table[] = { NEEDS(NREG(A, 1), NLEFT(R0), NRIGHT(R1), NRES(R0)), RESC1, "ZF", }, -{ PLUS, INCREG | FEATURE_FPA, - SCREG, TDOUBLE, - SCREG, TDOUBLE, - NCREG, RESC1, - " adfd A1,AL,AR" COM "double add\n", }, - -{ PLUS, INCREG | FEATURE_VFP, - SCREG, TDOUBLE, - SCREG, TDOUBLE, - NCREG, RESC1, - " faddd A1,AL,AR" COM "double add\n", }, - -{ PLUS, INBREG, - SBREG, TDOUBLE, - SBREG, TDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, - "ZF", }, - -{ PLUS, INCREG | FEATURE_FPA, - SCREG, TLDOUBLE, - SCREG, TLDOUBLE, - NCREG, RESC1, - " adfe A1,AL,AR" COM "ldouble add\n", }, - -{ PLUS, INCREG | FEATURE_VFP, - SCREG, TLDOUBLE, - SCREG, TLDOUBLE, +{ PLUS, INCREG | FEATURE_FPSIMD, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, - " faddd A1,AL,AR" COM "ldouble add\n", }, + " fadd A1,AL,AR" COM "(l)double add\n", }, -{ PLUS, INBREG, - SBREG, TLDOUBLE, - SBREG, TLDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, +{ PLUS, INAREG, + SAREG, TDOUBLE|TLDOUBLE, + SAREG, TDOUBLE|TLDOUBLE, + NEEDS(NREG(A, 1), NLEFT(R0), NRIGHT(R1), NRES(R0)), RESC1, "ZF", }, { MINUS, INAREG, - SAREG, TWORD|TPOINT, + SAREG, TWORD, SCCON, TANY, XSL(A), RESC1, " sub A1,AL,AR" COM "subtraction of constant\n", }, { MINUS, INAREG, - SAREG, TWORD|TPOINT, - SAREG, TWORD|TPOINT, + SAREG, TWORD, + SAREG, TWORD, XSL(A), RESC1, " sub A1,AL,AR" COM "subtraction\n", }, -{ MINUS, INBREG, - SBREG, TLONGLONG|TULONGLONG, +{ MINUS, INAREG, + SAREG, TLONGLONG|TULONGLONG|TPOINT, SCCON, TANY, - XSL(B), RESC1, + XSL(A), RESC1, " subs A1,AL,AR" COM "64-bit subtraction of constant\n", }, -{ MINUS, INBREG, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, - XSL(B), RESC1, +{ MINUS, INAREG, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + XSL(A), RESC1, " subs A1,AL,AR" COM "64-bit subtraction\n", }, -{ MINUS, INCREG | FEATURE_FPA, +{ MINUS, INCREG | FEATURE_FPSIMD, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, - " sufs A1,AL,AR" COM "float subtraction\n", }, - -{ MINUS, INCREG | FEATURE_VFP, - SCREG, TFLOAT, - SCREG, TFLOAT, - NCREG, RESC1, - " fsubs A1,AL,AR" COM "float subtraction\n", }, + " fsub A1,AL,AR" COM "float subtraction\n", }, { MINUS, INAREG, SAREG, TFLOAT, @@ -866,40 +653,16 @@ struct optab table[] = { NEEDS(NREG(A, 1), NLEFT(R0), NRIGHT(R1), NRES(R0)), RESC1, "ZF", }, -{ MINUS, INCREG | FEATURE_FPA, - SCREG, TDOUBLE, - SCREG, TDOUBLE, - NCREG, RESC1, - " sufd A1,AL,AR" COM "double subtraction\n", }, - -{ MINUS, INCREG | FEATURE_VFP, - SCREG, TDOUBLE, - SCREG, TDOUBLE, - NCREG, RESC1, - " fsubd A1,AL,AR" COM "double subtraction\n", }, - -{ MINUS, INBREG, - SBREG, TDOUBLE, - SBREG, TDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, - "ZF", }, - -{ MINUS, INCREG | FEATURE_FPA, - SCREG, TLDOUBLE, - SCREG, TLDOUBLE, - NCREG, RESC1, - " sufe A1,AL,AR" COM "ldouble subtraction\n", }, - -{ MINUS, INCREG | FEATURE_VFP, - SCREG, TLDOUBLE, - SCREG, TLDOUBLE, +{ MINUS, INCREG | FEATURE_FPSIMD, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, - " fsubd A1,AL,AR" COM "double subtraction\n", }, + " fsub A1,AL,AR" COM "(l)double subtraction\n", }, -{ MINUS, INBREG, - SBREG, TLDOUBLE, - SBREG, TLDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, +{ MINUS, INAREG, + SAREG, TDOUBLE|TLDOUBLE, + SAREG, TDOUBLE|TLDOUBLE, + NEEDS(NREG(A, 1), NLEFT(R0), NRIGHT(R1), NRES(R0)), RESC1, "ZF", }, /* @@ -910,192 +673,189 @@ struct optab table[] = { SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TANY, XSL(A), RESC1, - " mov A1,AL,lsl AR" COM "left shift\n", }, + " lsl A1,AL,AR" COM "left shift\n", }, { LS, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SCCON, TANY, XSL(A), RESC1, - " mov A1,AL,lsl AR" COM "left shift by constant\n", }, + " lsl A1,AL,AR" COM "left shift by constant\n", }, -{ LS, INBREG, - SBREG, TLONGLONG|TULONGLONG, +{ LS, INAREG, + SAREG, TLONGLONG|TULONGLONG, SCON, TANY, - NBREG, RESC1, - " mov A1,AL,lsl AR" COM "left shift by constant\n", }, + NAREG, RESC1, + " lsl A1,AL,AR" COM "left shift by constant\n", }, -{ LS, INBREG, - SBREG, TLONGLONG|TULONGLONG, +{ LS, INAREG, + SAREG, TLONGLONG|TULONGLONG, SAREG, TANY, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R2), NRES(R16)), RESC1, - "ZE" }, + XSL(A), RESC1, + " lsl A1,AL,ZXAR" COM "left shift\n", }, { RS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TANY, XSL(A), RESC1, - " mov A1,AL,lsr AR" COM "right shift\n", }, + " lsr A1,AL,AR" COM "right shift\n", }, { RS, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TANY, XSL(A), RESC1, - " mov A1,AL,lsr AR" COM "right shift\n", }, + " lsr A1,AL,AR" COM "right shift\n", }, { RS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SCCON, TANY, XSL(A), RESC1, - " mov A1,AL,lsr AR" COM "right shift by constant\n", }, + " lsr A1,AL,AR" COM "right shift by constant\n", }, { RS, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SCCON, TANY, XSL(A), RESC1, - " mov A1,AL,lsr AR" COM "right shift by constant\n", }, + " lsr A1,AL,AR" COM "right shift by constant\n", }, -{ RS, INBREG, - SBREG, TLONGLONG|TULONGLONG, +{ RS, INAREG, + SAREG, TLONGLONG|TULONGLONG, SCON, TANY, - NBREG, RESC1, - " mov A1,AL,lsr AR" COM "right shift by constant\n", }, -{ RS, INBREG, - SBREG, TLONGLONG|TULONGLONG, - SAREG, TANY, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R2), NRES(R16)), RESC1, - "ZE" }, + NAREG, RESC1, + " lsr A1,AL,AR" COM "right shift by constant\n", }, +{ RS, INAREG, + SAREG, TLONGLONG|TULONGLONG, + SAREG, TANY, + XSL(A), RESC1, + " lsr A1,AL,ZXAR" COM "right shift\n", }, /* * The next rules takes care of assignments. "=". */ { ASSIGN, FOREFF|INAREG, - SOREG, TWORD|TPOINT, - SAREG, TWORD|TPOINT, + SOREG, TWORD, + SAREG, TWORD, 0, RDEST, " str AR,AL" COM "assign word\n", }, { ASSIGN, FOREFF|INAREG, - SNAME, TWORD|TPOINT, - SAREG, TWORD|TPOINT, - 0, RDEST, - " adrp x0, AL\n" - " add x0, x0, :lo12:AL\n" - " str AR, [x0]" COM "assign global word\n", }, + SNAME, TWORD, + SAREG, TWORD, + NAREG, RDEST, + "ZA" + " str AR, [ZXA1]" COM "assign global word\n", }, -{ ASSIGN, FOREFF|INBREG, - SOREG|SNAME, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, +{ ASSIGN, FOREFF|INAREG, + SOREG, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TLONGLONG|TULONGLONG|TPOINT, 0, RDEST, " str AR,AL" COM "assign 64-bit value\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, + SNAME, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + NAREG, RDEST, + "ZA" + " str AR, [ZXA1]" COM "assign 64-bit global value\n", }, { ASSIGN, FOREFF|INAREG, - SOREG|SNAME, TCHAR|TUCHAR, + SOREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, 0, RDEST, " strb AR,AL" COM "assign (u)char\n", }, -{ ASSIGN, FOREFF|INAREG | FEATURE_HALFWORDS, - SOREG|SNAME, TSHORT|TUSHORT, +{ ASSIGN, FOREFF|INAREG, + SNAME, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + NAREG, RDEST, + "ZA" + " strb AR, [ZXA1]" COM "assign (u)char global\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RDEST, " strh AR,AL" COM "assign (u)short\n", }, { ASSIGN, FOREFF|INAREG, - SOREG|SNAME, TSHORT|TUSHORT, + SNAME, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, - XSL(A), RDEST, - "ZH", }, + NAREG, RDEST, + "ZA" + " strh AR, [ZXA1]" COM "assign (u)short global\n", }, -{ ASSIGN, FOREFF|INCREG | FEATURE_FPA, - SOREG|SNAME, TFLOAT, +{ ASSIGN, FOREFF|INCREG | FEATURE_FPSIMD, + SOREG, TFLOAT, SCREG, TFLOAT, 0, RDEST, - " stfs AR,AL" COM "assign float\n", }, + " str AR,AL" COM "assign float\n", }, -{ ASSIGN, FOREFF|INCREG | FEATURE_VFP, - SOREG|SNAME, TFLOAT, +{ ASSIGN, FOREFF|INCREG | FEATURE_FPSIMD, + SNAME, TFLOAT, SCREG, TFLOAT, - 0, RDEST, - COM "unimplemented\n", }, + NAREG, RDEST, + "ZA" + " str AR,[ZXA1]" COM "assign global float\n", }, { ASSIGN, FOREFF|INAREG, - SOREG|SNAME, TFLOAT, + SOREG, TFLOAT, SAREG, TFLOAT, 0, RDEST, " str AR,AL" COM "assign float (soft-float)\n", }, -{ ASSIGN, FOREFF|INCREG | FEATURE_FPA, - SOREG|SNAME, TDOUBLE, - SCREG, TDOUBLE, - 0, RDEST, - " stfd AR,AL" COM "assign double\n", }, - -{ ASSIGN, FOREFF|INCREG | FEATURE_VFP, - SOREG|SNAME, TDOUBLE, - SCREG, TDOUBLE, - 0, RDEST, - COM "unimplemented\n", }, +{ ASSIGN, FOREFF|INAREG, + SNAME, TFLOAT, + SAREG, TFLOAT, + NAREG, RDEST, + "ZA" + " str AR,[ZXA1]" COM "assign global float (soft-float)\n", }, -{ ASSIGN, FOREFF|INBREG, - SOREG|SNAME, TDOUBLE, - SBREG, TDOUBLE, +{ ASSIGN, FOREFF|INCREG | FEATURE_FPSIMD, + SOREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, 0, RDEST, - " str AR,AL" COM "assign double (soft-float)\n" - " str UR,UL\n", }, + " str AR,AL" COM "assign (l)double\n", }, -{ ASSIGN, FOREFF|INCREG | FEATURE_FPA, - SOREG|SNAME, TLDOUBLE, - SCREG, TLDOUBLE, - 0, RDEST, - " stfe AR,AL" COM "assign ldouble\n", }, +{ ASSIGN, FOREFF|INCREG | FEATURE_FPSIMD, + SNAME, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NAREG, RDEST, + "ZA" + " str AR,[ZXA1]" COM "assign global (l)double\n", }, -{ ASSIGN, FOREFF|INCREG | FEATURE_VFP, - SOREG|SNAME, TLDOUBLE, - SCREG, TLDOUBLE, +{ ASSIGN, FOREFF|INAREG, + SOREG, TDOUBLE|TLDOUBLE, + SAREG, TDOUBLE|TLDOUBLE, 0, RDEST, - COM "not implemented", }, + " str AR,AL" COM "assign (l)double (soft-float)\n", }, -{ ASSIGN, FOREFF|INBREG, - SOREG|SNAME, TLDOUBLE, - SBREG, TLDOUBLE, - 0, RDEST, - " str AR,AL" COM "assign ldouble (soft-float)\n" - " str UR,UL\n", }, +{ ASSIGN, FOREFF|INAREG, + SNAME, TDOUBLE|TLDOUBLE, + SAREG, TDOUBLE|TLDOUBLE, + NAREG, RDEST, + "ZA" + " str AR,[ZXA1]" COM "assign global (l)double (soft-float)\n", }, /* assign register to register */ { ASSIGN, FOREFF|INAREG, - SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, - SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, 0, RDEST, " mov AL,AR" COM "assign AR to AL\n", }, -{ ASSIGN, FOREFF|INBREG, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, +{ ASSIGN, FOREFF|INAREG, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TLONGLONG|TULONGLONG|TPOINT, 0, RDEST, " mov AL,AR" COM "assign AR to AL\n", }, -{ ASSIGN, FOREFF|INCREG | FEATURE_FPA, - SCREG, TFLOAT, - SCREG, TFLOAT, - 0, RDEST, - " mvf AL,AR" COM "assign float reg to float reg\n", }, - -{ ASSIGN, FOREFF|INCREG | FEATURE_VFP, +{ ASSIGN, FOREFF|INCREG | FEATURE_FPSIMD, SCREG, TFLOAT, SCREG, TFLOAT, 0, RDEST, - " fcpys AL,AR" COM "assign float reg to float reg\n", }, + " fmov AL,AR" COM "assign float reg to float reg\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TFLOAT, @@ -1103,24 +863,17 @@ struct optab table[] = { 0, RDEST, " mov AL,AR" COM "assign float reg to float reg\n", }, -{ ASSIGN, FOREFF|INCREG | FEATURE_FPA, +{ ASSIGN, FOREFF|INCREG | FEATURE_FPSIMD, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RDEST, - " mvf AL,AR" COM "assign float reg to float reg\n", }, - -{ ASSIGN, FOREFF|INCREG | FEATURE_VFP, - SCREG, TDOUBLE|TLDOUBLE, - SCREG, TDOUBLE|TLDOUBLE, - 0, RDEST, - " fcpyd AL,AR" COM "assign float reg to float reg\n", }, + " mvf AL,AR" COM "assign (l)double reg to (l)double reg\n", }, { ASSIGN, FOREFF|INBREG, - SBREG, TDOUBLE|TLDOUBLE, - SBREG, TDOUBLE|TLDOUBLE, + SAREG, TDOUBLE|TLDOUBLE, + SAREG, TDOUBLE|TLDOUBLE, 0, RDEST, - " mov AL,AR" COM "assign (l)double reg to (l)double reg\n" - " mov UL,UR\n", }, + " mov AL,AR" COM "assign (l)double reg to (l)double reg\n", }, { ASSIGN, FOREFF|INAREG, SFLD, TANY, @@ -1164,40 +917,34 @@ struct optab table[] = { { DIV, INAREG, SAREG, TSWORD, SAREG, TSWORD, - NEEDS(NREG(A, 1), NSL(A), NLEFT(R0), NRIGHT(R1), NRES(R0)), + NAREG, RESC1, " sdiv A1,AL,AR" COM "divide\n",}, { DIV, INAREG, SAREG, TUWORD, SAREG, TUWORD, - NEEDS(NREG(A, 1), NSL(A), NLEFT(R0), NRIGHT(R1), NRES(R0)), RESC1, + NAREG, RESC1, " udiv A1,AL,AR" COM "unsigned divide\n",}, -{ DIV, INBREG, - SBREG, TLONGLONG, - SBREG, TLONGLONG, - NEEDS(NREG(B, 1), NSL(B), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, - " sdiv x0,AL,AR" COM "long/longlong divide\n",}, - -{ DIV, INBREG, - SBREG, TULONGLONG, - SBREG, TULONGLONG, - NEEDS(NREG(B, 1), NSL(B), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, - " udiv x0,AL,AR" COM "long/longlong unsigned divide\n",}, +{ DIV, INAREG, + SAREG, TLONGLONG, + SAREG, TLONGLONG, + NAREG, RESC1, + " sdiv A1,AL,AR" COM "long/longlong divide\n",}, +{ DIV, INAREG, + SAREG, TULONGLONG, + SAREG, TULONGLONG, + NAREG, RESC1, + " udiv A1,AL,AR" COM "long/longlong unsigned divide\n",}, -{ DIV, INCREG | FEATURE_FPA, - SCREG, TFLOAT, - SCREG, TFLOAT, - NCREG, RESC1, - " dvfs A1,AL,AL" COM "fast (float) divide\n", }, -{ DIV, INCREG | FEATURE_VFP, +{ DIV, INCREG | FEATURE_FPSIMD, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, - " fdivs A1,AL,AL" COM "fast (float) divide\n", }, + " fdiv A1,AL,AR" COM "float divide\n", }, { DIV, INAREG, SAREG, TFLOAT, @@ -1205,155 +952,63 @@ struct optab table[] = { NEEDS(NREG(A, 1), NLEFT(R0), NRIGHT(R1), NRES(R0)), RESC1, "ZF", }, -{ DIV, INCREG | FEATURE_FPA, - SCREG, TDOUBLE, - SCREG, TDOUBLE, - NCREG, RESC1, - " dvfd A1,AL,AL" COM "double divide\n", }, - -{ DIV, INCREG | FEATURE_VFP, - SCREG, TDOUBLE, - SCREG, TDOUBLE, - NCREG, RESC1, - " fdivd A1,AL,AL" COM "double divide\n", }, - -{ DIV, INBREG, - SBREG, TDOUBLE, - SBREG, TDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, - "ZF", }, - -{ DIV, INCREG | FEATURE_FPA, - SCREG, TLDOUBLE, - SCREG, TLDOUBLE, - NCREG, RESC1, - " dvfe A1,AL,AR" COM "long double load\n", }, - -{ DIV, INCREG | FEATURE_VFP, - SCREG, TLDOUBLE, - SCREG, TLDOUBLE, +{ DIV, INCREG | FEATURE_FPSIMD, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, - " fdivd A1,AL,AL" COM "double divide\n", }, + " fdiv A1,AL,AR" COM "(l)double divide\n", }, -{ DIV, INBREG, - SBREG, TLDOUBLE, - SBREG, TLDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, +{ DIV, INAREG, + SAREG, TDOUBLE|TLDOUBLE, + SAREG, TDOUBLE|TLDOUBLE, + NEEDS(NREG(A, 1), NLEFT(R0), NRIGHT(R1), NRES(R0)), RESC1, "ZF", }, { MOD, INAREG, SAREG, TSWORD, SAREG, TSWORD, - NEEDS(NREG(A, 1), NLEFT(R0), NRIGHT(R1), NRES(R0)), RESC1, + NAREG, RESC1, " sdiv A1, AL, AR" COM "mod\n" - " mul AR, A1, AR\n" - " sub AL, AL, AR\n", }, + " msub A1, A1, AR, AL\n", }, { MOD, INAREG, SAREG, TUWORD, SAREG, TUWORD, - NEEDS(NREG(A, 1), NLEFT(R0), NRIGHT(R1), NRES(R0)), RESC1, + NAREG, RESC1, " udiv A1, AL, AR" COM "unsigned mod\n" - " mul AR, A1, AR\n" - " sub AL, AL, AR\n", }, + " msub A1, A1, AR, AL\n", }, - -{ MOD, INBREG, - SBREG, TLONGLONG, - SBREG, TLONGLONG, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, +{ MOD, INAREG, + SAREG, TLONGLONG, + SAREG, TLONGLONG, + NAREG, RESC1, " sdiv A1, AL, AR" COM "long/longlong mod\n" - " mul AR, A1, AR\n" - " sub AL, AL, AR\n", }, + " msub A1, A1, AR, AL\n", }, -{ MOD, INBREG, - SBREG, TULONGLONG, - SBREG, TULONGLONG, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, +{ MOD, INAREG, + SAREG, TULONGLONG, + SAREG, TULONGLONG, + NAREG, RESC1, " udiv A1, AL, AR" COM "long/longlong unsigned mod\n" - " mul AR, A1, AR\n" - " sub AL, AL, AR\n", }, + " msub A1, A1, AR, AL\n", }, -{ MUL, INAREG | FEATURE_MUL, - SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, - SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, +{ MUL, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG, RESC1, " mul A1,AL,AR\n", }, { MUL, INAREG, - SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, - SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, - NEEDS(NREG(A, 1), NLEFT(R0), NRIGHT(R1), NRES(R0)), RESC1, - "ZE", }, - -{ MUL, INBREG | FEATURE_MULL, - SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, - SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, - NBREG, RESC1, - " smull U1,A1,AL,AR\n", }, - -{ MUL, INBREG | FEATURE_MUL, - SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, - SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, - NBREG, RESC1, - " mul A1,AL,AR\n" - " mov U1,A1,lsr #31\n", }, - -{ MUL, INBREG, - SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, - SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, - "ZE", }, - -{ MUL, INBREG | FEATURE_MULL, - SAREG, TSWORD|TSHORT|TCHAR, - SAREG, TSWORD|TSHORT|TCHAR, - NBREG, RESC1, - " umull U1,A1,AL,AR\n", }, - -{ MUL, INBREG | FEATURE_MUL, - SAREG, TSWORD|TSHORT|TCHAR, - SAREG, TSWORD|TSHORT|TCHAR, - NBREG, RESC1, - " mul A1,AL,AR\n" - " mov U1,#0\n", }, - -{ MUL, INBREG, - SAREG, TSWORD|TSHORT|TCHAR, - SAREG, TSWORD|TSHORT|TCHAR, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, - "ZE", }, - -{ MUL, INBREG | FEATURE_MULL, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, - NBREG, RESC1, - " umull U1,A1,AL,AR\n", }, - -{ MUL, INBREG | FEATURE_MUL, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, - NBREG, RESC1, - " mul A1,AL,AR\n" - " mov U1,A1,lsr #31\n", }, - -{ MUL, INBREG, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, - "ZE", }, - -{ MUL, INCREG | FEATURE_FPA, - SCREG, TFLOAT, - SCREG, TFLOAT, - NCREG, RESC1, - " fmls A1,AL,AL" COM "fast (float) multiply\n", }, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + NAREG, RESC1, + " mul A1,AL,AR\n", }, -{ MUL, INCREG | FEATURE_VFP, +{ MUL, INCREG | FEATURE_FPSIMD, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, - " fmuls A1,AL,AL" COM "float multiply\n", }, + " fmul A1,AL,AR" COM "float multiply\n", }, { MUL, INAREG, SAREG, TFLOAT, @@ -1361,22 +1016,16 @@ struct optab table[] = { NEEDS(NREG(A, 1), NLEFT(R0), NRIGHT(R1), NRES(R0)), RESC1, "ZF", }, -{ MUL, INCREG | FEATURE_FPA, +{ MUL, INCREG | FEATURE_FPSIMD, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, - " mufd A1,AL,AL" COM "fast (l)double multiply\n", }, + " fmul A1,AL,AR" COM "(l)double multiply\n", }, -{ MUL, INCREG | FEATURE_VFP, - SCREG, TDOUBLE|TLDOUBLE, - SCREG, TDOUBLE|TLDOUBLE, - NCREG, RESC1, - " muld A1,AL,AL" COM "(l)double multiply\n", }, - -{ MUL, INBREG, - SBREG, TDOUBLE|TLDOUBLE, - SBREG, TDOUBLE|TLDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R16), NRIGHT(R18), NRES(R16)), RESC1, +{ MUL, INAREG, + SAREG, TDOUBLE|TLDOUBLE, + SAREG, TDOUBLE|TLDOUBLE, + NEEDS(NREG(A, 1), NLEFT(R0), NRIGHT(R1), NRES(R0)), RESC1, "ZF", }, /* @@ -1385,7 +1034,7 @@ struct optab table[] = { { UMUL, INAREG, SANY, TANY, - SOREG|SNAME, TWORD|TPOINT, + SOREG|SNAME, TWORD, NAREG, RESC1, " ldr A1,AL" COM "word load\n", }, @@ -1401,41 +1050,29 @@ struct optab table[] = { NAREG, RESC1, " ldrb A1,AL" COM "uchar load\n", }, -{ UMUL, INAREG | FEATURE_HALFWORDS, +{ UMUL, INAREG, SANY, TANY, SOREG|SNAME, TUSHORT, NAREG, RESC1, " ldrh A1,AL" COM "short load\n", }, -{ UMUL, INAREG | FEATURE_HALFWORDS, +{ UMUL, INAREG, SANY, TANY, SOREG|SNAME, TSHORT, NAREG, RESC1, " ldrsh A1,AL" COM "short load\n", }, -{ UMUL, INAREG, - SANY, TANY, - SOREG|SNAME, TSHORT|TUSHORT, - NEEDS(NREG(A, 2), NSL(A)), RESC1, - "ZH", }, - -{ UMUL, INBREG, +{ UMUL, INAREG, SANY, TANY, - SOREG|SNAME, TLONGLONG|TULONGLONG, - NBREG, RESC1, + SOREG|SNAME, TLONGLONG|TULONGLONG|TPOINT, + NAREG, RESC1, " ldr A1,AL" COM "64-bit load\n", }, -{ UMUL, INCREG | FEATURE_FPA, +{ UMUL, INCREG | FEATURE_FPSIMD, SANY, TANY, SOREG|SNAME, TFLOAT, NCREG, RESC1, - " ldfs A1,AL" COM "float load\n", }, - -{ UMUL, INCREG | FEATURE_VFP, - SANY, TANY, - SOREG|SNAME, TFLOAT, - NCREG, RESC1, - COM "not implemented\n", }, + " ldr A1,AL" COM "float load\n", }, { UMUL, INAREG, SANY, TANY, @@ -1443,44 +1080,17 @@ struct optab table[] = { NAREG, RESC1, " ldr A1,AL" COM "float load\n", }, -{ UMUL, INCREG | FEATURE_FPA, +{ UMUL, INCREG | FEATURE_FPSIMD, SANY, TANY, - SOREG|SNAME, TDOUBLE, + SOREG|SNAME, TDOUBLE|TLDOUBLE, NCREG, RESC1, - " ldfd A1,AL" COM "double load\n", }, + " ldr A1,AL" COM "(l)double load\n", }, -{ UMUL, INCREG | FEATURE_VFP, - SANY, TANY, - SOREG|SNAME, TDOUBLE, - NCREG, RESC1, - COM "not implemented\n", }, - -{ UMUL, INBREG, - SANY, TANY, - SOREG|SNAME, TDOUBLE, - NBREG, RESC1, - " ldr A1,AL" COM "double load\n" - " ldr U1,UL\n", }, - -{ UMUL, INCREG | FEATURE_FPA, - SANY, TANY, - SOREG|SNAME, TLDOUBLE, - NCREG, RESC1, - " ldfe A1,AL" COM "long double load\n", }, - -{ UMUL, INCREG | FEATURE_VFP, - SANY, TANY, - SOREG|SNAME, TLDOUBLE, - NCREG, RESC1, - COM "not implemented\n", }, - -{ UMUL, INBREG, +{ UMUL, INAREG, SANY, TANY, - SOREG|SNAME, TLDOUBLE, - NBREG, RESC1, - " ldr A1,AL" COM "long double load (soft-float)\n" - " ldr U1,UL\n", }, - + SOREG|SNAME, TDOUBLE|TLDOUBLE, + NAREG, RESC1, + " ldr A1,AL" COM "(l)double load\n", }, /* * Logical/branching operators */ @@ -1494,29 +1104,23 @@ struct optab table[] = { /* compare with register */ { OPLOG, FORCC, - SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, - SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TUWORD|TUSHORT|TUCHAR, 0, RESCC, " cmp AL,AR" COM "AR-AL (sets flags)\n", }, /* compare with register */ { OPLOG, FORCC, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TLONGLONG|TULONGLONG|TPOINT, 0, RESCC, " cmp AL,AR" COM "AR-AL (sets flags)\n", }, -{ OPLOG, FORCC | FEATURE_FPA, +{ OPLOG, FORCC | FEATURE_FPSIMD, SCREG, TFLOAT, SCREG, TFLOAT, 0, RESCC, - " cmfs AL,AR" COM "float compare\n", }, - -{ OPLOG, FORCC | FEATURE_VFP, - SCREG, TFLOAT, - SCREG, TFLOAT, - 0, RESCC, - " fcmps AL,AR" COM "float compare\n", }, + " fcmp AL,AR" COM "float compare\n", }, { OPLOG, FORCC, SAREG, TFLOAT, @@ -1524,59 +1128,35 @@ struct optab table[] = { NEEDS(NLEFT(R0), NRIGHT(R1), NRES(R0)), RESCC, "ZF", }, -{ OPLOG, FORCC | FEATURE_FPA, - SCREG, TDOUBLE, - SCREG, TDOUBLE, - 0, RESCC, - " cmfd AL,AR" COM "double compare\n", }, - -{ OPLOG, FORCC | FEATURE_VFP, - SCREG, TDOUBLE, - SCREG, TDOUBLE, - 0, RESCC, - " fcmpd AL,AR" COM "double compare\n", }, - -{ OPLOG, FORCC, - SBREG, TDOUBLE, - SBREG, TDOUBLE, - NEEDS(NLEFT(R16), NRIGHT(R18), NRES(R0)), RESCC, - "ZF", }, - -{ OPLOG, FORCC | FEATURE_FPA, - SCREG, TLDOUBLE, - SCREG, TLDOUBLE, - 0, RESCC, - " cmfe AL,AR" COM "ldouble compare\n", }, - -{ OPLOG, FORCC | FEATURE_VFP, - SCREG, TLDOUBLE, - SCREG, TLDOUBLE, +{ OPLOG, FORCC | FEATURE_FPSIMD, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, 0, RESCC, - " fcmpd AL,AR" COM "double compare\n", }, + " fcmp AL,AR" COM "(l)double compare\n", }, { OPLOG, FORCC, - SBREG, TLDOUBLE, - SBREG, TLDOUBLE, - NEEDS(NLEFT(R16), NRIGHT(R18), NRES(R0)), RESCC, + SAREG, TDOUBLE|TLDOUBLE, + SAREG, TDOUBLE|TLDOUBLE, + NEEDS(NLEFT(R0), NRIGHT(R1), NRES(R0)), RESCC, "ZF", }, /* AND/OR/ER */ -{ AND, INBREG, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, - XSL(B), RESC1|RESCC, +{ AND, INAREG, + SAREG, TLONGLONG|TULONGLONG, + SAREG, TLONGLONG|TULONGLONG, + XSL(A), RESC1|RESCC, " and A1,AL,AR" COM "64-bit and\n", }, -{ OR, INBREG, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, - XSL(B), RESC1, +{ OR, INAREG, + SAREG, TLONGLONG|TULONGLONG, + SAREG, TLONGLONG|TULONGLONG, + XSL(A), RESC1, " orr A1,AL,AR" COM "64-bit or\n", }, -{ ER, INBREG, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, - XSL(B), RESC1, +{ ER, INAREG, + SAREG, TLONGLONG|TULONGLONG, + SAREG, TLONGLONG|TULONGLONG, + XSL(A), RESC1, " eor A1,AL,AR" COM "64-bit xor\n", }, { OPSIMP, INAREG, @@ -1607,153 +1187,188 @@ struct optab table[] = { { OPLTYPE, INAREG, SANY, TANY, - SOREG|SNAME, TWORD|TPOINT, + SOREG, TWORD, NAREG, RESC1, " ldr A1,AL" COM "load word from memory\n" , }, -{ OPLTYPE, INBREG, +{ OPLTYPE, INAREG, + SANY, TANY, + SNAME, TWORD, + NAREG, RESC1, + "ZA" + " ldr A1,[ZXA1]" COM "load word from memory\n" , }, + +{ OPLTYPE, INAREG, SANY, TANY, - SOREG|SNAME, TLONGLONG|TULONGLONG, - NBREG, RESC1, + SOREG, TLONGLONG|TULONGLONG|TPOINT, + NAREG, RESC1, " ldr A1,AL" COM "load long long from memory\n" , }, +{ OPLTYPE, INAREG, + SANY, TANY, + SNAME, TLONGLONG|TULONGLONG|TPOINT, + NAREG, RESC1, + "ZA" + " ldr A1,[ZXA1]" COM "load long long from memory\n" , }, + { OPLTYPE, INAREG, SANY, TANY, - SOREG|SNAME, TCHAR, + SOREG, TCHAR, NAREG, RESC1, " ldrsb A1,AL" COM "load char from memory\n" }, { OPLTYPE, INAREG, SANY, TANY, - SOREG|SNAME, TUCHAR, + SNAME, TCHAR, + NAREG, RESC1, + "ZA" + " ldrsb A1,[ZXA1]" COM "load char from memory\n" }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG, TUCHAR, NAREG, RESC1, " ldrb A1,AL" COM "load uchar from memory\n", }, -{ OPLTYPE, INAREG | FEATURE_HALFWORDS, +{ OPLTYPE, INAREG, SANY, TANY, - SOREG|SNAME, TSHORT, + SNAME, TUCHAR, + NAREG, RESC1, + "ZA" + " ldrb A1,[ZXA1]" COM "load uchar from memory\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG, TSHORT, NAREG, RESC1, " ldrsh A1,AL" COM "load short from memory\n", }, -{ OPLTYPE, INAREG | FEATURE_HALFWORDS, +{ OPLTYPE, INAREG, SANY, TANY, - SOREG|SNAME, TUSHORT, + SNAME, TSHORT, + NAREG, RESC1, + "ZA" + " ldrsh A1,[ZXA1]" COM "load short from memory\n", }, + + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG, TUSHORT, NAREG, RESC1, " ldrh A1,AL" COM "load ushort from memory\n", }, { OPLTYPE, INAREG, SANY, TANY, - SOREG|SNAME, TSHORT|TUSHORT, - NEEDS(NREG(A, 2)), RESC1, - "ZH", }, + SNAME, TUSHORT, + NAREG, RESC1, + "ZA" + " ldrh A1,[ZXA1]" COM "load ushort from memory\n", }, +/* longlong constant initialization */ +{ OPLTYPE, INAREG, + SANY, TLONGLONG|TULONGLONG, + SCON, TLONGLONG|TULONGLONG, + NAREG, RESC1, + "ZJ", }, + +/* integer constant initialization */ { OPLTYPE, INAREG, SANY, TANY, SCON, TANY, NAREG, RESC1, "ZI", }, -{ 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, +{ OPLTYPE, INAREG, SANY, TANY, - SBREG, TLONGLONG|TULONGLONG, - NBREG, RESC1, + SAREG, TLONGLONG|TULONGLONG, + NAREG, RESC1, " mov A1,AL" COM "load AL into A1\n", }, -{ OPLTYPE, INCREG | FEATURE_FPA, +{ OPLTYPE, INCREG | FEATURE_FPSIMD, SANY, TANY, - SOREG|SNAME, TFLOAT, + SOREG, TFLOAT, NCREG, RESC1, - " ldfs A1,AL" COM "load float\n", }, + " ldr A1,AL" COM "load float\n", }, -{ OPLTYPE, INCREG | FEATURE_VFP, +{ OPLTYPE, INCREG | FEATURE_FPSIMD, SANY, TANY, - SOREG|SNAME, TFLOAT, - NCREG, RESC1, - COM "not implemented\n", }, + SNAME, TFLOAT, + NEEDS(NREG(A,1), NREG(C,1)), RESC2, + "ZA" + " ldr A2,[ZXA1]" COM "load float\n", }, { OPLTYPE, INAREG, SANY, TANY, - SOREG|SNAME, TFLOAT, + SOREG, TFLOAT, NAREG, RESC1, " ldr A1,AL" COM "load float (soft-float)\n", }, -{ OPLTYPE, INCREG | FEATURE_FPA, +{ OPLTYPE, INAREG, SANY, TANY, - SOREG|SNAME, TDOUBLE, - NCREG, RESC1, - " ldfd A1,AL" COM "load double\n", }, + SNAME, TFLOAT, + NAREG, RESC1, + "ZA" + " ldr A1,[ZXA1]" COM "load float (soft-float)\n", }, -{ OPLTYPE, INCREG | FEATURE_VFP, +{ OPLTYPE, INCREG | FEATURE_FPSIMD, SANY, TANY, - SOREG|SNAME, TDOUBLE, + SOREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, - COM "not implemented\n" }, + " ldr A1,AL" COM "load (l)double\n", }, -{ OPLTYPE, INBREG, +{ OPLTYPE, INCREG | FEATURE_FPSIMD, SANY, TANY, - SOREG|SNAME, TDOUBLE, - NBREG, RESC1, - " ldr A1,AL" COM "load double (soft-float)\n" - " ldr U1,UL\n", }, + SNAME, TDOUBLE|TLDOUBLE, + NEEDS(NREG(A,1), NREG(C,1)), RESC2, + "ZA" + " ldr A2,[ZXA1]" COM "load (l)double\n", }, -{ OPLTYPE, INCREG | FEATURE_FPA, +{ OPLTYPE, INAREG, SANY, TANY, - SOREG|SNAME, TLDOUBLE, - NCREG, RESC1, - " ldfe A1,AL" COM "load ldouble\n", }, + SOREG, TDOUBLE|TLDOUBLE, + NAREG, RESC1, + " ldr A1,AL" COM "load (l)double (soft-float)\n", }, -{ OPLTYPE, INCREG | FEATURE_VFP, +{ OPLTYPE, INAREG, SANY, TANY, - SOREG|SNAME, TLDOUBLE, + SNAME, TDOUBLE|TLDOUBLE, + NAREG, RESC1, + "ZA" + " ldr A1,[ZXA1]" COM "load (l)double (soft-float)\n", }, + +{ OPLTYPE, INCREG | FEATURE_FPSIMD, + SANY, TANY, + SCREG, TANY, NCREG, RESC1, - COM "not implemented\n", }, - -{ OPLTYPE, INBREG, - SANY, TANY, - SOREG|SNAME, TLDOUBLE, - NBREG, RESC1, - " ldr A1,AL" COM "load ldouble (soft-float)\n" - " ldr U1,UL\n", }, + " mov A1,AL" COM "load AL into A1\n" }, /* * Negate a word. */ { UMINUS, INAREG, - SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, - SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, XSL(A), RESC1, " neg A1,AL" COM "negation\n", }, -{ UMINUS, INBREG, - SBREG, TLONGLONG|TULONGLONG, - SBREG, TLONGLONG|TULONGLONG, - XSL(B), RESC1, +{ UMINUS, INAREG, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + XSL(A), RESC1, " neg A1,AL" COM "64-bit negation\n", }, -{ UMINUS, INCREG | FEATURE_FPA, +{ UMINUS, INCREG | FEATURE_FPSIMD, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, - " mvfs A1,AL" COM "float negation\n", }, - -{ UMINUS, INCREG | FEATURE_VFP, - SCREG, TFLOAT, - SCREG, TFLOAT, - NCREG, RESC1, - " negs A1,AL" COM "float negation\n", }, + " fneg A1,AL" COM "float negation\n", }, { UMINUS, INAREG, SAREG, TFLOAT, @@ -1761,40 +1376,16 @@ struct optab table[] = { NEEDS(NREG(A, 1), NLEFT(R0), NRES(R0)), RESC1, "ZF", }, -{ UMINUS, INCREG | FEATURE_FPA, - SCREG, TDOUBLE, - SCREG, TDOUBLE, - NCREG, RESC1, - " mvfd A1,AL" COM "double negation\n", }, - -{ UMINUS, INCREG | FEATURE_VFP, - SCREG, TDOUBLE, - SCREG, TDOUBLE, - NCREG, RESC1, - " negd A1,AL" COM "double negation\n", }, - -{ UMINUS, INBREG, - SBREG, TDOUBLE, - SBREG, TDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R16), NRES(R16)), RESC1, - "ZF", }, - -{ UMINUS, INCREG | FEATURE_FPA, - SCREG, TLDOUBLE, - SCREG, TLDOUBLE, - NCREG, RESC1, - " mvfe A1,AL" COM "ldouble negation\n", }, - -{ UMINUS, INCREG | FEATURE_VFP, - SCREG, TLDOUBLE, - SCREG, TLDOUBLE, +{ UMINUS, INCREG | FEATURE_FPSIMD, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, - " negd A1,AL" COM "ldouble negation\n", }, + " fneg A1,AL" COM "(l)double negation\n", }, -{ UMINUS, INBREG, - SBREG, TLDOUBLE, - SBREG, TLDOUBLE, - NEEDS(NREG(B, 1), NLEFT(R16), NRES(R16)), RESC1, +{ UMINUS, INAREG, + SAREG, TDOUBLE, + SAREG, TDOUBLE, + NEEDS(NREG(A, 1), NLEFT(R0), NRES(R0)), RESC1, "ZF", }, { COMPL, INAREG, @@ -1803,10 +1394,10 @@ struct optab table[] = { XSL(A), RESC1, " mvn A1,AL" COM "complement\n", }, -{ COMPL, INBREG, - SBREG, TLONGLONG|TULONGLONG, +{ COMPL, INAREG, + SAREG, TLONGLONG|TULONGLONG, SANY, TANY, - XSL(B), RESC1, + XSL(A), RESC1, " mvn A1,AL" COM "64-bit complement\n", }, /* @@ -1814,14 +1405,14 @@ struct optab table[] = { */ { FUNARG, FOREFF, - SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, - SANY, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, 0, 0, " stmfd sp!,{AL}" COM "save function arg to stack\n", }, { FUNARG, FOREFF, - SBREG, TLONGLONG|TULONGLONG, - SANY, TLONGLONG|TULONGLONG, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SANY, TLONGLONG|TULONGLONG|TPOINT, 0, 0, " stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", }, @@ -1837,6 +1428,12 @@ struct optab table[] = { 0, 0, " stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", }, +{ ADDROF, INAREG, + SNAME, TANY, + SANY, TANY, + NAREG, RESC1, + "ZA", }, + # define DF(x) FORREW,SANY,TANY,SANY,TANY,NEEDS(NREWRITE),x,"" { UMUL, DF( UMUL ), }, diff --git a/cc/ccom/init.c b/cc/ccom/init.c index a08d6f10c..a4e9ce439 100644 --- a/cc/ccom/init.c +++ b/cc/ccom/init.c @@ -1058,7 +1058,7 @@ strcvt(struct initctx *ctx, NODE *p) char *s; int i; -#ifdef mach_arm +#if defined(mach_arm) || defined(mach_aarch64) /* XXX */ if (p->n_op == UMUL && p->n_left->n_op == ADDROF) p = p->n_left->n_left; @@ -1282,6 +1282,9 @@ simpleinit(struct symtab *sp, NODE *p) (p->n_sp->sflags & SMASK) == SSTRING) p->n_sp->sflags |= SASG; p = optloop(buildtree(ASSIGN, nt, p)); + /* for structure assignment */ + if (p->n_op == UMUL) + p = p1nfree(p); q = p->n_right; t = q->n_type; sz = (int)tsize(t, q->n_df, q->pss); diff --git a/cc/ccom/optim.c b/cc/ccom/optim.c index 13c8fc5a8..0b9c69080 100644 --- a/cc/ccom/optim.c +++ b/cc/ccom/optim.c @@ -159,6 +159,14 @@ again: o = p->n_op; /* Do not discard ADDROF TEMP's */ if (LO(p) == ADDROF && LO(p->n_left) != TEMP) { q = p->n_left->n_left; + /* + * Type might have changed during UMUL & ADDROF. + * This can occur when the first field of a struct + * in the first element of a struct array is accessed. + * + * Patch the type to be equivalent to the type in UMUL. + */ + q->n_type = p->n_type; nfree(p->n_left); nfree(p); p = q; diff --git a/cc/ccom/params.c b/cc/ccom/params.c index 9dbebfe7c..1dc84c944 100644 --- a/cc/ccom/params.c +++ b/cc/ccom/params.c @@ -485,6 +485,33 @@ if (pdebug) printf("pr_hasell: dsym %d\n", dsym); return 0; } +/* + * Obtain the vararg start index of a function. + * Return index if the function has varargs. + * Return -1 if the function does not have varargs. + */ +int +pr_ellidx(int dsym) +{ + int t, i; + i = 0; + +if (pdebug) printf("pr_ellidx: dsym %d\n", dsym); + SEEKRD(dsym, t); + while (t != TNULL) { + if (t == TELLIPSIS) + return i; + if (ISSOU(BTYPE(t))) + (void)pr_rptr(); + for (; t > BTMASK; t = DECREF(t)) + if (ISFTN(t) || ISARY(t)) + (void)pr_rptr(); + t = pr_rd(); + i++; + } + return -1; +} + /* * Extract the important parts of arguments and put away them for * prototype checking. diff --git a/cc/ccom/pass1.h b/cc/ccom/pass1.h index a80cd024c..1f18a0734 100644 --- a/cc/ccom/pass1.h +++ b/cc/ccom/pass1.h @@ -461,6 +461,7 @@ struct symtab *strmemb(struct ssdesc *); int yylex(void); void yyerror(char *); int pragmas_gcc(char *t); +P1ND *cstknode(TWORD t, union dimfun *df, struct ssdesc *ss); int concast(P1ND *p, TWORD t); char *stradd(char *old, char *new); #ifdef WORD_ADDRESSED @@ -485,6 +486,7 @@ int pr_ckproto(int usym, int udef, int old); void pr_callchk(struct symtab *sp, P1ND *f, P1ND *a); void pr_oldstyle(struct symtab **as, int nparams); int pr_hasell(int); +int pr_ellidx(int); struct tdef *intdef(struct tdef *, TWORD); struct tdef *intdefq(TWORD); void incref(struct tdef *d, struct tdef *s); diff --git a/cc/cxxcom/pass1.h b/cc/cxxcom/pass1.h index 1e25d9393..7c4356907 100644 --- a/cc/cxxcom/pass1.h +++ b/cc/cxxcom/pass1.h @@ -132,6 +132,7 @@ union dimfun { }; #define dlst dfun /* XXX workaround for ccom changes */ int pr_hasell(union arglist *df); +int pr_ellidx(union arglist *df); /* * Argument list member info when storing prototypes. diff --git a/cc/cxxcom/pftn.c b/cc/cxxcom/pftn.c index 423f1b500..0dc7781c6 100644 --- a/cc/cxxcom/pftn.c +++ b/cc/cxxcom/pftn.c @@ -3343,3 +3343,30 @@ pr_hasell(union arglist *al) } return 1; } + +/* + * Obtain the vararg start index of a function. + * Return index if the function has varargs. + * Return -1 if the function does not have varargs. + */ +int +pr_ellidx(union arglist *al) +{ + int t, i, idx; + i = idx = 0; + + for (; al->type != TELLIPSIS; al++) { + t = al->type; + if (t == TNULL) + return -1; + if (ISSOU(BTYPE(t))) + al++; + for (i = 0; t > BTMASK; t = DECREF(t)) + if (ISARY(t) || ISFTN(t)) + i++; + if (i) + al++; + idx++; + } + return i; +} diff --git a/common/softfloat.c b/common/softfloat.c index 66779b78a..cd8a43d28 100644 --- a/common/softfloat.c +++ b/common/softfloat.c @@ -259,11 +259,6 @@ FPI fpi_binary16 = { 11, 1-15-11+1, 30-15-11+1, 1, 0, 0, 1, 1, 0, 16, 15+11-1 }; #endif -#ifdef notyet -FPI fpi_binary128 = { 113, 1-16383-113+1, - 32766-16383-113+1, 1, 0, - 0, 1, 1, 0, 128, 16383+113-1 }; -#endif #ifdef USE_IEEEFP_32 #define IEEEFP_32_ISINF(x) (((x)->fp[0] & 0x7fffffff) == 0x7f800000) @@ -456,6 +451,161 @@ FPI fpi_binary64 = { }; #endif +#ifdef USE_IEEEFP_128 +#define IEEEFP_128_ISINF(x) \ + ((((x)->fp[3] & 0x7fffffff) == 0x7fff0000) && \ + (x)->fp[2] == 0 && (x)->fp[1] == 0 && (x)->fp[0] == 0) + +#define IEEEFP_128_ISZERO(x) \ + ((((x)->fp[3] & 0x7fffffff) == 0) && \ + (x)->fp[2] == 0 && (x)->fp[1] == 0 && (x)->fp[0] == 0) + +#define IEEEFP_128_ISNAN(x) \ + ((((x)->fp[3] & 0x7fffffff) == 0x7fff8000) && \ + (x)->fp[2] == 0 && (x)->fp[1] == 0 && (x)->fp[0] == 0) + +static int +ieee128_classify(SFP sfp) +{ + /* Mask out the sign bit (31), check the 15-bit exponent */ + int e = sfp->fp[3] & 0x7fff0000; + + if (IEEEFP_128_ISINF(sfp)) + return SOFT_INFINITE; + if (IEEEFP_128_ISNAN(sfp)) + return SOFT_NAN; + if (IEEEFP_128_ISZERO(sfp)) + return SOFT_ZERO; + if (e) + return SOFT_NORMAL; + return SOFT_SUBNORMAL; +} + +static int +ieee128_unmake(SFP sfp, int *sign, int *exp, MINT *m) +{ + int t, v = ieee128_classify(sfp); + + *sign = (sfp->fp[3] >> 31) & 1; + /* Exponent is bits 30-16 (15 bits) of high word */ + *exp = ((sfp->fp[3] >> 16) & 0x7fff) - fpi_binary128.bias; + + /* * Unpack 128 bits into MINT. + * We need 112 bits of stored mantissa. + * Assuming MINT val[] are 16-bit chunks. + * We need 7 chunks (112/16) just for stored bits. + */ + minit(m, sfp->fp[0]); // Initialize with LSB? Depends on your minit impl. + + // Low word (bits 0-31) + m->val[0] = sfp->fp[0] & 0xffff; + m->val[1] = (sfp->fp[0] >> 16); + + // Mid-low word (bits 32-63) + m->val[2] = sfp->fp[1] & 0xffff; + m->val[3] = (sfp->fp[1] >> 16); + + // Mid-high word (bits 64-95) + m->val[4] = sfp->fp[2] & 0xffff; + m->val[5] = (sfp->fp[2] >> 16); + + // High word (bits 96-111 stored here) + m->val[6] = sfp->fp[3] & 0xffff; + // val[7] will hold the implicit bit later + m->val[7] = 0; + + m->len = 8; // Ensure MINT treats this as 8 chunks + + if (v == SOFT_SUBNORMAL) { + v = SOFT_NORMAL; + chomp(m); + t = topbit(m); + /* Adjust for 113 bits precision */ + *exp = fpi_binary128.minexp - (fpi_binary128.nbits - t) + 1; + } else if (v == SOFT_NORMAL) { + /* * Implicit bit is at bit 112. + * 112 / 16 = 7. Remainder 0. + * So it is bit 0 of val[7]. + */ + m->val[7] |= 1; + } + return v; +} +static void +ieee128_make(SFP sfp, int typ, int sign, int exp, MINT *m) +{ + sfp->fp[0] = 0; + sfp->fp[1] = 0; + sfp->fp[2] = 0; + /* Initialize high word with just the sign bit */ + sfp->fp[3] = (sign << 31); + + SD(("ieee128_make: typ %s sign %d exp %d M ... %04x%04x\n", + sftyp[typ], sign, exp, m->val[1], m->val[0])); + + if (typ == SOFT_NORMAL) + typ = mknormal(&fpi_binary128, &exp, m); + + SD(("ieee128_make2: typ %s sign %d exp %d\n", sftyp[typ], sign, exp)); + + switch (typ) { + case SOFT_ZERO: + break; + case SOFT_INFINITE: + sfp->fp[3] |= 0x7fff0000; + break; + case SOFT_NAN: + sfp->fp[3] |= 0x7fff8000; + break; + case SOFT_NORMAL: + /* * FIX: Do not subtract 1 from bias. + * The 64-bit code subtracted 1 because the implicit bit in val[3] + * overflowed into the exponent field. + * We are not packing val[7] (the implicit bit) into fp[3], + * so we do not need to compensate for it. + */ + exp += fpi_binary128.bias; + + /* Pack LSBs */ + sfp->fp[0] = ((uint32_t)m->val[1] << 16) | m->val[0]; + sfp->fp[1] = ((uint32_t)m->val[3] << 16) | m->val[2]; + sfp->fp[2] = ((uint32_t)m->val[5] << 16) | m->val[4]; + + /* Pack MSBs: val[6] contains the top 16 stored bits (96-111) */ + sfp->fp[3] |= (uint32_t)m->val[6] & 0xffff; + + /* Add Exponent (bits 16-30) */ + sfp->fp[3] |= (uint32_t)(exp & 0x7fff) << 16; + break; + case SOFT_SUBNORMAL: + sfp->fp[0] = ((uint32_t)m->val[1] << 16) | m->val[0]; + sfp->fp[1] = ((uint32_t)m->val[3] << 16) | m->val[2]; + sfp->fp[2] = ((uint32_t)m->val[5] << 16) | m->val[4]; + sfp->fp[3] |= (uint32_t)m->val[6] & 0xffff; + break; + } + SD(("ieee128_make3: fp %08x %08x %08x %08x\n", + sfp->fp[3], sfp->fp[2], sfp->fp[1], sfp->fp[0])); +} + +/* Ensure struct is updated if you haven't already */ +FPI fpi_binary128 = { + .nbits = IEEEFP_128_MANT_DIG, + .storage = 128, + .bias = 16383, + .minexp = IEEEFP_128_MIN_EXP - 1, + .maxexp = IEEEFP_128_MAX_EXP - 1, + .min10exp = IEEEFP_128_MIN_10_EXP - 1, + .max10exp = IEEEFP_128_MAX_10_EXP - 1, + .dig = IEEEFP_128_DIG, + .expadj = 1, /* This stays 1, it interacts with mknormal */ + + .make = ieee128_make, + .unmake = ieee128_unmake, + .classify = ieee128_classify, +}; +#endif + #ifdef USE_IEEEFP_X80 #define IEEEFP_X80_ISINF(x) ((((x)->fp[2] & 0x7fff) == 0x7fff) && \ ((x)->fp[1] == 0x80000000) && (x)->fp[0] == 0) diff --git a/common/softfloat.h b/common/softfloat.h index da46abb6d..12ad72234 100644 --- a/common/softfloat.h +++ b/common/softfloat.h @@ -56,6 +56,7 @@ extern struct FPI fpi_ffloat; extern struct FPI fpi_dfloat; extern struct FPI fpi_binary32; extern struct FPI fpi_binary64; +extern struct FPI fpi_binary128; extern struct FPI fpi_binaryx80; /* MP package */ @@ -98,6 +99,19 @@ typedef struct mint { #define IEEEFP_64_HAS_SUBNORM 1 #define IEEEFP_64_TRUE_MIN 0x1.0p-1074 #endif +#ifdef USE_IEEEFP_128 +#define IEEEFP_128_DIG 33 +#define IEEEFP_128_EPSILON 0x1.0p-112L +#define IEEEFP_128_MAX_10_EXP 4932 +#define IEEEFP_128_MAX_EXP 16384 +#define IEEEFP_128_MAX 0x1.ffffffffffffffffffffffffffffp+16383L +#define IEEEFP_128_MIN_10_EXP (-4931) +#define IEEEFP_128_MIN_EXP (-16381) +#define IEEEFP_128_MIN 0x1.0p-16382L +#define IEEEFP_128_MANT_DIG 113 +#define IEEEFP_128_HAS_SUBNORM 1 +#define IEEEFP_128_TRUE_MIN 0x1.0p-16494L +#endif #ifdef USE_IEEEFP_X80 #define IEEEFP_X80_DIG 18 #define IEEEFP_X80_EPSILON 1.08420217248550443401e-19L diff --git a/configure b/configure index 340c774d6..11df0c99f 100755 --- a/configure +++ b/configure @@ -2942,6 +2942,7 @@ case "$target_os" in *7.*) targosver=7 ;; esac case "$target_cpu" in + aarch64) targmach=aarch64 ;; i?86) targmach=i386 ;; powerpc) targmach=powerpc endian=big ;; x86_64) targmach=amd64 ;; diff --git a/configure.ac b/configure.ac index 3e647fc8a..cb0603bb8 100644 --- a/configure.ac +++ b/configure.ac @@ -53,6 +53,7 @@ case "$target_os" in *7.*) targosver=7 ;; esac case "$target_cpu" in + aarch64) targmach=aarch64 ;; i?86) targmach=i386 ;; powerpc) targmach=powerpc endian=big ;; x86_64) targmach=amd64 ;; diff --git a/os/linux/ccconfig.h b/os/linux/ccconfig.h index f81d690b4..ef096f484 100644 --- a/os/linux/ccconfig.h +++ b/os/linux/ccconfig.h @@ -67,6 +67,7 @@ #elif defined(mach_aarch64) #define CPPMDADD { "-D__aarch64__", NULL, } #define MUSL_DYLIB "/lib/ld-musl-aarch64.so.1" +#define STDINC "/usr/include", "/usr/include/aarch64-linux-gnu" #elif defined(mach_m68k) #define CPPMDADD { "-D__m68k__", NULL, } #else