From ba6eec0d3886b1fdb3c6c0bfc965aa87ee19590f Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Wed, 5 Nov 2025 18:13:56 +0300 Subject: [PATCH 01/27] aarch64: Add Darwin configuration. Signed-off-by: Hakan Candar --- configure | 1 + configure.ac | 1 + 2 files changed, 2 insertions(+) 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 ;; From 8eb0b9c65135e81b8c95c565d49f9385b035a4a1 Mon Sep 17 00:00:00 2001 From: hakanrw Date: Mon, 16 Feb 2026 17:47:41 +0100 Subject: [PATCH 02/27] aarch64: Add architecture-dependent include path in Linux configuration. Add /usr/include/aarch64-none-linux-gnu to STDINC, as glibc expects this to be available in the include path. Signed-off-by: hakanrw --- os/linux/ccconfig.h | 1 + 1 file changed, 1 insertion(+) 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 From 07c139cf783de01260621b2cfe475ce9e8502347 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Wed, 21 Jan 2026 18:41:01 +0300 Subject: [PATCH 03/27] aarch64: Fix ABI inaccuracies. Remove 32-bit ARMv7 assumptions. Signed-off-by: Hakan Candar --- arch/aarch64/local.c | 5 +- arch/aarch64/local2.c | 133 ++++++++++++++++++----------------- arch/aarch64/macdefs.h | 153 ++++++++++++++++++++++++++++++++++------- 3 files changed, 200 insertions(+), 91 deletions(-) diff --git a/arch/aarch64/local.c b/arch/aarch64/local.c index 9c21b4a31..a1417c783 100644 --- a/arch/aarch64/local.c +++ b/arch/aarch64/local.c @@ -134,7 +134,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: @@ -200,7 +200,7 @@ clocal(NODE *p) 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) { @@ -385,7 +385,6 @@ 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; diff --git a/arch/aarch64/local2.c b/arch/aarch64/local2.c index 96468156e..4f44b8e3e 100644 --- a/arch/aarch64/local2.c +++ b/arch/aarch64/local2.c @@ -23,32 +23,46 @@ #include "pass2.h" +#define SZFPSP 16 + extern void defalign(int); -int isConverstion=0; -int addStack=0; +static int isConverstion=0; +static int addStack=0; #define exname(x) x /* 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" }; /* @@ -142,8 +156,8 @@ offcalc(struct interpass_prolog *ipp) void prologue(struct interpass_prolog *ipp) { - int addto; - int vals[4], nc, i; + int addto; + int vals[4], nc, i; #ifdef PCC_DEBUG if (x2debug) @@ -159,30 +173,37 @@ 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); + printf("%s:\n", exname(ipp->ipp_name)); + + addto = offcalc(ipp); + +#define BALSTACK (ALSTACK/SZCHAR) + if (addto < BALSTACK) { + addto = BALSTACK; + } + if (addto % BALSTACK) { + addto = addto + (BALSTACK - (addto % BALSTACK)); + } +#undef BALSTACK + addStack = addto; + + printf("\tstp %s,%s,[%s,#%d]!\n", rnames[FP], rnames[LR], rnames[SP], -SZFPSP); + printf("\tmov %s,%s\n", rnames[FP], rnames[SP]); + 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]); + 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; } void eoftn(struct interpass_prolog *ipp) { + int vals[4], nc, i; + if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ @@ -190,16 +211,16 @@ 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); - } + if (trepresent(addStack)) { + printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], addStack); + } else { + nc = encode_constant(addStack, vals); + for (i = 0; i < nc; i++) + printf("\tadd %s,%s,#%d\n", + rnames[SP], rnames[SP], vals[i]); + } + printf("\tldp %s,%s,[%s],#%d\n", rnames[FP], rnames[LR], + rnames[SP], SZFPSP); } printf("\tret\n"); #ifndef MACHOABI @@ -776,6 +797,7 @@ adrput(FILE *io, NODE *p) case REG: switch (p->n_type) { + case FLOAT: case CHAR: case UCHAR: case INT: @@ -796,14 +818,9 @@ adrput(FILE *io, NODE *p) 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]); + fprintf(io, "%s", rnames[p->n_rval]); break; default: fprintf(io, "%s", rnames[p->n_rval]); @@ -1040,8 +1057,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)) { @@ -1108,20 +1124,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 +1136,8 @@ int retreg(int t) { int c = gclass(t); - if (c == CLASSB) - return R16; + if (c == CLASSC) + return V0; return R0; } diff --git a/arch/aarch64/macdefs.h b/arch/aarch64/macdefs.h index 722c63dca..b64eecd78 100644 --- a/arch/aarch64/macdefs.h +++ b/arch/aarch64/macdefs.h @@ -28,7 +28,7 @@ * Storage space requirements */ #define SZCHAR 8 -#define SZBOOL 32 +#define SZBOOL 8 /* XXX - investigate */ #define SZINT 32 #define SZFLOAT 32 #define SZDOUBLE 64 @@ -42,17 +42,17 @@ * 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 +#define ALLDOUBLE 64 +#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 +63,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 +73,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 +96,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 +136,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 +248,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 +274,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 */ @@ -208,7 +311,7 @@ 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 From fde4f8b13a92e3a4a9063c64cf63224b71e07f5b Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Thu, 22 Jan 2026 14:28:54 +0300 Subject: [PATCH 04/27] aarch64: Remove macro definition which creates disrepancies across TUs. This broke symtab definition across local.c and symtabs.c, which lead to major ICE. Refactor to use `sss` instead of `sap`, similar to amd64 backend. Also fix segmentation fault in exname() caused by sp->sname not being set to NULL during initialization. Signed-off-by: Hakan Candar --- arch/aarch64/local.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/aarch64/local.c b/arch/aarch64/local.c index a1417c783..c7dd39567 100644 --- a/arch/aarch64/local.c +++ b/arch/aarch64/local.c @@ -30,6 +30,7 @@ #ifdef LANG_CXX #define p1listf listf #define p1tfree tfree +#define sss sap #else #define NODE P1ND #define talloc p1alloc @@ -54,10 +55,6 @@ getsoname(struct symtab *sp) ap->sarg(0) : sp->sname; } -#ifndef LANG_CXX -#define sap sss -#endif - /* * clocal() is called to do local transformations on * an expression tree before being sent to the backend. @@ -307,15 +304,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); @@ -482,7 +481,7 @@ defzero(struct symtab *sp) { int off; - off = tsize(sp->stype, 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) From 2abc716445e95973d73fbe53c84d47a952085331 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Wed, 21 Jan 2026 18:42:49 +0300 Subject: [PATCH 05/27] aarch64: Fix problems in stack frame setup and parameter passing mechanisms. Remove 32-bit ARMv7 assumptions. Signed-off-by: Hakan Candar --- arch/aarch64/code.c | 442 ++++++++++++++---------------------------- arch/aarch64/local2.c | 19 +- 2 files changed, 162 insertions(+), 299 deletions(-) diff --git a/arch/aarch64/code.c b/arch/aarch64/code.c index ac0b233fb..ec0b3a74b 100644 --- a/arch/aarch64/code.c +++ b/arch/aarch64/code.c @@ -22,7 +22,6 @@ #include #include "pass1.h" -#include "pass2.h" #ifdef LANG_CXX #define p1listf listf @@ -43,6 +42,8 @@ #endif static int rvnr; +int p1maxstacksize = 0; /* XXX - remove, move calculation to pass2 */ + /* * Print out assembler segment name. @@ -103,12 +104,12 @@ defloc(struct symtab *sp) * 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 = buildtree(ASSIGN, p, q); sym->soffset = regno(p->n_left); sym->sflags |= STNODE; ecomp(p); @@ -117,151 +118,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->sap); + 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->sap); + 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 @@ -284,9 +211,10 @@ 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 *stackofsp) { - int argofs = *argofsp; + /* XXX - investigate, is stack correct? */ + int argofs = *regp; NODE *p, *q; int navail; int sz; @@ -309,7 +237,7 @@ param_struct(struct symtab *sym, int *argofsp) ecomp(p); } - *argofsp = argofs; + *regp = argofs; } @@ -322,20 +250,29 @@ 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; + ++reg; } /* recalculate the arg offset and create TEMP moves */ @@ -344,40 +281,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], ®, &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); @@ -531,7 +460,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,180 +473,88 @@ 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 *stackofsp) { + /* XXX - investigate */ int reg = *regp; NODE *l, *q, *t, *r; int tmpnr; @@ -767,7 +604,7 @@ movearg_struct(NODE *p, int *regp) 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, ®); + r = pusharg(t, stackofsp); q = block(CM, q, r, INT, 0, 0); } @@ -779,13 +616,12 @@ movearg_struct(NODE *p, int *regp) static NODE * -moveargs(NODE *p, int *regp) +moveargs(NODE *p, 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, regp, fregp, stackofsp); r = p->n_right; rp = &p->n_right; } else { @@ -793,18 +629,26 @@ 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, stackofsp); + } else if ((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); } @@ -873,17 +717,21 @@ builtin_cfa(const struct bitable *bt, NODE *a) NODE * funcode(NODE *p) { - int reg = R0; + int reg, freg, stackofs; + reg = freg = stackofs = 0; if (p->n_type == STRTY+FTN || p->n_type == UNIONTY+FTN) { p = retstruct(p); reg = R1; } - p->n_right = moveargs(p->n_right, ®); + p->n_right = moveargs(p->n_right, ®, &freg, &stackofs); if (p->n_right == NULL) p->n_op += (UCALL - CALL); + if (stackofs > p1maxstacksize) + p1maxstacksize = stackofs; + return p; } diff --git a/arch/aarch64/local2.c b/arch/aarch64/local2.c index 4f44b8e3e..9d066bba4 100644 --- a/arch/aarch64/local2.c +++ b/arch/aarch64/local2.c @@ -65,6 +65,8 @@ char *rnames[] = { "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. @@ -143,6 +145,12 @@ offcalc(struct interpass_prolog *ipp) addto = p2maxautooff; + /* XXX - move calculation from pass1 to pass2. + * it works, but it is hacky. we are crossing + * the pass1-pass2 boundary informally. + */ + addto += p1maxstacksize; + #ifdef PCC_DEBUG if (x2debug) printf("offcalc: addto=%d\n", addto); @@ -611,19 +619,25 @@ argsiz(NODE *p) void zzzcode(NODE *p, int c) { - int pr; - switch (c) { 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; @@ -1000,6 +1014,7 @@ myreader(struct interpass *ipole) break; } } + if (x2debug) printip(ipole); } From d4709b24f7b4e283adfb384f9c14a63875e21830 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Wed, 4 Feb 2026 21:29:10 +0300 Subject: [PATCH 06/27] aarch64: Implement address loading helpers. Signed-off-by: Hakan Candar --- arch/aarch64/local2.c | 67 ++++++++++++++++++++++++++++++++++++------- arch/aarch64/table.c | 6 ++++ 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/arch/aarch64/local2.c b/arch/aarch64/local2.c index 9d066bba4..655bb6cd0 100644 --- a/arch/aarch64/local2.c +++ b/arch/aarch64/local2.c @@ -29,6 +29,7 @@ extern void defalign(int); static int isConverstion=0; static int addStack=0; +static int isExtend=0; #define exname(x) x /* @@ -616,10 +617,46 @@ 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 (1 /* normal */) { +#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) { switch (c) { + case 'A': /* load address of NAME */ + addrload(p); + break; + case 'B': /* bit-field sign extension */ bfext(p); break; @@ -669,6 +706,10 @@ zzzcode(NODE *p, int c) stasg(p); break; + case 'X': + isExtend = 1; + break; + default: comperr("zzzcode %c", c); } @@ -824,6 +865,10 @@ adrput(FILE *io, NODE *p) fprintf(io, "%s", wnames[0]); isConverstion = 0; } + else if (isExtend) { + fprintf(io, "%s", rnames[p->n_rval]); + isExtend = 0; + } else fprintf(io, "%s", wnames[p->n_rval]); } @@ -944,7 +989,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 */ @@ -959,8 +1004,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; } @@ -969,25 +1014,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 diff --git a/arch/aarch64/table.c b/arch/aarch64/table.c index f1981982a..00ce74644 100644 --- a/arch/aarch64/table.c +++ b/arch/aarch64/table.c @@ -1837,6 +1837,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 ), }, From 441895d349c211a7307167cee2e08b273d2cad7f Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Mon, 24 Nov 2025 22:31:50 +0300 Subject: [PATCH 07/27] aarch64: Fix instruction table for 64-bits. Remove 32-bit ARMv7 assumptions. Signed-off-by: Hakan Candar --- arch/aarch64/local.c | 21 +- arch/aarch64/local2.c | 85 +----- arch/aarch64/macdefs.h | 1 - arch/aarch64/table.c | 664 ++++++++++++++++++++--------------------- 4 files changed, 353 insertions(+), 418 deletions(-) diff --git a/arch/aarch64/local.c b/arch/aarch64/local.c index c7dd39567..70a47ed95 100644 --- a/arch/aarch64/local.c +++ b/arch/aarch64/local.c @@ -69,6 +69,23 @@ clocal(NODE *p) int tmpnr, isptrvoid = 0; 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: @@ -264,8 +281,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) diff --git a/arch/aarch64/local2.c b/arch/aarch64/local2.c index 655bb6cd0..ebdc5625c 100644 --- a/arch/aarch64/local2.c +++ b/arch/aarch64/local2.c @@ -27,7 +27,7 @@ extern void defalign(int); -static int isConverstion=0; +static int isShrink=0; static int addStack=0; static int isExtend=0; #define exname(x) x @@ -544,49 +544,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) { @@ -676,8 +633,8 @@ zzzcode(NODE *p, int c) 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); @@ -687,10 +644,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"); @@ -698,7 +651,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; @@ -860,30 +813,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 if (isExtend) { - fprintf(io, "%s", rnames[p->n_rval]); - isExtend = 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: case LONGLONG: case ULONGLONG: - fprintf(io, "%s", rnames[p->n_rval]); + 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: @@ -1232,9 +1179,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 #else -#define DEFAULT_FEATURES FEATURE_MUL +#define DEFAULT_FEATURES FEATURE_EXTEND #endif static int fset = DEFAULT_FEATURES; diff --git a/arch/aarch64/macdefs.h b/arch/aarch64/macdefs.h index b64eecd78..14f34ba22 100644 --- a/arch/aarch64/macdefs.h +++ b/arch/aarch64/macdefs.h @@ -287,7 +287,6 @@ int retreg(int ty); int features(int f); #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 diff --git a/arch/aarch64/table.c b/arch/aarch64/table.c index 00ce74644..ecf370000 100644 --- a/arch/aarch64/table.c +++ b/arch/aarch64/table.c @@ -28,8 +28,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 +43,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 +73,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/ushort/uint\n", }, + " 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, + " mov A1,AL" COM "convert char to uint\n", }, { SCONV, INAREG | FEATURE_EXTEND, SAREG, TUCHAR, @@ -87,8 +99,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 +114,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 +136,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 +149,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 +174,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 +187,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,26 +286,19 @@ 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, @@ -332,6 +323,7 @@ struct optab table[] = { NEEDS(NREG(A, 1), NLEFT(R0), NRES(R0)), RESC1, "ZF", }, +/* XXX - investigate */ { SCONV, INBREG | FEATURE_FPA, SCREG, TFLOAT, SBREG, TULONGLONG|TLONGLONG, @@ -344,6 +336,7 @@ struct optab table[] = { NBREG, RESC1, COM "unimplemented\n", }, +/* XXX - investigate */ { SCONV, INBREG, SAREG, TFLOAT, SBREG, TULONGLONG|TLONGLONG, @@ -374,6 +367,7 @@ struct optab table[] = { NEEDS(NREG(A, 1), NLEFT(R16), NRES(R0)), RESC1, "ZF", }, +/* XXX - investiagte */ { SCONV, INBREG | FEATURE_FPA, SCREG, TDOUBLE|TLDOUBLE, SBREG, TLONGLONG|TULONGLONG, @@ -416,6 +410,7 @@ struct optab table[] = { NEEDS(NREG(A, 1), NLEFT(R0), NRES(R0)), RESC1, "ZF", }, +/* XXX - investigate */ { SCONV, INCREG | FEATURE_FPA, SBREG, TULONGLONG|TLONGLONG, SCREG, TFLOAT, @@ -458,6 +453,7 @@ struct optab table[] = { NEEDS(NREG(B, 1), NLEFT(R0), NRES(R16)), RESC1, "ZF", }, +/* XXX - investigate */ { SCONV, INCREG | FEATURE_FPA, SBREG, TLONGLONG|TULONGLONG, SCREG, TDOUBLE, @@ -500,6 +496,7 @@ struct optab table[] = { NEEDS(NREG(B, 1), NLEFT(R0), NRES(R16)), RESC1, "ZF", }, +/* XXX - investigate */ { SCONV, INCREG | FEATURE_FPA, SBREG, TLONGLONG|TULONGLONG, SCREG, TLDOUBLE, @@ -591,16 +588,16 @@ 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, @@ -633,15 +630,15 @@ struct optab table[] = { { 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, SCON|SNAME, TANY, @@ -685,21 +682,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,27 +729,27 @@ 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, @@ -825,27 +807,27 @@ struct optab table[] = { "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, @@ -910,112 +892,120 @@ 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", }, +/* XXX - investigate */ { ASSIGN, FOREFF|INCREG | FEATURE_FPA, SOREG|SNAME, TFLOAT, SCREG, TFLOAT, @@ -1028,12 +1018,14 @@ struct optab table[] = { 0, RDEST, COM "unimplemented\n", }, +/* XXX - investigate */ { ASSIGN, FOREFF|INAREG, SOREG|SNAME, TFLOAT, SAREG, TFLOAT, 0, RDEST, " str AR,AL" COM "assign float (soft-float)\n", }, +/* XXX - investigate */ { ASSIGN, FOREFF|INCREG | FEATURE_FPA, SOREG|SNAME, TDOUBLE, SCREG, TDOUBLE, @@ -1046,6 +1038,7 @@ struct optab table[] = { 0, RDEST, COM "unimplemented\n", }, +/* XXX - investigate */ { ASSIGN, FOREFF|INBREG, SOREG|SNAME, TDOUBLE, SBREG, TDOUBLE, @@ -1053,6 +1046,7 @@ struct optab table[] = { " str AR,AL" COM "assign double (soft-float)\n" " str UR,UL\n", }, +/* XXX - investigate */ { ASSIGN, FOREFF|INCREG | FEATURE_FPA, SOREG|SNAME, TLDOUBLE, SCREG, TLDOUBLE, @@ -1065,6 +1059,7 @@ struct optab table[] = { 0, RDEST, COM "not implemented", }, +/* XXX - investigate */ { ASSIGN, FOREFF|INBREG, SOREG|SNAME, TLDOUBLE, SBREG, TLDOUBLE, @@ -1074,14 +1069,14 @@ struct optab table[] = { /* 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", }, @@ -1164,27 +1159,27 @@ 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, INAREG, + SAREG, TLONGLONG, + SAREG, TLONGLONG, + NAREG, RESC1, + " sdiv A1,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, TULONGLONG, + SAREG, TULONGLONG, + NAREG, RESC1, + " udiv A1,AL,AR" COM "long/longlong unsigned divide\n",}, { DIV, INCREG | FEATURE_FPA, @@ -1244,104 +1239,42 @@ struct optab table[] = { { 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", }, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + SAREG, TLONGLONG|TULONGLONG|TPOINT, + NAREG, RESC1, + " mul A1,AL,AR\n", }, { MUL, INCREG | FEATURE_FPA, SCREG, TFLOAT, @@ -1385,7 +1318,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,28 +1334,22 @@ 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, @@ -1494,15 +1421,15 @@ 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", }, @@ -1561,22 +1488,22 @@ struct optab table[] = { "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,70 +1534,110 @@ 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", }, +/* XXX - investigate */ { OPLTYPE, INCREG | FEATURE_FPA, SANY, TANY, SOREG|SNAME, TFLOAT, @@ -1683,12 +1650,14 @@ struct optab table[] = { NCREG, RESC1, COM "not implemented\n", }, +/* XXX - investigate */ { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TFLOAT, NAREG, RESC1, " ldr A1,AL" COM "load float (soft-float)\n", }, +/* XXX - investigate */ { OPLTYPE, INCREG | FEATURE_FPA, SANY, TANY, SOREG|SNAME, TDOUBLE, @@ -1701,6 +1670,7 @@ struct optab table[] = { NCREG, RESC1, COM "not implemented\n" }, +/* XXX - investigate */ { OPLTYPE, INBREG, SANY, TANY, SOREG|SNAME, TDOUBLE, @@ -1708,6 +1678,7 @@ struct optab table[] = { " ldr A1,AL" COM "load double (soft-float)\n" " ldr U1,UL\n", }, +/* XXX - investigate */ { OPLTYPE, INCREG | FEATURE_FPA, SANY, TANY, SOREG|SNAME, TLDOUBLE, @@ -1720,6 +1691,7 @@ struct optab table[] = { NCREG, RESC1, COM "not implemented\n", }, +/* XXX - investigate */ { OPLTYPE, INBREG, SANY, TANY, SOREG|SNAME, TLDOUBLE, @@ -1732,15 +1704,15 @@ struct optab table[] = { */ { 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, @@ -1803,10 +1775,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 +1786,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", }, From 6920108aebffa3ee65deeb2dda3891b7a7476113 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Mon, 16 Feb 2026 00:20:20 +0300 Subject: [PATCH 08/27] aarch64: Fix assembly directive type names for initializing LONGLONG and WORD. Signed-off-by: Hakan Candar --- arch/aarch64/code.c | 3 +++ arch/aarch64/local.c | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/aarch64/code.c b/arch/aarch64/code.c index ec0b3a74b..ec6d8667e 100644 --- a/arch/aarch64/code.c +++ b/arch/aarch64/code.c @@ -374,6 +374,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"; } /* diff --git a/arch/aarch64/local.c b/arch/aarch64/local.c index 70a47ed95..3d23292a9 100644 --- a/arch/aarch64/local.c +++ b/arch/aarch64/local.c @@ -407,9 +407,10 @@ ninval(CONSZ off, int fsz, NODE *p) t = p->n_type; if (t > BTMASK) - t = p->n_type = INT; /* pointer */ + t = p->n_type = LONGLONG; /* pointer */ - 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) { From 55243c3acb383dda126a0fb8b02e1f2bd56b462c Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Wed, 28 Jan 2026 00:42:27 +0300 Subject: [PATCH 09/27] aarch64: Convert OREGs found in ADD/SUB instrs to AREGs. The Aarch64 ISA does not have xN,xN,[xN,#p] style OREG additions. Signed-off-by: Hakan Candar --- arch/aarch64/order.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/aarch64/order.c b/arch/aarch64/order.c index 5e6f07d65..03d7443c4 100644 --- a/arch/aarch64/order.c +++ b/arch/aarch64/order.c @@ -52,6 +52,19 @@ 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); From c29a02d1c9bdad8c34f4b90b6ca7a8ac79cc09ee Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Thu, 29 Jan 2026 01:27:42 +0300 Subject: [PATCH 10/27] aarch64: Fix OREG conversion logic. Remove geninsn() calls in myormake() and move them to offstar(). Calling instruction gen. on myormake leads to unwanted behaviour, where the result register becomes undefined. No other backends call geninsn() in myormake(), so I assume this was a previous backend bug. Cap OREG immediate to +-256 bytes. AArch64 has a lot of instructions with different OREG limits, but the least common denominator is 256. Signed-off-by: Hakan Candar --- arch/aarch64/order.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/arch/aarch64/order.c b/arch/aarch64/order.c index 03d7443c4..fff388ba2 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); } /* @@ -68,7 +65,7 @@ offstar(NODE *p, int shape) 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: */ @@ -78,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; } } @@ -85,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) @@ -102,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; From 7597af70a6757e8f98e445978a87047a0c2f1957 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Mon, 16 Feb 2026 17:51:30 +0300 Subject: [PATCH 11/27] aarch64: Fix several patterns that block code generation. Turn ICONs that are of INT type in PTR PLUS operations into LONGLONG. Convert unnecessary ADDROF operations wrapped in an UMUL into a no-op. Signed-off-by: Hakan Candar --- arch/aarch64/local2.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/arch/aarch64/local2.c b/arch/aarch64/local2.c index ebdc5625c..956039090 100644 --- a/arch/aarch64/local2.c +++ b/arch/aarch64/local2.c @@ -1011,15 +1011,22 @@ myreader(struct interpass *ipole) 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; @@ -1035,12 +1042,20 @@ 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); + walkf(p, fixtree2, 0); } void From 3c11ada8a0b06fe7f719e198d7f740ad678da044 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Thu, 29 Jan 2026 23:22:01 +0300 Subject: [PATCH 12/27] aarch64: Introduce literal pools for immediates that do not fit into MOV instruction. Convert ICONs of such immediates into NAMEs, and print the literals into a pool at the beginning of the function. This logic is put into pass2 and not pass1 because the middleend generates new ICONs (i.e. due to TEMP conversions) which can not be detected during pass1. Signed-off-by: Hakan Candar --- arch/aarch64/local.c | 46 +++++----------- arch/aarch64/local2.c | 120 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 118 insertions(+), 48 deletions(-) diff --git a/arch/aarch64/local.c b/arch/aarch64/local.c index 3d23292a9..99864d73b 100644 --- a/arch/aarch64/local.c +++ b/arch/aarch64/local.c @@ -403,48 +403,30 @@ ninval(CONSZ off, int fsz, NODE *p) { struct symtab *q; TWORD t; - int i, j; + U_CONSZ uval; t = p->n_type; if (t > BTMASK) 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 || 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; } diff --git a/arch/aarch64/local2.c b/arch/aarch64/local2.c index 956039090..735316a2e 100644 --- a/arch/aarch64/local2.c +++ b/arch/aarch64/local2.c @@ -21,6 +21,7 @@ #include #include +#include "pass1.h" /* for astypnames, talign and defalign */ #include "pass2.h" #define SZFPSP 16 @@ -69,22 +70,55 @@ char *rnames[] = { 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); } /* @@ -198,7 +232,7 @@ prologue(struct interpass_prolog *ipp) printf("\tstp %s,%s,[%s,#%d]!\n", rnames[FP], rnames[LR], rnames[SP], -SZFPSP); printf("\tmov %s,%s\n", rnames[FP], rnames[SP]); - if (trepresent(addto)) { + if (t12represent(addto)) { printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], addto); } else { nc = encode_constant(addto, vals); @@ -220,7 +254,7 @@ eoftn(struct interpass_prolog *ipp) if (ftype == STRTY || ftype == UNIONTY) { assert(0); } else { - if (trepresent(addStack)) { + if (t12represent(addStack)) { printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], addStack); } else { nc = encode_constant(addStack, vals); @@ -380,7 +414,7 @@ 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 { @@ -787,7 +821,7 @@ adrput(FILE *io, NODE *p) if (getlval(p) != 0) fprintf(io, "+%lld", getlval(p)); } else - fprintf(io, "#" CONFMT, getlval(p)); + fprintf(io, LABFMT, (int)getlval(p)); return; case OREG: @@ -992,11 +1026,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) @@ -1055,12 +1084,71 @@ fixtree2(NODE *p, void *arg) void mycanon(NODE *p) { - walkf(p, fixtree2, 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); } /* From de54a7ca839272447e3208d3ceaebad7fa8f2f25 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Thu, 22 Jan 2026 22:06:13 +0300 Subject: [PATCH 13/27] aarch64: Fix floating point extension. Implement FP SIMD instructions. Remove 32-bit ARMv7 assumptions. Signed-off-by: Hakan Candar --- arch/aarch64/local.c | 8 + arch/aarch64/local2.c | 17 +- arch/aarch64/macdefs.h | 8 +- arch/aarch64/table.c | 788 +++++++++++------------------------------ 4 files changed, 226 insertions(+), 595 deletions(-) diff --git a/arch/aarch64/local.c b/arch/aarch64/local.c index 99864d73b..38b21ea19 100644 --- a/arch/aarch64/local.c +++ b/arch/aarch64/local.c @@ -273,6 +273,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: diff --git a/arch/aarch64/local2.c b/arch/aarch64/local2.c index 735316a2e..da502808c 100644 --- a/arch/aarch64/local2.c +++ b/arch/aarch64/local2.c @@ -1157,7 +1157,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)) { @@ -1210,6 +1210,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: @@ -1282,9 +1283,9 @@ special(NODE *p, int shape) * default to ARMv2 */ #ifdef TARGET_BIG_ENDIAN -#define DEFAULT_FEATURES FEATURE_BIGENDIAN | FEATURE_EXTEND +#define DEFAULT_FEATURES FEATURE_BIGENDIAN | FEATURE_EXTEND | FEATURE_FPSIMD #else -#define DEFAULT_FEATURES FEATURE_EXTEND +#define DEFAULT_FEATURES FEATURE_EXTEND | FEATURE_FPSIMD #endif static int fset = DEFAULT_FEATURES; @@ -1295,8 +1296,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 14f34ba22..f49c6295a 100644 --- a/arch/aarch64/macdefs.h +++ b/arch/aarch64/macdefs.h @@ -288,12 +288,8 @@ int features(int f); #define FEATURE_BIGENDIAN 0x00010000 #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 diff --git a/arch/aarch64/table.c b/arch/aarch64/table.c index ecf370000..77944db39 100644 --- a/arch/aarch64/table.c +++ b/arch/aarch64/table.c @@ -299,273 +299,111 @@ struct optab table[] = { XSL(A), RESC1, " ldrh A1,AL" COM "convert ushort to int/long\n", }, -{ SCONV, INAREG | FEATURE_FPA, +{ SCONV, INAREG | FEATURE_FPSIMD, SCREG, TFLOAT, - SAREG, TWORD, - NAREG, RESC1, - " fix AL,AR" COM "convert float to int\n", }, - -{ SCONV, INAREG | FEATURE_VFP, - 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", }, -/* XXX - investigate */ -{ 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", }, - -/* XXX - investigate */ -{ 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, + SAREG, TUWORD|TULONGLONG, NAREG, RESC1, - " ftosid AL,AR" COM "convert double/ldouble to int\n", }, - -{ SCONV, INAREG | FEATURE_VFP, - SCREG, TDOUBLE|TLDOUBLE, - SAREG, TUWORD, - 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", }, -/* XXX - investiagte */ -{ 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, - SCREG, TFLOAT, - NCREG, RESC1, - " flts AL,AR" COM "convert int to float\n" }, - -{ SCONV, INCREG | FEATURE_VFP, - SAREG, TSWORD, +{ SCONV, INCREG | FEATURE_FPSIMD, + SAREG, TSWORD|TLONGLONG, SCREG, TFLOAT, NCREG, RESC1, - " fsitos AL,AR" COM "convert int to float\n" }, + " scvtf A1,AL" COM "convert int/long to float\n" }, -{ SCONV, INCREG | FEATURE_VFP, - SAREG, TUWORD, +{ SCONV, INCREG | FEATURE_FPSIMD, + SAREG, TUWORD|TULONGLONG, 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", }, -/* XXX - investigate */ -{ 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", }, - -/* XXX - investigate */ -{ 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", }, - -/* XXX - investigate */ -{ 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", }, @@ -600,18 +438,20 @@ struct optab table[] = { " 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, @@ -621,11 +461,11 @@ 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, @@ -640,17 +480,17 @@ struct optab table[] = { 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, @@ -752,17 +592,11 @@ struct optab table[] = { 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, @@ -770,40 +604,16 @@ 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, @@ -830,17 +640,11 @@ struct optab table[] = { XSL(A), RESC1, " subs A1,AL,AR" COM "64-bit subtraction\n", }, -{ MINUS, INCREG | FEATURE_FPA, - SCREG, TFLOAT, - SCREG, TFLOAT, - NCREG, RESC1, - " sufs A1,AL,AR" COM "float subtraction\n", }, - -{ MINUS, INCREG | FEATURE_VFP, +{ MINUS, INCREG | FEATURE_FPSIMD, 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, @@ -848,40 +652,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", }, /* @@ -1005,67 +785,57 @@ struct optab table[] = { "ZA" " strh AR, [ZXA1]" COM "assign (u)short global\n", }, -/* XXX - investigate */ -{ 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", }, -/* XXX - investigate */ { ASSIGN, FOREFF|INAREG, - SOREG|SNAME, TFLOAT, + SOREG, TFLOAT, SAREG, TFLOAT, 0, RDEST, " str AR,AL" COM "assign float (soft-float)\n", }, -/* XXX - investigate */ -{ 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", }, -/* XXX - investigate */ -{ 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", }, -/* XXX - investigate */ -{ 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", }, -/* XXX - investigate */ -{ 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, @@ -1080,17 +850,11 @@ struct optab table[] = { 0, RDEST, " mov AL,AR" COM "assign AR to AL\n", }, -{ ASSIGN, FOREFF|INCREG | FEATURE_FPA, +{ ASSIGN, FOREFF|INCREG | FEATURE_FPSIMD, SCREG, TFLOAT, SCREG, TFLOAT, 0, RDEST, - " mvf AL,AR" COM "assign float reg to float reg\n", }, - -{ ASSIGN, FOREFF|INCREG | FEATURE_VFP, - 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, @@ -1098,24 +862,17 @@ struct optab table[] = { 0, RDEST, " mov AL,AR" COM "assign float reg to float reg\n", }, -{ ASSIGN, FOREFF|INCREG | FEATURE_FPA, - SCREG, TDOUBLE|TLDOUBLE, - SCREG, TDOUBLE|TLDOUBLE, - 0, RDEST, - " mvf AL,AR" COM "assign float reg to float reg\n", }, - -{ ASSIGN, FOREFF|INCREG | FEATURE_VFP, +{ ASSIGN, FOREFF|INCREG | FEATURE_FPSIMD, 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, @@ -1182,17 +939,11 @@ struct optab table[] = { " udiv A1,AL,AR" COM "long/longlong unsigned divide\n",}, -{ DIV, INCREG | FEATURE_FPA, +{ DIV, INCREG | FEATURE_FPSIMD, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, - " dvfs A1,AL,AL" COM "fast (float) divide\n", }, - -{ DIV, INCREG | FEATURE_VFP, - 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, @@ -1200,40 +951,16 @@ 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, @@ -1276,17 +1003,11 @@ struct optab table[] = { NAREG, RESC1, " mul A1,AL,AR\n", }, -{ MUL, INCREG | FEATURE_FPA, - SCREG, TFLOAT, - SCREG, TFLOAT, - NCREG, RESC1, - " fmls A1,AL,AL" COM "fast (float) multiply\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, @@ -1294,22 +1015,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", }, /* @@ -1352,17 +1067,11 @@ struct optab table[] = { 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, @@ -1370,44 +1079,17 @@ struct optab table[] = { NAREG, RESC1, " ldr A1,AL" COM "float load\n", }, -{ UMUL, INCREG | FEATURE_FPA, - SANY, TANY, - SOREG|SNAME, TDOUBLE, - NCREG, RESC1, - " ldfd A1,AL" COM "double load\n", }, - -{ UMUL, INCREG | FEATURE_VFP, +{ UMUL, INCREG | FEATURE_FPSIMD, SANY, TANY, - SOREG|SNAME, TDOUBLE, + SOREG|SNAME, TDOUBLE|TLDOUBLE, NCREG, RESC1, - COM "not implemented\n", }, + " ldr A1,AL" COM "(l)double load\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 */ @@ -1433,17 +1115,11 @@ struct optab table[] = { 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, @@ -1451,40 +1127,16 @@ 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 */ @@ -1637,67 +1289,63 @@ struct optab table[] = { NAREG, RESC1, " mov A1,AL" COM "load AL into A1\n", }, -/* XXX - investigate */ -{ 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", }, -/* XXX - investigate */ { OPLTYPE, INAREG, SANY, TANY, - SOREG|SNAME, TFLOAT, + SOREG, TFLOAT, NAREG, RESC1, " ldr A1,AL" COM "load float (soft-float)\n", }, -/* XXX - investigate */ -{ 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", }, -/* XXX - investigate */ -{ 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", }, -/* XXX - investigate */ -{ 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", }, - -/* XXX - investigate */ -{ 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. @@ -1715,17 +1363,11 @@ struct optab table[] = { XSL(A), RESC1, " neg A1,AL" COM "64-bit negation\n", }, -{ UMINUS, INCREG | FEATURE_FPA, - SCREG, TFLOAT, - SCREG, TFLOAT, - NCREG, RESC1, - " mvfs A1,AL" COM "float negation\n", }, - -{ UMINUS, INCREG | FEATURE_VFP, +{ UMINUS, INCREG | FEATURE_FPSIMD, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, - " negs A1,AL" COM "float negation\n", }, + " fneg A1,AL" COM "float negation\n", }, { UMINUS, INAREG, SAREG, TFLOAT, @@ -1733,40 +1375,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, From 6eda5c55a6a62fdeee3e11d27fc9f9aa88ddd4dc Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Tue, 3 Feb 2026 19:27:17 +0300 Subject: [PATCH 14/27] aarch64: Save permanent registers on the stack. Signed-off-by: Hakan Candar --- arch/aarch64/local2.c | 129 +++++++++++++++++++++++++++++------------- 1 file changed, 91 insertions(+), 38 deletions(-) diff --git a/arch/aarch64/local2.c b/arch/aarch64/local2.c index da502808c..997f17275 100644 --- a/arch/aarch64/local2.c +++ b/arch/aarch64/local2.c @@ -29,7 +29,6 @@ extern void defalign(int); static int isShrink=0; -static int addStack=0; static int isExtend=0; #define exname(x) x @@ -167,40 +166,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. */ - addto += p1maxstacksize; + 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) @@ -218,34 +274,27 @@ prologue(struct interpass_prolog *ipp) ftype = ipp->ipp_type; printf("%s:\n", exname(ipp->ipp_name)); - addto = offcalc(ipp); - -#define BALSTACK (ALSTACK/SZCHAR) - if (addto < BALSTACK) { - addto = BALSTACK; - } - if (addto % BALSTACK) { - addto = addto + (BALSTACK - (addto % BALSTACK)); - } -#undef BALSTACK - addStack = addto; + 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 (t12represent(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]); - } + + 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 vals[4], nc, i; + int i, pi; if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ @@ -254,17 +303,21 @@ eoftn(struct interpass_prolog *ipp) if (ftype == STRTY || ftype == UNIONTY) { assert(0); } else { - if (t12represent(addStack)) { - printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], addStack); - } else { - nc = encode_constant(addStack, vals); - for (i = 0; i < nc; i++) - printf("\tadd %s,%s,#%d\n", - rnames[SP], rnames[SP], vals[i]); + 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), From 38063487199dfc164de95b660bdb047525430718 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Tue, 3 Feb 2026 20:28:39 +0300 Subject: [PATCH 15/27] aarch64: Remove inappropriate SCONV elision. The previous optimization removed integer SCONV nodes solely based on equal tsize(), which is wrong for same-width signedness conversions (e.g., char -> unsigned char) and caused miscompiles under -O1/-xtemps. Restrict the "free conversion" elision to (u)longlong <-> (u)longlong only. Signed-off-by: Hakan Candar --- arch/aarch64/local.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/arch/aarch64/local.c b/arch/aarch64/local.c index 38b21ea19..b65e3049b 100644 --- a/arch/aarch64/local.c +++ b/arch/aarch64/local.c @@ -65,7 +65,7 @@ clocal(NODE *p) struct symtab *q; NODE *l, *r, *t; int o; - int ty; + int ty, tyl; int tmpnr, isptrvoid = 0; char *n; @@ -198,17 +198,20 @@ 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; } } From 157ac19a0d63b15d04799ba5178cf9308e0f7627 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Wed, 4 Feb 2026 20:34:29 +0300 Subject: [PATCH 16/27] aarch64: Implement GOT/extern handling. Prefix extern symbols with '@'. Expand to GOT load in pass2 via local2.c. Signed-off-by: Hakan Candar --- arch/aarch64/local.c | 51 ++++++++++++++++++++++++++++++++++++++++++ arch/aarch64/local2.c | 7 ++++-- arch/aarch64/macdefs.h | 5 +++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/arch/aarch64/local.c b/arch/aarch64/local.c index b65e3049b..6399d1160 100644 --- a/arch/aarch64/local.c +++ b/arch/aarch64/local.c @@ -55,6 +55,50 @@ getsoname(struct symtab *sp) ap->sarg(0) : sp->sname; } +#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 * an expression tree before being sent to the backend. @@ -156,6 +200,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); diff --git a/arch/aarch64/local2.c b/arch/aarch64/local2.c index 997f17275..fb9ec1fc5 100644 --- a/arch/aarch64/local2.c +++ b/arch/aarch64/local2.c @@ -668,7 +668,7 @@ addrload(NODE *p) if (l->n_op == NAME) { if (kflag) { /* PIC load */ - if (1 /* normal */) { + 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"); @@ -869,8 +869,11 @@ 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 diff --git a/arch/aarch64/macdefs.h b/arch/aarch64/macdefs.h index f49c6295a..a8760483f 100644 --- a/arch/aarch64/macdefs.h +++ b/arch/aarch64/macdefs.h @@ -286,6 +286,11 @@ 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_EXTEND 0x00040000 /* sxth, sxtb, uxth, uxtb */ #define FEATURE_FPSIMD 0x10000000 From 21062544e26b896e3541a6169aa5a2338742d5ce Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Thu, 12 Feb 2026 01:17:17 +0300 Subject: [PATCH 17/27] aarch64: Prefix Mach-O symbols with underscore. Signed-off-by: Hakan Candar --- arch/aarch64/local.c | 19 +++++++++++++++++++ arch/aarch64/local2.c | 4 +++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/aarch64/local.c b/arch/aarch64/local.c index 6399d1160..480bf762d 100644 --- a/arch/aarch64/local.c +++ b/arch/aarch64/local.c @@ -498,7 +498,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 && iipp_type; - printf("%s:\n", exname(ipp->ipp_name)); + printf("%s:\n", ipp->ipp_name); offcalc(ipp, fframe); From 54e4343472ce001d93cc6c9c7db140472edf1b24 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Mon, 24 Nov 2025 22:13:37 +0300 Subject: [PATCH 18/27] aarch64: Implement vararg passing for Mach-O ABI. Signed-off-by: Hakan Candar --- arch/aarch64/code.c | 27 +++++++++++++++++++-------- cc/ccom/params.c | 27 +++++++++++++++++++++++++++ cc/ccom/pass1.h | 1 + cc/cxxcom/pass1.h | 1 + cc/cxxcom/pftn.c | 27 +++++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 8 deletions(-) diff --git a/arch/aarch64/code.c b/arch/aarch64/code.c index ec6d8667e..3c003d3ea 100644 --- a/arch/aarch64/code.c +++ b/arch/aarch64/code.c @@ -20,6 +20,7 @@ */ #include +#include #include "pass1.h" @@ -617,14 +618,13 @@ movearg_struct(NODE *p, int *regp, int *stackofsp) return q; } - static NODE * -moveargs(NODE *p, int *regp, int *fregp, int *stackofsp) +moveargs(NODE *p, int vararg, int *idxp, int *regp, int *fregp, int *stackofsp) { NODE *r, **rp; if (p->n_op == CM) { - p->n_left = moveargs(p->n_left, regp, fregp, stackofsp); + p->n_left = moveargs(p->n_left, vararg, idxp, regp, fregp, stackofsp); r = p->n_right; rp = &p->n_right; } else { @@ -636,9 +636,11 @@ moveargs(NODE *p, int *regp, int *fregp, int *stackofsp) && (r->n_type == DOUBLE || r->n_type == LDOUBLE || r->n_type == FLOAT); - if (r->n_op == STARG) { + if (r->n_op == STARG) { *rp = movearg_struct(r, regp, stackofsp); - } else if ((isfp && *fregp >= NARGREGS) || (!isfp && *regp >= NARGREGS)) { + } 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); @@ -656,6 +658,7 @@ moveargs(NODE *p, int *regp, int *fregp, int *stackofsp) *rp = movearg_32bit(r, regp); } + (*idxp)++; return straighten(p); } @@ -720,15 +723,23 @@ builtin_cfa(const struct bitable *bt, NODE *a) NODE * funcode(NODE *p) { - int reg, freg, stackofs; - reg = freg = stackofs = 0; + int idx, reg, freg, stackofs; + idx = reg = freg = stackofs = 0; + int vararg = INT_MAX; if (p->n_type == STRTY+FTN || p->n_type == UNIONTY+FTN) { p = retstruct(p); reg = R1; } - p->n_right = moveargs(p->n_right, ®, &freg, &stackofs); +#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 + + p->n_right = moveargs(p->n_right, vararg, &idx, ®, &freg, &stackofs); if (p->n_right == NULL) p->n_op += (UCALL - CALL); 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..2f2184449 100644 --- a/cc/ccom/pass1.h +++ b/cc/ccom/pass1.h @@ -485,6 +485,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; +} From b5fef330d32c25324d234bcab91289c1ddf11a55 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Mon, 19 Jan 2026 21:29:48 +0300 Subject: [PATCH 19/27] aarch64: Fix section naming for Mach-O. Signed-off-by: Hakan Candar --- arch/aarch64/code.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/aarch64/code.c b/arch/aarch64/code.c index 3c003d3ea..65bf9e497 100644 --- a/arch/aarch64/code.c +++ b/arch/aarch64/code.c @@ -58,15 +58,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; From 3206b04232b2652f22a13adb1768285097d29844 Mon Sep 17 00:00:00 2001 From: hakanrw Date: Wed, 4 Feb 2026 23:15:36 +0100 Subject: [PATCH 20/27] common: Implement IEEE-754 binary128 softfloat handler. Signed-off-by: hakanrw --- common/softfloat.c | 160 +++++++++++++++++++++++++++++++++++++++++++-- common/softfloat.h | 14 ++++ 2 files changed, 169 insertions(+), 5 deletions(-) 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 From 41b5bd958d7bc344ac96f31de6f799a75286c493 Mon Sep 17 00:00:00 2001 From: hakanrw Date: Wed, 4 Feb 2026 23:18:17 +0100 Subject: [PATCH 21/27] aarch64: Define basic LDOUBLE configuration for AAPCS64 and Darwin ABI. Signed-off-by: hakanrw --- arch/aarch64/macdefs.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/aarch64/macdefs.h b/arch/aarch64/macdefs.h index a8760483f..216c54537 100644 --- a/arch/aarch64/macdefs.h +++ b/arch/aarch64/macdefs.h @@ -32,7 +32,11 @@ #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 @@ -46,7 +50,11 @@ #define ALINT 32 #define ALFLOAT 32 #define ALDOUBLE 64 +#ifndef MACHOABI +#define ALLDOUBLE 128 +#else #define ALLDOUBLE 64 +#endif #define ALLONG 64 #define ALLONGLONG 64 #define ALSHORT 16 @@ -318,5 +326,11 @@ NODE *arm_builtin_va_copy(const struct bitable *bt, NODE *a); #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 From f3924ae62d512bee9cb4349a7771e8ffb0acb765 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Sat, 7 Feb 2026 22:59:21 +0300 Subject: [PATCH 22/27] aarch64: Implement AAPCS64 calling convention for structs. Signed-off-by: Hakan Candar --- arch/aarch64/code.c | 420 ++++++++++++++++++++++++++++++------------ arch/aarch64/local.c | 78 +++++--- arch/aarch64/local2.c | 4 +- arch/aarch64/order.c | 2 +- cc/ccom/pass1.h | 1 + 5 files changed, 362 insertions(+), 143 deletions(-) diff --git a/arch/aarch64/code.c b/arch/aarch64/code.c index 65bf9e497..5e6850876 100644 --- a/arch/aarch64/code.c +++ b/arch/aarch64/code.c @@ -32,6 +32,7 @@ #define talloc p1alloc #define tcopy p1tcopy #define nfree p1nfree +#define attr ssdesc #undef n_type #define n_type ptype #undef n_qual @@ -104,6 +105,36 @@ 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 attr *ss) +{ + struct symtab s; + NODE *n; + + s.stype = t; + s.squal = 0; + s.sdf = df; + s.sap = 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 */ @@ -205,7 +236,7 @@ param_retstruct(void) p = tempnode(0, PTR-FTN+cftnsp->stype, 0, cftnsp->sap); rvnr = regno(p); q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); - regno(q) = R0; + regno(q) = R8; p = buildtree(ASSIGN, p, q); ecomp(p); } @@ -215,33 +246,101 @@ param_retstruct(void) * push the registers out to memory * used by bfcode() */ static void -param_struct(struct symtab *sym, int *regp, int *stackofsp) +param_struct(struct symtab *sym, int *regp, int *fregp, int *stackofsp) { - /* XXX - investigate, is stack correct? */ - int argofs = *regp; - 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->sap); + 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->sap); + 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->sap); + regno(q) = FPREG; + q = block(PLUS, q, bcon(ARGINIT/SZCHAR + *stackofsp), INCREF(PTR+STRTY), 0, sym->sap); + *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->sap); + 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; + } } - *regp = argofs; + *regp = reg; } @@ -276,7 +375,6 @@ bfcode(struct symtab **sp, int cnt) /* if returning a structure, move the hidden argument into a TEMP */ if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { param_retstruct(); - ++reg; } /* recalculate the arg offset and create TEMP moves */ @@ -286,7 +384,7 @@ bfcode(struct symtab **sp, int cnt) continue; if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) { - param_struct(sp[i], ®, &stackofs); + param_struct(sp[i], ®, &freg, &stackofs); } else if (DEUNSIGN(sp[i]->stype) == LONGLONG || DEUNSIGN(sp[i]->stype) == LONG) { param_64bit(sp[i], ®, &stackofs, xtemps && !saveallargs); } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) { @@ -327,17 +425,19 @@ 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->sap); + 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 */ @@ -350,15 +450,42 @@ efcode(void) /* get the address from the tempnode */ q = tempnode(tempnr, PTR+STRTY, 0, cftnsp->sap); - q = buildtree(UMUL, q, NIL); - /* 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->sap); + 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); + } + } } /* @@ -559,64 +686,98 @@ movearg_float(NODE *p, int *regp) /* setup call stack with a structure */ /* called from moveargs() */ static NODE * -movearg_struct(NODE *p, int *regp, int *stackofsp) +movearg_struct(NODE *p, int *regp, int *fregp, int *stackofsp) { - /* XXX - investigate */ 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, stackofsp); - 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; } @@ -640,7 +801,7 @@ moveargs(NODE *p, int vararg, int *idxp, int *regp, int *fregp, int *stackofsp) || r->n_type == FLOAT); if (r->n_op == STARG) { - *rp = movearg_struct(r, regp, stackofsp); + *rp = movearg_struct(r, regp, fregp, stackofsp); } else if ((*idxp >= vararg) || (isfp && *fregp >= NARGREGS) || (!isfp && *regp >= NARGREGS)) { @@ -665,39 +826,6 @@ moveargs(NODE *p, int vararg, int *idxp, int *regp, int *fregp, int *stackofsp) 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) { @@ -719,6 +847,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. @@ -726,15 +912,10 @@ builtin_cfa(const struct bitable *bt, NODE *a) NODE * funcode(NODE *p) { - int idx, reg, freg, stackofs; - idx = reg = freg = stackofs = 0; + int reg, freg, stackofs, idx; + reg = freg = stackofs = idx = 0; int vararg = INT_MAX; - if (p->n_type == STRTY+FTN || p->n_type == UNIONTY+FTN) { - p = retstruct(p); - reg = R1; - } - #if defined(MACHOABI) if (p->n_left->n_df) vararg = pr_ellidx(p->n_left->n_df->dlst); @@ -744,6 +925,11 @@ funcode(NODE *p) p->n_right = moveargs(p->n_right, vararg, &idx, ®, &freg, &stackofs); + /* 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); diff --git a/arch/aarch64/local.c b/arch/aarch64/local.c index 480bf762d..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" @@ -46,6 +45,7 @@ #endif extern void defalign(int); +static NODE * stret(NODE *p); static char * getsoname(struct symtab *sp) @@ -110,7 +110,6 @@ clocal(NODE *p) NODE *l, *r, *t; int o; int ty, tyl; - int tmpnr, isptrvoid = 0; char *n; /* @@ -155,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: @@ -368,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. */ diff --git a/arch/aarch64/local2.c b/arch/aarch64/local2.c index d717da81c..c038a9c97 100644 --- a/arch/aarch64/local2.c +++ b/arch/aarch64/local2.c @@ -460,7 +460,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); @@ -473,7 +473,7 @@ stasg(NODE *p) 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)]); } diff --git a/arch/aarch64/order.c b/arch/aarch64/order.c index fff388ba2..165e1b225 100644 --- a/arch/aarch64/order.c +++ b/arch/aarch64/order.c @@ -307,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/cc/ccom/pass1.h b/cc/ccom/pass1.h index 2f2184449..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 From 85769ba5579af68d0a6dfb04b0a0dd0fd20c4681 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Sun, 15 Feb 2026 17:57:55 +0300 Subject: [PATCH 23/27] aarch64: Fix issue in strcvt(). Add condition which prevents char arrays from segfaulting the compiler. The previous solution now applies to both arm and aarch64 backends. Signed-off-by: Hakan Candar --- cc/ccom/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cc/ccom/init.c b/cc/ccom/init.c index a08d6f10c..67aa4d6ad 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; From aa2bea0bf0e45879da885e007e3ad2f5c20ccc12 Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Sun, 15 Feb 2026 23:58:20 +0300 Subject: [PATCH 24/27] ccom: Fix structure assignment ICE in simpleinit(). When buildtree(ASSIGN, strtype, strtype) is called, it generates a STASG operation wrapped in an UMUL operation. Due to this, the righthand side of the returned node is NULL. This part of the code had not accounted for this case, which resulted in a segfault. Check whether the node returned from the ASSIGN build is UMUL, and if so, discard the parent node. Signed-off-by: Hakan Candar --- cc/ccom/init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cc/ccom/init.c b/cc/ccom/init.c index 67aa4d6ad..a4e9ce439 100644 --- a/cc/ccom/init.c +++ b/cc/ccom/init.c @@ -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); From 2ee34d6d21d5c66f6288e85d39b1e578a100e98d Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Mon, 16 Feb 2026 18:54:08 +0300 Subject: [PATCH 25/27] ccom: Preserve correct type when folding UMUL & ADDROF combination. During the ADDROF elimination optimization, the resulting node type was not preserved when rewriting the tree. This could cause loads to be interpreted as STRUCT loads instead of scalar loads. The issue appears when accessing the first field of a struct in the first element of a struct array, where UMUL and ADDROF transformations may alter the node type. When collapsing the ADDROF expression, the replacement node must inherit the type of the UMUL result. Fix by explicitly propagating the type from the parent node to the replacement node before freeing the intermediate nodes. An example of the previous misoptimization: U*, int +, PTR int U&, PTR strty NAME _arr, strty ICON, 0, 0x0, longlong => NAME _arr, strty, REG x0 , SU= 0(@REG,,,,) This commit fixes the above misoptimization. Signed-off-by: Hakan Candar --- cc/ccom/optim.c | 8 ++++++++ 1 file changed, 8 insertions(+) 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; From 97a7355f6b27d1e4ae7f5b8c5821621d1443bd41 Mon Sep 17 00:00:00 2001 From: hakanrw Date: Sat, 21 Feb 2026 14:06:03 +0100 Subject: [PATCH 26/27] aarch64: Fix sym->sss getting obstructed by macro for LANG_C. In code.c, the field sym->sap was getting rewritten to sym->sss, which prevented setting sym->sap to NULL. This would in turn cause a segfault in certain scenarios. Refactor code.c, remove sap expansion from LANG_C, instead expand sss from LANG_CXX. Rename sap access to sss to match intended behavior. Signed-off-by: hakanrw --- arch/aarch64/code.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/arch/aarch64/code.c b/arch/aarch64/code.c index 5e6850876..bb70dc033 100644 --- a/arch/aarch64/code.c +++ b/arch/aarch64/code.c @@ -27,19 +27,19 @@ #ifdef LANG_CXX #define p1listf listf #define p1tfree tfree +#define sss sap +#define ssdesc attr #else #define NODE P1ND #define talloc p1alloc #define tcopy p1tcopy #define nfree p1nfree -#define attr ssdesc #undef n_type #define n_type ptype #undef n_qual #define n_qual pqual #undef n_df #define n_df pdf -#define sap sss #define n_ap pss #endif @@ -116,7 +116,7 @@ defloc(struct symtab *sp) * & cxxcom/trees.c as a generic routine. */ static NODE * -mkstknode(TWORD t, union dimfun *df, struct attr *ss) +mkstknode(TWORD t, union dimfun *df, struct ssdesc *ss) { struct symtab s; NODE *n; @@ -124,7 +124,8 @@ mkstknode(TWORD t, union dimfun *df, struct attr *ss) s.stype = t; s.squal = 0; s.sdf = df; - s.sap = ss; + s.sap = 0; + s.sss = ss; s.sclass = AUTO; s.soffset = NOOFFSET; s.sname = "mkstknode"; /* or else nametree() accesses invalid string */ @@ -143,7 +144,7 @@ putintemp(struct symtab *sym, NODE *q) { NODE *p; - p = tempnode(0, sym->stype, sym->sdf, sym->sap); + p = tempnode(0, sym->stype, sym->sdf, sym->sss); p = buildtree(ASSIGN, p, q); sym->soffset = regno(p->n_left); sym->sflags |= STNODE; @@ -165,7 +166,7 @@ param_64bit(struct symtab *sym, int *regp, int *stackofsp, int dotemps) putintemp(sym, q); } } else { - q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); + q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sss); regno(q) = R0 + (*regp)++; putintemp(sym, q); } @@ -203,7 +204,7 @@ param_double(struct symtab *sym, int *fregp, int *stackofsp, int dotemps) putintemp(sym, q); } } else { - q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); + q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sss); regno(q) = V0 + (*fregp)++; putintemp(sym, q); } @@ -233,9 +234,9 @@ 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); + q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sss); regno(q) = R8; p = buildtree(ASSIGN, p, q); ecomp(p); @@ -257,7 +258,7 @@ param_struct(struct symtab *sym, int *regp, int *fregp, int *stackofsp) navail = NARGREGS - reg; navail = navail < 0 ? 0 : navail; - sz = tsize(sym->stype, sym->sdf, sym->sap); + sz = tsize(sym->stype, sym->sdf, sym->sss); szb = sz / SZCHAR; num = (sz+SZLONGLONG-1) / SZLONGLONG; /* ceil(sz/8) */ @@ -280,7 +281,7 @@ param_struct(struct symtab *sym, int *regp, int *fregp, int *stackofsp) * dedicated IR lowering pass that rewrites references to use the hidden * pointer instead of forcing a memcpy. */ - s = cstknode(sym->stype, sym->sdf, sym->sap); + s = cstknode(sym->stype, sym->sdf, sym->sss); sym->soffset = AUTOINIT - autooff; if (navail == 0) { @@ -288,9 +289,9 @@ param_struct(struct symtab *sym, int *regp, int *fregp, int *stackofsp) * we have no free argument register left, read pointer * from stack. */ - q = block(REG, NIL, NIL, INCREF(PTR+STRTY), 0, sym->sap); + 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->sap); + q = block(PLUS, q, bcon(ARGINIT/SZCHAR + *stackofsp), INCREF(PTR+STRTY), 0, sym->sss); *stackofsp += SZLONGLONG; q = buildtree(UMUL, q, 0); @@ -303,7 +304,7 @@ param_struct(struct symtab *sym, int *regp, int *fregp, int *stackofsp) * we have at least one free argument register, read the * pointer from the available register. */ - q = block(REG, NIL, NIL, PTR+STRTY, 0, sym->sap); + q = block(REG, NIL, NIL, PTR+STRTY, 0, sym->sss); regno(q) = R0 + reg++; /* XXX - perform unnecessary copy */ @@ -431,7 +432,7 @@ efcode(void) if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; - sz = tsize(DECREF(cftnsp->stype), cftnsp->sdf, cftnsp->sap); + sz = tsize(DECREF(cftnsp->stype), cftnsp->sdf, cftnsp->sss); szb = sz / SZCHAR; num = (sz+SZLONGLONG-1) / SZLONGLONG; @@ -441,15 +442,15 @@ efcode(void) */ /* 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 = tempnode(tempnr, PTR+STRTY, 0, cftnsp->sss); if (szb > 16) { /* @@ -459,7 +460,7 @@ efcode(void) */ q = buildtree(UMUL, q, NIL); /* get the structure destination */ - p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->sap); + p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->sss); p = buildtree(UMUL, p, NIL); /* struct assignment */ From 0b5d859e580cbb8aa2e28bc37a2f8815ba661e9b Mon Sep 17 00:00:00 2001 From: Hakan Candar Date: Sun, 25 Jan 2026 03:21:43 +0300 Subject: [PATCH 27/27] aarch64: Add attribution. Signed-off-by: Hakan Candar --- arch/aarch64/code.c | 1 + arch/aarch64/local2.c | 1 + arch/aarch64/macdefs.h | 1 + arch/aarch64/table.c | 1 + 4 files changed, 4 insertions(+) diff --git a/arch/aarch64/code.c b/arch/aarch64/code.c index bb70dc033..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 diff --git a/arch/aarch64/local2.c b/arch/aarch64/local2.c index c038a9c97..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 diff --git a/arch/aarch64/macdefs.h b/arch/aarch64/macdefs.h index 216c54537..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 diff --git a/arch/aarch64/table.c b/arch/aarch64/table.c index 77944db39..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