From a8d6f8bf30c07edb775e56889f568ca20240bedf Mon Sep 17 00:00:00 2001 From: lemon Date: Tue, 17 Mar 2026 13:22:00 +0100 Subject: REFACTOR: move sources to src/ --- aarch64/aapcs.c | 77 ----- aarch64/all.h | 16 - aarch64/emit.c | 1023 ------------------------------------------------------- aarch64/isel.c | 515 ---------------------------- 4 files changed, 1631 deletions(-) delete mode 100644 aarch64/aapcs.c delete mode 100644 aarch64/all.h delete mode 100644 aarch64/emit.c delete mode 100644 aarch64/isel.c (limited to 'aarch64') diff --git a/aarch64/aapcs.c b/aarch64/aapcs.c deleted file mode 100644 index fc08da1..0000000 --- a/aarch64/aapcs.c +++ /dev/null @@ -1,77 +0,0 @@ -#include "all.h" - -static int -abiarg(short r[2], uchar cls[2], uchar *r2off, int *ni, int *nf, int *ns, union irtype typ) -{ - enum { NINT = 8, NFLT = 8 }; - if (!typ.isagg) { - if (kisflt(cls[0] = typ.cls) && *nf < 8) { - r[0] = V(0) + (*nf)++; - } else if (kisint(cls[0]) && *ni < NINT) { - r[0] = R0 + (*ni)++; - } else { - r[0] = *ns; - *ns += 8; - return 0; /* MEMORY */ - } - return 1; - } else assert(!"nyi"); -} - -static int -abiret(short r[2], uchar cls[2], uchar *r2off, int *ni, union irtype typ) -{ - if (!typ.isagg) { - r[0] = kisflt(cls[0] = typ.cls) ? V(0) : R0; - return 1; - } - int nf = 0, ns = 0; - int ret = abiarg(r, cls, r2off, ni, &nf, &ns, typ); - if (ret) return ret; - /* caller-allocated result address in x8 */ - assert(*ni == 0); - r[0] = -1; - r[1] = R(8); - return 0; -} - -static void -vastart(struct function *fn, struct block *blk, int *curi) -{ - assert(!"nyi"); -} - -static void -vaarg(struct function *fn, struct block *blk, int *curi) -{ - assert(!"nyi"); -} - -static const char aarch64_rnames[][6] = { - "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9","R10","R11","R12","R13","R14","R15", - "R16","R17","R18","R19","R20","R21","R22","R23","R24","R25","R26","R27","R28", "FP", "LR", "SP", - "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7", "V8", "V9","V10","V11","V12","V13","V14","V15", - "V16","V17","V18","V19","V20","V21","V22","V23","V24","V25","V26","V27","V28","V29","V30","V31", -}; - -const struct mctarg t_aarch64_aapcs = { - .gpr0 = R0, .ngpr = 31, - .bpr = FP, - .gprscratch = R(16), .fprscratch = V(31), - .fpr0 = V0, .nfpr = 32, - .rcallee = BIT(R(19)) | BIT(R(20)) | BIT(R(21)) | BIT(R(22)) | BIT(R(23)) - | BIT(R(24)) | BIT(R(25)) | BIT(R(26)) | BIT(R(27)) | BIT(R(28)) - | BIT( V(8)) | BIT( V(9)) | BIT(V(10)) | BIT(V(11)) | BIT(V(12)) - | BIT(V(13)) | BIT(V(14)) | BIT(V(15)), - .rglob = BIT(FP) | BIT(LR) | BIT(SP), - .rnames = aarch64_rnames, - .objkind = OBJELF, - .abiret = abiret, - .abiarg = abiarg, - .vastart = vastart, - .vaarg = vaarg, - .isel = aarch64_isel, - .emit = aarch64_emit, -}; - -/* vim:set ts=3 sw=3 expandtab: */ diff --git a/aarch64/all.h b/aarch64/all.h deleted file mode 100644 index 828909e..0000000 --- a/aarch64/all.h +++ /dev/null @@ -1,16 +0,0 @@ -#include "../ir/ir.h" - -enum reg { - R0 = 0, -#define R(n) (R0+n) - FP = R(29), LR = R(30), SP = R(31), - V0, -#define V(n) (V0+n) -}; - -bool aarch64_logimm(uint *enc, enum irclass, uvlong x); -void aarch64_isel(struct function *); -void aarch64_emit(struct function *); - -/* vim:set ts=3 sw=3 expandtab: */ - diff --git a/aarch64/emit.c b/aarch64/emit.c deleted file mode 100644 index 9fdcd83..0000000 --- a/aarch64/emit.c +++ /dev/null @@ -1,1023 +0,0 @@ -#include "all.h" -#include "../obj/obj.h" -#include "../endian.h" - -/* References: - * ARM ARM https://developer.arm.com/documentation/ddi0628/aa/?lang=en - * AAELF ABI https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst - */ - -enum operkind { ONONE, OREGZR, OREG, OIMM, OMEM, OSYM }; -enum shiftkind { SLSL, SLSR, SASR, SROR }; -enum addrmode { AIMMIDX, AREGIDX, APREIDX, APOSTIDX }; -enum addrregext { XUXTW = 2, XLSL = 3, XSXTW = 6, XSXTX = 7 }; -struct oper { - uchar t; - union { - struct { /* OREG (opt. shifted) */ - uchar reg; - uchar shft : 2, /* enum shiftkind */ - shamt : 6; - }; - struct { /* OMEM */ - uchar mode : 3; /* enum addrmode */ - uchar base : 5; /* reg */ - union { - struct { - uchar index : 5; /* reg */ - uchar ext : 3; /* enum addrregext */ - uchar shamt; - }; - short disp; - }; - } m; - vlong imm; uvlong uimm; /* OIMM */ - struct { /* OSYM */ - ushort con; - int cdisp; - }; - }; -}; - -#define REGZR ((struct oper){OREGZR, .reg=31}) -#define mkoper(t, ...) ((struct oper){(t), __VA_ARGS__}) -#define reg2oper(r) (assert((uint)(r) <= V(31)), mkoper(OREG, .reg = (r))) - -static struct oper -mkmemoper(uint msiz, union ref r) -{ - if (r.t == RTMP) { - assert(in_range(instrtab[r.i].reg-1, R0, SP)); - return mkoper(OMEM, .m = {AIMMIDX, .base = instrtab[r.i].reg-1}); - } else if (r.t == RREG) { - return mkoper(OMEM, .m = {AIMMIDX, .base = r.i}); - } else if (isaddrcon(r,1)) { - return mkoper(OSYM, .con = r.i,); - } else if (r.t == RADDR) { - const struct addr *addr = &addrtab.p[r.i]; - assert(addr->shift <= 3 && (!addr->disp || !addr->index.bits)); - if (isaddrcon(addr->base,0)) { - assert(!addr->index.bits); - return mkoper(OSYM, .con = addr->base.i, .cdisp = addr->disp); - } - assert(addr->base.t == RREG); - if (!addr->index.bits) { - return mkoper(OMEM, .m = {.mode = AIMMIDX, .base = addr->base.i, .disp = addr->disp}); - } else { - assert(addr->index.t == RREG); - assert(addr->shift == 0 || 1<shift == msiz); - return mkoper(OMEM, .m = { - .mode = AREGIDX, - .base = addr->base.i, - .index = addr->index.i, - .ext = XLSL, - .shamt = !!addr->shift, - }); - } - } - assert(!"nyi"); -} - -static struct oper -ref2oper(union ref r) -{ - switch (r.t) { - case RTMP: return instrtab[r.i].reg ? mkoper(ONONE,) : reg2oper(instrtab[r.i].reg-1); - case RREG: return reg2oper(r.i); - case RICON: return mkoper(OIMM, .imm = r.i); - case RXCON: - if (kisint(contab.p[r.i].cls)) - return mkoper(OIMM, .imm = contab.p[r.i].i); - else if (kisflt(contab.p[r.i].cls)) { - assert(contab.p[r.i].f == 0.0); - return mkoper(OIMM, .imm = 0); - } else if (!contab.p[r.i].cls) { - return mkoper(OSYM, .con = r.i); - } - assert(0); - case RADDR: return mkmemoper(0, r); - default: assert(0); - } -} - -enum operpat { - PNONE, - PGPRZ, /* R0-R30,ZR */ - PGPRSP, /* R0-R30,SP */ - PSP, /* SP */ - PGPRZSHFT, /* R0-30,ZR SFHT #n */ - PFPR, /* V0 - V31 */ - PZERO, /* zero immediate */ - PU6, /* 6-bit uimm */ - PU12SL12, /* 12 bit uimm, optionally left shifted by 12 */ - PU16SL16, /* 16 bit uimm, left shift by 0/16/32/48 */ - PLOGIMM, /* immediate for logical instrs */ - PMEMAIMM, /* addr 12bit immediate byte offset */ - PMEMAIMMH, /* addr 12bit immediate halfword offset (multiple of 2) */ - PMEMAIMMW, /* addr 12bit immediate word offset (multiple of 4) */ - PMEMAIMMX, /* addr 12bit immediate doubleword offset (multiple of 8) */ - PMEMPREPOST, /* addr signed 9bit immediate byte offset */ - PMEMAREG, /* addr reg offset, optionally left shifted */ - PSYM, /* symbol */ -}; -enum operenc { - EN_ADDSUBEXT3R, /* add/sub-ext-reg */ - EN_ADDSUBSHFT3R, /* add/sub-shift-reg */ - EN_LOGSHFT3R, /* logical/shifted-reg */ - EN_ARITH2R, /* data-processing/1src */ - EN_ARITH3R, /* data-processing/2src */ - EN_ADDSUBIMM, /* add/subtract-imm */ - EN_LOGIMM, /* logical-imm */ - EN_MOVEIMM, /* move/wide-imm */ - EN_MEMAIMM, /* load/store/unsigned-imm */ - EN_MEMAIMMH, /* load/store/unsigned-imm (halfword) */ - EN_MEMAIMMW, /* load/store/unsigned-imm (word) */ - EN_MEMAIMMX, /* load/store/unsigned-imm (doubleword) */ - EN_MEMAPREPOST, /* load/store/pre/postidx-imm */ - EN_MEMAREG, /* load/store/reg-offset */ - EN_MEMPPREPOST, /* load/store-pair/pre/postidx-imm */ - EN_ADRSYMLO21, /* for ADR */ - EN_ADRSYMPGHI21, /* for ADRP */ - EN_ADDSYMLO12, /* for ADD x,x, */ - EN_LDSYMLO19, /* for LDR (literal) */ - EN_FP2R, /* float 1src */ - EN_FP1GPR1, /* fpr + gpr */ - EN_FP3R, /* float 2src */ - EN_FPIMM, /* float-imm */ - EN_FPCMPZ, /* float cmp with zero */ - EN_FPCMP, /* float cmp-imm */ -}; -struct desc { - uchar psiz; /* subset of {4,8} */ - uchar pt[3]; /* bitsets of enum operpat, up to 3 operands */ - uint opc; - uchar operenc; /* enum operenc */ -}; - -/* match operand against pattern */ -static inline bool -opermatch(enum operpat pat, enum irclass k, struct oper o) -{ - switch (pat) { - case PNONE: return !o.t; - case PGPRZ: - return o.t == OREGZR || (o.t == OREG && in_range(o.reg, R0, R(30)) && !o.shamt); - case PGPRSP: - return o.t == OREG && in_range(o.reg, R0, R(31)) && !o.shamt; - case PGPRZSHFT: - return o.t == OREGZR || (o.t == OREG && in_range(o.reg, R0, R(30))); - case PSP: return o.t == OREG && o.reg == SP; - case PFPR: return o.t == OREG && in_range(o.reg, V0, V(31)); - case PZERO: return o.t == OIMM && o.imm == 0; - case PU6: return o.t == OIMM && (uint)o.imm < 63; - case PSYM: return o.t == OSYM; - case PU12SL12: - return o.t == OIMM && ((o.imm &~ 0xFFF) == 0 || (o.imm &~ 0xFFF000) == 0); - case PU16SL16: - return o.t == OIMM - && ((o.imm &~ 0xFFFF) == 0 || (o.imm &~ 0xFFFF0000) == 0 - || (o.imm &~ (0xFFFFull<<32)) == 0 || (o.imm &~ (0xFFFFull<<48)) == 0); - case PLOGIMM: return o.t == OIMM && aarch64_logimm(NULL, k, o.imm); - case PMEMAIMM: - return o.t == OMEM && o.m.mode == AIMMIDX && (uint)o.m.disp < (1<<12); - case PMEMAIMMH: - return o.t == OMEM && o.m.mode == AIMMIDX && (uint)o.m.disp < (1<<13) && !(o.m.disp % 2); - case PMEMAIMMW: - return o.t == OMEM && o.m.mode == AIMMIDX && (uint)o.m.disp < (1<<14) && !(o.m.disp % 4); - case PMEMAIMMX: - return o.t == OMEM && o.m.mode == AIMMIDX && (uint)o.m.disp < (1<<15) && !(o.m.disp % 8); - case PMEMAREG: - return o.t == OMEM && o.m.mode == AREGIDX; - case PMEMPREPOST: - return o.t == OMEM && (o.m.mode == APREIDX || o.m.mode == APOSTIDX - || (o.m.mode == AIMMIDX && o.m.disp >= -256 && o.m.disp < 256)); - } - assert(0); -} - -/* code output helpers */ -#define W32(w) (wr32targ(*pcode, (w)), *pcode += 4) - -static uchar *fnstart; -static internstr curfnsym; -static bool usefp; -static int rbpoff; - -/* Given an instruction description table, find the first entry that matches - * the operands and encode it. */ -static void -encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct oper o[3]) -{ - const struct desc *en = NULL; - for (int i = 0; i < ntab; ++i) { - if (!(tab[i].psiz & cls2siz[k])) continue; - for (int j = 0; j < 3; ++j) - if (!opermatch(tab[i].pt[j], k, o[j])) - goto Skip; - en = &tab[i]; - break; - Skip:; - } - assert(en && "no match for instr"); - - uint sf = cls2siz[k] >> 3; - uint ins = en->opc, sh, nimmrs; - switch (en->operenc) { - default: assert(!"nyi enc"); - case EN_ADDSUBSHFT3R: case EN_LOGSHFT3R: - ins |= sf<<31 | o[2].shft<<22 | o[2].reg<<16 | o[2].shamt<<10 | o[1].reg<<5 | o[0].reg; - break; - case EN_ARITH3R: - ins |= sf<<31 | o[2].reg<<16 | o[1].reg<<5 | o[0].reg; - break; - case EN_ADDSUBIMM: - sh = o[2].imm > 0xFFF; - ins |= sf<<31 | sh<<22 | (o[2].uimm >> 12*sh)<<10 | o[1].reg<<5 | o[0].reg; - break; - case EN_LOGIMM: - assert(aarch64_logimm(&nimmrs, k, o[2].uimm)); - ins |= sf<<31 | nimmrs<<10 | o[1].reg<<5 | o[0].reg; - break; - case EN_MOVEIMM: - sh = o[1].imm ? lowestsetbit(o[1].imm) / 16 : 0; - ins |= sf<<31 | sh<<21 | (o[1].uimm >> 16*sh)<<5 | o[0].reg; - break; - case EN_MEMAIMM: AImm: - ins |= o[1].m.disp<<10 | o[1].m.base<<5 | (o[0].reg&31); - break; - case EN_MEMAIMMH: o[1].m.disp >>= 1; goto AImm; - case EN_MEMAIMMW: o[1].m.disp >>= 2; goto AImm; - case EN_MEMAIMMX: o[1].m.disp >>= 3; goto AImm; - case EN_MEMAPREPOST: - ins |= (o[1].m.disp&0x1FF)<<12 | o[1].m.base<<5 | (o[0].reg&31); - if (o[1].m.mode == APREIDX) ins |= 3<<10; - else if (o[1].m.mode == APOSTIDX) ins |= 1<<10; - break; - case EN_MEMAREG: - assert(o[1].m.shamt <= 1); - ins |= o[1].m.index<<16 | o[1].m.ext<<13 | o[1].m.shamt<<12 | o[1].m.base<<5 | (o[0].reg&31); - break; - case EN_MEMPPREPOST: - assert(o[2].m.disp % 8 == 0); - ins |= (o[2].m.disp/8&0x7F)<<15 | (o[1].reg&31)<<10 | o[2].m.base<<5 | (o[0].reg&31); - if (o[2].m.mode == APREIDX) ins |= 3<<23; - else if (o[2].m.mode == APOSTIDX) ins |= 1<<23; - else ins |= 2<<23; - break; - case EN_ADRSYMLO21: - ins |= o[0].reg; - objreloc(xcon2sym(o[1].con), REL_ADR_PREL_LO21, Stext, *pcode - objout.textbegin, o[1].cdisp); - break; - case EN_ADRSYMPGHI21: - ins |= o[0].reg; - objreloc(xcon2sym(o[1].con), REL_ADR_PREL_PG_HI21, Stext, *pcode - objout.textbegin, o[1].cdisp); - break; - case EN_ADDSYMLO12: - ins |= sf<<31 | o[1].reg<<5 | o[0].reg; - objreloc(xcon2sym(o[2].con), REL_ADD_ABS_LO12_NC, Stext, *pcode - objout.textbegin, o[1].cdisp); - break; - case EN_LDSYMLO19: - ins |= o[0].reg; - objreloc(xcon2sym(o[1].con), REL_LD_PREL_LO19, Stext, *pcode - objout.textbegin, o[1].cdisp); - break; - case EN_FP2R: - ins |= sf<<22 | (o[1].reg&31)<<5 | (o[0].reg&31); - break; - case EN_FP1GPR1: - ins |= (o[1].reg&31)<<5 | (o[0].reg&31); - break; - case EN_FP3R: - ins |= sf<<22 | (o[2].reg&31)<<16 | (o[1].reg&31)<<5 | (o[0].reg&31); - break; - case EN_FPCMPZ: - ins |= sf<<22 | (o[0].reg&31)<<5; - break; - case EN_FPCMP: - ins |= sf<<22 | (o[1].reg&31)<<16 | (o[0].reg&31)<<5; - break; - } - W32(ins); -} -#define DEFINSTR1(X, ...) \ - static void \ - X(uchar **pcode, enum irclass k, struct oper a) \ - { \ - static const struct desc tab[] = { __VA_ARGS__ }; \ - encode(pcode, tab, countof(tab), k, ((struct oper [3]){a})); \ - } - -#define DEFINSTR2(X, ...) \ - static void \ - X(uchar **pcode, enum irclass k, struct oper op1, struct oper op2) \ - { \ - static const struct desc tab[] = { __VA_ARGS__ }; \ - encode(pcode, tab, countof(tab), k, ((struct oper [3]){op1,op2})); \ - } -#define DEFINSTR3(X, ...) \ - static void \ - X(uchar **pcode, enum irclass k, struct oper op1, struct oper op2, struct oper op3) \ - { \ - static const struct desc tab[] = { __VA_ARGS__ }; \ - encode(pcode, tab, countof(tab), k, ((struct oper [3]){op1,op2,op3})); \ - } - -DEFINSTR2(Xadrp, - {8, {PGPRZ, PSYM}, 0x90000000, EN_ADRSYMPGHI21} /* ADR (sym pg hi21) */ -) -DEFINSTR2(Xadr, - {8, {PGPRZ, PSYM}, 0x10000000, EN_ADRSYMLO21} /* ADR (sym pg hi21) */ -) - -DEFINSTR3(Xadd, - {4|8, {PGPRSP, PGPRSP, PU12SL12}, 0x11000000, EN_ADDSUBIMM}, /* ADD (immediate) */ - {4|8, {PGPRZ, PGPRZ, PGPRZSHFT}, 0x0B000000, EN_ADDSUBSHFT3R}, /* ADD (shifted register) */ - { 8, {PGPRZ, PGPRZ, PSYM}, 0x11000000, EN_ADDSYMLO12}, /* ADD (sym lo12) */ -) -DEFINSTR3(Xsub, - {4|8, {PGPRSP, PGPRSP, PU12SL12}, 0x51000000, EN_ADDSUBIMM}, /* SUB (immediate) */ - {4|8, {PGPRZ, PGPRZ, PGPRZSHFT}, 0x4B000000, EN_ADDSUBSHFT3R}, /* SUB (shifted register) */ -) -DEFINSTR3(Xsubs, - {4|8, {PGPRZ, PGPRSP, PU12SL12}, 0x71000000, EN_ADDSUBIMM}, /* SUBS (immediate) */ - {4|8, {PGPRZ, PGPRZ, PGPRZSHFT}, 0x6B000000, EN_ADDSUBSHFT3R}, /* SUBS (shifted register) */ -) - -static void -Xmadd(uchar **pcode, enum irclass k, struct oper d, struct oper n, struct oper m, struct oper a) -{ - assert(opermatch(PGPRZ, k, d) && opermatch(PGPRZ, k, n) - && opermatch(PGPRZ, k, a) && opermatch(PGPRZ, k, m)); - uint sf = k > KI32; - W32(0x1B000000 | sf<<31 | m.reg<<16 | a.reg<<10 | n.reg<<5 | d.reg); -} - -DEFINSTR3(Xsdiv, {4|8, {PGPRZ, PGPRZ, PGPRZ}, 0x1AC00C00, EN_ARITH3R}) -DEFINSTR3(Xudiv, {4|8, {PGPRZ, PGPRZ, PGPRZ}, 0x1AC00800, EN_ARITH3R}) - -DEFINSTR3(Xand, - {4|8, {PGPRSP, PGPRZ, PLOGIMM}, 0x12000000, EN_LOGIMM}, /* AND (immediate) */ - {4|8, {PGPRZ, PGPRZ, PGPRZSHFT}, 0x0A000000, EN_LOGSHFT3R}, /* AND (shifted register) */ -) -DEFINSTR3(Xorr, - {4|8, {PGPRSP, PGPRZ, PLOGIMM}, 0x32000000, EN_LOGIMM}, /* ORR (immediate) */ - {4|8, {PGPRZ, PGPRZ, PGPRZSHFT}, 0x2A000000, EN_LOGSHFT3R}, /* ORR (shifted register) */ -) -DEFINSTR3(Xorn, {4|8, {PGPRZ, PGPRZ, PGPRZSHFT}, 0x2A200000, EN_LOGSHFT3R}) -DEFINSTR3(Xeor, - {4|8, {PGPRSP, PGPRZ, PLOGIMM}, 0x52000000, EN_LOGIMM}, /* EOR (immediate) */ - {4|8, {PGPRZ, PGPRZ, PGPRZSHFT}, 0x4A000000, EN_LOGSHFT3R}, /* EOR (shifted register) */ -) -DEFINSTR3(Xlslv, {4|8, {PGPRZ, PGPRZ, PGPRZ}, 0x1AC02000, EN_ARITH3R}) -DEFINSTR3(Xlsrv, {4|8, {PGPRZ, PGPRZ, PGPRZ}, 0x1AC02400, EN_ARITH3R}) -DEFINSTR3(Xasrv, {4|8, {PGPRZ, PGPRZ, PGPRZ}, 0x1AC02800, EN_ARITH3R}) -static void -Xubfm(uchar **pcode, enum irclass k, struct oper rd, struct oper rn, uint immr, uint imms) -{ - uint x = k != KI32; - uint nbit = x ? 64 : 32; - assert(opermatch(PGPRZ, k, rd) && opermatch(PGPRZ, k, rn) && immr < nbit && imms < nbit); - W32(x<<31 | 0x53000000 | x<<22 | immr<<16 | imms<<10 | rn.reg<<5 | rd.reg); -} -static void -Xsbfm(uchar **pcode, enum irclass k, struct oper rd, struct oper rn, uint immr, uint imms) -{ - uint x = k != KI32; - uint nbit = x ? 64 : 32; - assert(opermatch(PGPRZ, k, rd) && opermatch(PGPRZ, k, rn) && immr < nbit && imms < nbit); - W32(x<<31 | 0x13000000 | x<<22 | immr<<16 | imms<<10 | rn.reg<<5 | rd.reg); -} - -DEFINSTR2(Xmovz, {4|8, {PGPRZ, PU16SL16}, 0x52800000, EN_MOVEIMM}, /* MOVZ */) -DEFINSTR2(Xmovn, {4|8, {PGPRZ, PU16SL16}, 0x12800000, EN_MOVEIMM}, /* MOVN */) -DEFINSTR2(Xmovk, {4|8, {PGPRZ, PU16SL16}, 0x72800000, EN_MOVEIMM}, /* MOVK */) -DEFINSTR2(Xldr, - {4, {PGPRZ, PMEMAIMMW}, 0xB9400000, EN_MEMAIMMW}, /* LDR (immediate) */ - {8, {PGPRZ, PMEMAIMMX}, 0xF9400000, EN_MEMAIMMX}, - {4, {PGPRZ, PMEMAREG}, 0xB8600800, EN_MEMAREG}, /* LDR (register) */ - {8, {PGPRZ, PMEMAREG}, 0xF8600800, EN_MEMAREG}, - {4, {PGPRZ, PSYM}, 0x18000000, EN_LDSYMLO19}, /* LDR (literal) */ - {8, {PGPRZ, PSYM}, 0x58000000, EN_LDSYMLO19}, - {4, {PGPRZ, PMEMPREPOST}, 0xB8400000, EN_MEMAPREPOST}, /* LDR (immediate, (pre/postinc)) */ - {8, {PGPRZ, PMEMPREPOST}, 0xF8400000, EN_MEMAPREPOST}, -) -DEFINSTR2(Xfldr, - {4, {PFPR, PMEMAIMMW}, 0xBD400000, EN_MEMAIMMW}, /* LDR (immediate) */ - {8, {PFPR, PMEMAIMMX}, 0xFD400000, EN_MEMAIMMX}, - {4, {PFPR, PMEMAREG}, 0xBC600800, EN_MEMAREG}, /* LDR (register) */ - {8, {PFPR, PMEMAREG}, 0xFC600800, EN_MEMAREG}, - {4, {PFPR, PMEMPREPOST}, 0xBC400000, EN_MEMAPREPOST}, /* LDR (immediate, (pre/postinc)) */ - {8, {PFPR, PMEMPREPOST}, 0xFC400000, EN_MEMAPREPOST}, -) -DEFINSTR2(Xldrsw, - {8, {PGPRZ, PMEMAIMMW}, 0xB9800000, EN_MEMAIMMW}, /* LDRSW (immediate) */ -// {8, {PGPRZ, PMEMAREG}, 0xB8A00800, EN_MEMAREG}, /* LDRSW (register) */ - {8, {PGPRZ, PMEMPREPOST}, 0xB8800000, EN_MEMAPREPOST}, /* LDRSW (immediate, (pre/postinc)) */ -) -DEFINSTR2(Xldrh, - {4|8, {PGPRZ, PMEMAIMMH}, 0x79400000, EN_MEMAIMMH}, /* LDRH (immediate) */ - {4|8, {PGPRZ, PMEMAREG}, 0x78600800, EN_MEMAREG}, /* LDRH (register) */ - {4|8, {PGPRZ, PMEMPREPOST}, 0x78400000, EN_MEMAPREPOST}, /* LDRH (immediate, (pre/postinc)) */ -) -DEFINSTR2(Xldrsh, - {4, {PGPRZ, PMEMAIMMH}, 0x79C00000, EN_MEMAIMMH}, /* LDRSH (immediate) */ - {8, {PGPRZ, PMEMAIMMH}, 0x79800000, EN_MEMAIMMH}, - {4, {PGPRZ, PMEMAREG}, 0x78E00800, EN_MEMAREG}, /* LDRSH (register) */ - {8, {PGPRZ, PMEMAREG}, 0x78A00800, EN_MEMAREG}, - {4, {PGPRZ, PMEMPREPOST}, 0x78C00000, EN_MEMAPREPOST}, /* LDRSH (immediate, (pre/postinc)) */ - {8, {PGPRZ, PMEMPREPOST}, 0x78800000, EN_MEMAPREPOST}, -) -DEFINSTR2(Xldrb, - {4|8, {PGPRZ, PMEMAIMM}, 0x39400000, EN_MEMAIMM}, /* LDRB (immediate) */ - {4|8, {PGPRZ, PMEMAREG}, 0x38600800, EN_MEMAREG}, /* LDRB (register) */ - {4|8, {PGPRZ, PMEMPREPOST}, 0x38400000, EN_MEMAPREPOST}, /* LDRB (immediate, (pre/postinc)) */ -) -DEFINSTR2(Xldrsb, - {4, {PGPRZ, PMEMAIMM}, 0x39C00000, EN_MEMAIMM}, /* LDRSB (immediate) */ - {8, {PGPRZ, PMEMAIMM}, 0x39800000, EN_MEMAIMM}, - {4, {PGPRZ, PMEMAREG}, 0x38E00800, EN_MEMAREG}, /* LDRSB (register) */ - {8, {PGPRZ, PMEMAREG}, 0x38A00800, EN_MEMAREG}, - {4, {PGPRZ, PMEMPREPOST}, 0x38C00000, EN_MEMAPREPOST}, /* LDRSB (immediate, (pre/postinc)) */ - {8, {PGPRZ, PMEMPREPOST}, 0x38800000, EN_MEMAPREPOST}, -) -DEFINSTR2(Xstr, - {4, {PGPRZ, PMEMAIMMW}, 0xB9000000, EN_MEMAIMMW}, /* STR (immediate) */ - {8, {PGPRZ, PMEMAIMMX}, 0xF9000000, EN_MEMAIMMX}, - {4, {PGPRZ, PMEMAREG}, 0xB8200800, EN_MEMAREG}, /* STR (register) */ - {8, {PGPRZ, PMEMAREG}, 0xF8200800, EN_MEMAREG}, - {4, {PGPRZ, PMEMPREPOST}, 0xB8000000, EN_MEMAPREPOST}, /* STR (immediate, (pre/postinc)) */ - {8, {PGPRZ, PMEMPREPOST}, 0xF8000000, EN_MEMAPREPOST}, -) -DEFINSTR2(Xfstr, - {4, {PFPR, PMEMAIMMW}, 0xBD000000, EN_MEMAIMMW}, /* LDR (immediate) */ - {8, {PFPR, PMEMAIMMX}, 0xFD000000, EN_MEMAIMMX}, - {4, {PFPR, PMEMAREG}, 0xBC200800, EN_MEMAREG}, /* LDR (register) */ - {8, {PFPR, PMEMAREG}, 0xFC200800, EN_MEMAREG}, - {4, {PFPR, PMEMPREPOST}, 0xBC000000, EN_MEMAPREPOST}, /* LDR (immediate, (pre/postinc)) */ - {8, {PFPR, PMEMPREPOST}, 0xFC000000, EN_MEMAPREPOST}, -) -DEFINSTR2(Xstrh, - {4|8, {PGPRZ, PMEMAIMMH}, 0x79000000, EN_MEMAIMMH}, /* STRH (immediate) */ - {4|8, {PGPRZ, PMEMAREG}, 0x78200800, EN_MEMAREG}, /* STRH (register) */ - {4|8, {PGPRZ, PMEMPREPOST}, 0x78000000, EN_MEMAPREPOST}, /* STRH (immediate, (pre/postinc)) */ -) -DEFINSTR2(Xstrb, - {4|8, {PGPRZ, PMEMAIMM}, 0x39000000, EN_MEMAIMM}, /* STRB (immediate) */ - {4|8, {PGPRZ, PMEMAREG}, 0x38200800, EN_MEMAREG}, /* STRB (register) */ - {4|8, {PGPRZ, PMEMPREPOST}, 0x38000000, EN_MEMAPREPOST}, /* STRB (immediate, (pre/postinc)) */ -) -DEFINSTR3(Xldp, - {8, {PGPRZ, PGPRZ, PMEMPREPOST}, 0xA8400000, EN_MEMPPREPOST} /* LDP (immediate, (pre/postinc)) */ -) -DEFINSTR3(Xstp, - {8, {PGPRZ, PGPRZ, PMEMPREPOST}, 0xA8000000, EN_MEMPPREPOST} /* STP (immediate, (pre/postinc)) */ -) -DEFINSTR3(Xfldp, - {8, {PFPR, PFPR, PMEMPREPOST}, 0x6CC00000, EN_MEMPPREPOST} /* LDP (immediate, (pre/postinc)) */ -) -DEFINSTR3(Xfstp, - {8, {PFPR, PFPR, PMEMPREPOST}, 0x6C800000, EN_MEMPPREPOST} /* STP (immediate, (pre/postinc)) */ -) -static void -Xcall(uchar **pcode, struct oper dst) -{ - if (dst.t == OSYM) { - objreloc(xcon2sym(dst.con), REL_CALL26, Stext, *pcode - objout.textbegin, 0); - W32(0x94000000); /* BL */ - } else { - assert(opermatch(PGPRZ, KPTR, dst)); - W32(0xD63F0000 | dst.reg<<5); /* BLR Xn */ - } -} -DEFINSTR2(Xfmov, - {4|8, {PFPR, PFPR}, 0x1E204000, EN_FP2R}, - {4, {PFPR, PGPRZ}, 0x1E270000, EN_FP1GPR1}, - { 8, {PFPR, PGPRZ}, 0x9E670000, EN_FP1GPR1}, - {4, {PGPRZ, PFPR}, 0x1E260000, EN_FP1GPR1}, - { 8, {PGPRZ, PFPR}, 0x9E660000, EN_FP1GPR1}, -) -DEFINSTR2(Xfneg, {4|8, {PFPR, PFPR}, 0x1E214000, EN_FP2R}) -DEFINSTR2(Xscvtfw, {4|8, {PFPR, PGPRZ}, 0x1E220000, EN_FP2R}) -DEFINSTR2(Xscvtfx, {4|8, {PFPR, PGPRZ}, 0x9E220000, EN_FP2R}) -DEFINSTR2(Xfcvtzsw, {4|8, {PGPRZ, PFPR}, 0x1E380000, EN_FP2R}) -DEFINSTR2(Xfcvtzsx, {4|8, {PGPRZ, PFPR}, 0x9E380000, EN_FP2R}) -DEFINSTR2(Xucvtfw, {4|8, {PFPR, PGPRZ}, 0x1E230000, EN_FP2R}) -DEFINSTR2(Xucvtfx, {4|8, {PFPR, PGPRZ}, 0x9E230000, EN_FP2R}) -DEFINSTR2(Xfcvtzuw, {4|8, {PGPRZ, PFPR}, 0x1E390000, EN_FP2R}) -DEFINSTR2(Xfcvtzux, {4|8, {PGPRZ, PFPR}, 0x9E390000, EN_FP2R}) -DEFINSTR2(Xfcvtds, {4, {PFPR, PFPR}, 0x1E624000, EN_FP2R}) -DEFINSTR2(Xfcvtsd, {4, {PFPR, PFPR}, 0x1E22C000, EN_FP2R}) -DEFINSTR3(Xfadd, {4|8, {PFPR, PFPR, PFPR}, 0x1E202800, EN_FP3R}) -DEFINSTR3(Xfsub, {4|8, {PFPR, PFPR, PFPR}, 0x1E203800, EN_FP3R}) -DEFINSTR3(Xfmul, {4|8, {PFPR, PFPR, PFPR}, 0x1E200800, EN_FP3R}) -DEFINSTR3(Xfdiv, {4|8, {PFPR, PFPR, PFPR}, 0x1E201800, EN_FP3R}) -DEFINSTR2(Xfcmp, - {4|8, {PFPR, PZERO}, 0x1E602008, EN_FPCMPZ}, - {4|8, {PFPR, PFPR}, 0x1E602000, EN_FPCMP}, -) - -static void -gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct oper dst, union ref val) -{ - assert(dst.t == OREG); - struct oper src; - if (val.bits == UNDREF.bits) return; - if (isintcon(val)) { - assert(dst.reg <= R(31)); - /* MOV r, #imm */ - uvlong u = intconval(val); - if (~u <= 0xFFFF) { - /* immediate can be encoded with 1 MOVN instruction */ - Xmovn(pcode, cls, dst, mkoper(OIMM, .imm = ~u)); - } else { - /* generate MOV (+ MOVKs) */ - if (cls == KI32) u = (uint)u; - int s = 0; - while (s < 48 && (u >> s & 0xFFFF) == 0) s += 16; - if ((u &~ (0xFFFFull << s)) != 0 && aarch64_logimm(NULL, cls, u)) { - /* can be encoded as a logical immediate in 1 instr */ - Xorr(pcode, cls, dst, REGZR, mkoper(OIMM, .uimm = u)); - } else { - Xmovz(pcode, cls, dst, mkoper(OIMM, .imm = u & (0xFFFFull << s))); - for (s += 16; s <= 48; s += 16) { - if ((u >> s) & 0xFFFF) - Xmovk(pcode, cls, dst, mkoper(OIMM, .imm = u & (0xFFFFull << s))); - } - } - } - } else if (opermatch(PGPRZ, cls, (src = ref2oper(val))) && kisint(cls)) { - Xorr(pcode, cls, dst, REGZR, src); /* MOV Rd, Rn ==> ORR Rd, zr, Rn */ - } else if (kisflt(cls) || opermatch(PFPR, 0, src)) { - if (src.t == OREG) - Xfmov(pcode, cls, dst, src); - else if (src.t == OIMM && src.imm == 0) - Xfmov(pcode, cls, dst, REGZR); - else assert(0); - } else if (isaddrcon(val,0) || (val.t == RADDR && isaddrcon(addrtab.p[val.i].base,0))) { - if ((ccopt.pic || (contab.p[val.i].flag & SFUNC)) && !(contab.p[val.i].flag & SLOCAL)) { - Xadrp(pcode, KPTR, dst, src); - Xadd(pcode, KPTR, dst, dst, src); - } else { - Xadr(pcode, KPTR, dst, src); - } - } else assert(0); -} - -/* maps blk -> address when resolved; or to linked list of jump displacement - * relocations */ -static struct blkaddr { - bool resolved; - union { - uint addr; - uint relreloc; - }; -} *blkaddr; - -enum cc { - CCEQ, CCNE, CCCS, CCCC, CCMI, CCPL, CCVS, CCVC, - CCHI, CCLS, CCGE, CCLT, CCGT, CCLE, CCAL, CCNV, - CCHS = CCCS, CCLO = CCCC, -}; - -static void -Xbcc(uchar **pcode, enum cc cc, struct block *dst) -{ - int disp, insaddr = *pcode - objout.textbegin; - - if (blkaddr[dst->id].resolved) { - disp = (int)(blkaddr[dst->id].addr - insaddr)/4; - assert(disp >= -(1<<18) && disp < (1<<18)); - } else { - disp = blkaddr[dst->id].relreloc; - blkaddr[dst->id].relreloc = insaddr; - } - assert(in_range(cc, 0, 0xF)); - W32(0x54000000 | (disp & 0x7FFFF)<<5 | cc); -} - -static void -Xcbcc(uchar **pcode, enum irclass k, uint rt, enum cc cc, struct block *dst) -{ - int disp, insaddr = *pcode - objout.textbegin; - if (blkaddr[dst->id].resolved) { - disp = (int)(blkaddr[dst->id].addr - insaddr)/4; - assert(disp >= -(1<<18) && disp < (1<<18)); - } else { - disp = blkaddr[dst->id].relreloc; - blkaddr[dst->id].relreloc = insaddr; - } - assert(in_range(cc, CCEQ, CCNE)); - assert(in_range(rt, 0, 31)); - W32(0x34000000 | (uint)(k > KI32)<<31 | cc<<24 | (disp & 0x7FFFF)<<5 | rt); -} - -/* condition code for CMP */ -static const schar icmpop2cc[] = { - [Oequ] = CCEQ, [Oneq] = CCNE, - [Olth] = CCLT, [Ogth] = CCGT, [Olte] = CCLE, [Ogte] = CCGE, - [Oulth] = CCLO, [Ougth] = CCHI, [Oulte] = CCLS, [Ougte] = CCHS, -}, fcmpop2cc[] = { - [Oequ] = CCEQ, [Oneq] = CCNE, - [Olth] = CCLO, [Ogth] = CCGT, [Olte] = CCLS, [Ogte] = CCGE, -}; - -static void -emitbranch(uchar **pcode, struct block *blk) -{ - enum irclass cbk = 0; - struct oper cbopr; - enum cc cc = CCAL; - assert(blk->s1); - if (blk->s2) { - /* conditional branch.. */ - union ref arg = blk->jmp.arg[0]; - assert(arg.t == RTMP); - struct instr *ins = &instrtab[arg.i]; - if (in_range(ins->op, Oequ, Oneq) && ins->r.bits == ZEROREF.bits) { - cc = ins->op == Oequ ? CCEQ : CCNE; - cbk = ins->cls; - cbopr = ref2oper(ins->l); - assert(opermatch(PGPRZ, ins->cls, cbopr)); - } else if (oiscmp(ins->op)) { - /* for CMP instr */ - cc = (kisint(ins->cls) ? icmpop2cc : fcmpop2cc)[ins->op]; - } else { - /* implicit by ZF */ - cc = CCNE; - } - if (blk->s1 == blk->lnext) { - /* if s1 is next adjacent block, swap s1,s2 and flip condition to emit a - * single jump */ - struct block *tmp = blk->s1; - blk->s1 = blk->s2; - blk->s2 = tmp; - cc ^= 1; - } - } - /* make sure to fallthru if jumping to next adjacent block */ - if (blk->s2 || blk->s1 != blk->lnext) { - if (cbk) Xcbcc(pcode, cbk, cbopr.reg, cc, blk->s1); - else Xbcc(pcode, cc, blk->s1); - } - if (blk->s2 && blk->s2 != blk->lnext) - Xbcc(pcode, CCAL, blk->s2); -} - -static struct instr *lastcmp; - -static void -emitinstr(uchar **pcode, struct function *fn, struct block *blk, int curi, struct instr *ins) -{ - struct oper dst, o1, o2; - enum irclass cls = ins->cls; - void (*X3)(uchar **, enum irclass, struct oper, struct oper, struct oper) = NULL; - void (*X2)(uchar **, enum irclass, struct oper, struct oper) = NULL; - - switch (ins->op) { - default: fatal(NULL, "aarch64 unimplemented instr: %s", opnames[ins->op]); - case Onop: break; - case Omove: - dst = ref2oper(ins->l); - gencopy(pcode, cls, blk, curi, dst, ins->r); - break; - case Oextu32: cls = KI32; - /* fallthru */ - case Ocopy: - dst = reg2oper(ins->reg-1); - gencopy(pcode, cls, blk, curi, dst, ins->l); - break; - case Oswap: - o1 = ref2oper(ins->l), o2 = ref2oper(ins->r); - if (kisflt(ins->cls) && ins->l.i != mctarg->fprscratch && ins->r.i != mctarg->fprscratch) { - dst = reg2oper(mctarg->fprscratch); - Xfmov(pcode, cls, dst, o1); - Xfmov(pcode, cls, o1, o2); - Xfmov(pcode, cls, o2, dst); - } else if (ins->l.i != mctarg->gprscratch && ins->r.i != mctarg->gprscratch) { - dst = reg2oper(mctarg->gprscratch); - Xorr(pcode, cls, dst, REGZR, o1); - Xorr(pcode, cls, o1, REGZR, o2); - Xorr(pcode, cls, o2, REGZR, dst); - } else { - Xeor(pcode, cls, o1, o1, o2); - Xeor(pcode, cls, o2, o1, o2); - Xeor(pcode, cls, o1, o1, o2); - } - break; - case Onot: /* MVN Rd, Rn ==> ORN Rd, zr, Rn */ - Xorn(pcode, cls, reg2oper(ins->reg-1), REGZR, ref2oper(ins->l)); - break; - case Oneg: - if (kisint(ins->cls)) /* NEG Rd, Rn ==> SUB Rd, zr, Rn */ - Xsub(pcode, cls, reg2oper(ins->reg-1), REGZR, ref2oper(ins->l)); - else - Xfneg(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l)); - break; - case Oexts8: case Oexts16: case Oexts32: /* SXTB/H/W Rd, Rn ==> SBFM Rd, Rn, #0, #7/15/31 */ - Xsbfm(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l), 0, (8<<(ins->op-Oexts8)/2)-1); - break; - case Oextu8: case Oextu16: /* UXTB/H Rd, Rn ==> UBFM Rd, Rn, #0, #7/15 */ - Xubfm(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l), 0, (8<<(ins->op-Oexts8)/2)-1); - break; - case Ocvts32f: X2 = Xscvtfw; goto Cvt; - case Ocvts64f: X2 = Xscvtfx; goto Cvt; - case Ocvtf32s: - X2 = cls == KI32 ? Xfcvtzsw : Xfcvtzsx; - cls = KF32; - goto Cvt; - case Ocvtf64s: - X2 = cls == KI32 ? Xfcvtzsw : Xfcvtzsx; - cls = KF64; - goto Cvt; - case Ocvtu32f: X2 = Xucvtfw; goto Cvt; - case Ocvtu64f: X2 = Xucvtfx; goto Cvt; - case Ocvtf32u: - X2 = cls == KI32 ? Xfcvtzuw : Xfcvtzux; - cls = KF32; - goto Cvt; - case Ocvtf64u: - X2 = cls == KI32 ? Xfcvtzuw : Xfcvtzux; - cls = KF64; - goto Cvt; - case Ocvtf32f64: cls = KF32; X2 = Xfcvtsd; goto Cvt; - case Ocvtf64f32: cls = KF32; X2 = Xfcvtds; goto Cvt; - Cvt: - X2(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l)); - break; - case Oadd: X3 = kisint(cls) ? Xadd : Xfadd; goto ALU3; - case Osub: X3 = kisint(cls) ? Xsub : Xfsub; goto ALU3; - case Omul: if (kisflt(cls)) { X3 = Xfmul; goto ALU3; } - /* MUL Rd,Rn,Rm ==> MADD Rd,Rn,Rm,zr */ - Xmadd(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l), ref2oper(ins->r), REGZR); - break; - case Odiv: X3 = kisint(cls) ? Xsdiv : Xfdiv; goto ALU3; - case Oudiv: X3 = Xudiv; goto ALU3; - case Oand: X3 = Xand; goto ALU3; - case Oior: X3 = Xorr; goto ALU3; - case Oxor: X3 = Xeor; goto ALU3; - ALU3: - X3(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l), ref2oper(ins->r)); - break; - case Oshl: - if (ins->r.t == RICON) { - uint nbit = cls == KI32 ? 32 : 64, s = ins->r.i & (nbit-1); - assert(s > 0); - Xubfm(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l), nbit-s, nbit-s-1); - } else { - X3 = Xlslv; - goto ALU3; - } - break; - case Oslr: - if (ins->r.t == RICON) { - uint nbit = cls == KI32 ? 32 : 64, s = ins->r.i & (nbit-1); - assert(s > 0); - Xubfm(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l), s, nbit-1); - } else { - X3 = Xlsrv; - goto ALU3; - } - break; - case Osar: - if (ins->r.t == RICON) { - uint nbit = cls == KI32 ? 32 : 64, s = ins->r.i & (nbit-1); - assert(s > 0); - Xsbfm(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l), s, nbit-1); - } else { - X3 = Xasrv; - goto ALU3; - } - break; - case Oequ: case Oneq: - if (!ins->reg && kisint(cls) && ins->r.bits == ZEROREF.bits) /* handled by emitbranch for CBZ/CBNZ */ - break; - case Olth: case Ogth: case Olte: case Ogte: - case Oulth: case Ougth: case Oulte: case Ougte: - if (lastcmp && lastcmp->cls == cls - && lastcmp->l.bits == ins->l.bits && lastcmp->r.bits == ins->r.bits) - /* reuse flags from previous identical cmp */ ; - else if (kisflt(cls)) - Xfcmp(pcode, cls, ref2oper(ins->l), ref2oper(ins->r)); - else /* CMP ... ==> SUBS zr, ... */ - Xsubs(pcode, cls, REGZR, ref2oper(ins->l), ref2oper(ins->r)); - lastcmp = ins; - if (ins->reg) { - enum cc cc = (kisflt(cls) ? fcmpop2cc : icmpop2cc)[ins->op]; - dst = reg2oper(ins->reg-1); - assert(dst.reg < R(31)); - W32(0x1A9F07E0 | (cc^1)<<12 | dst.reg); /* CSET Wd, */ - } - break; - case Oloadu8: X2 = Xldrb; goto Load; - case Oloads8: X2 = Xldrsb; goto Load; - case Oloadu16: X2 = Xldrh; goto Load; - case Oloads16: X2 = Xldrsh; goto Load; - case Oloads32: - if (cls != KI32) { - X2 = Xldrsw; - goto Load; - } - case Oloadu32: - cls = KI32; - /* fallthru */ - case Oloadi64: X2 = Xldr; - Load: - X2(pcode, cls, reg2oper(ins->reg-1), mkmemoper(1<<(ins->op - Oloads8)/2, ins->l)); - break; - case Oloadf32: case Oloadf64: - Xfldr(pcode, cls, reg2oper(ins->reg-1), mkmemoper(ins->op == Oloadf32 ? 4 : 8, ins->l)); - break; - case Ostorei8: cls = KI32; X2 = Xstrb; goto Store; - case Ostorei16: cls = KI32; X2 = Xstrh; goto Store; - case Ostorei32: cls = KI32; X2 = Xstr; goto Store; - case Ostorei64: cls = KI64; X2 = Xstr; - Store: - X2(pcode, cls, ins->r.bits == ZEROREF.bits ? REGZR : ref2oper(ins->r), - mkmemoper(1<<(ins->op-Ostorei8), ins->l)); - break; - case Ostoref32: case Ostoref64: - Xfstr(pcode, KF32 + ins->op-Ostoref32, ref2oper(ins->r), mkmemoper(ins->op == Oloadf32 ? 4 : 8, ins->l)); - break; - case Ocall: - Xcall(pcode, ref2oper(ins->l)); - break; - } -} - -struct frame { - regset save; - struct rpair { uchar a,b; } pairs[10]; - uchar single[2]; - uint nfpairs, ngpairs; -}; - -static void -prologue(uchar **pcode, struct frame *frame, struct function *fn) -{ - *frame = (struct frame){0}; - regset save = frame->save = (fn->regusage & mctarg->rcallee) | (usefp * BIT(FP)) | (!fn->isleaf * BIT(LR)); - if (save) { - int prev = 0; - struct rpair *p = frame->pairs; - for (uint reg = V(8); reg <= V(15); ++reg) { - if (!rstest(save, reg)) continue; - if (prev) { - *p++ = (struct rpair) {prev, reg}; - ++frame->nfpairs; - prev = 0; - } else prev = reg; - } - uint ngpr = popcnt(save & (BIT(32)-1)); - if (prev) { - if (ngpr & 1) { - frame->single[0] = prev; - frame->single[1] = prev = lowestsetbit(save); - rsclr(&save, prev); - } else { - *p++ = (struct rpair) {prev, V(0)}; - ++frame->nfpairs; - } - prev = 0; - } else if (ngpr & 1) { - prev = 0x100; - } - for (uint reg = R(19); reg <= LR; ++reg) { - if (!rstest(save, reg)) continue; - if (prev) { - *p++ = (struct rpair) {prev, reg}; - ++frame->ngpairs; - prev = 0; - } else prev = reg; - } - assert(!prev); - - p = frame->pairs; - struct oper adr = mkoper(OMEM, .m = {.mode = APREIDX, .base = SP, .disp = -16}); - for (int i = 0; i < frame->nfpairs; ++i, ++p) - Xfstp(pcode, KF64, reg2oper(p->a), reg2oper(p->b), adr); - adr.m.disp = -8; - if (frame->single[0]) Xfstr(pcode, KF64, reg2oper(frame->single[0]), adr); - if (frame->single[1]) Xstr(pcode, KPTR, reg2oper(frame->single[1]), adr); - adr.m.disp = -16; - for (int i = 0; i < frame->ngpairs; ++i, ++p) - Xstp(pcode, KPTR, reg2oper(p->a), reg2oper(p->b), adr); - } - - if (usefp) /* MOV x29, sp */ - Xadd(pcode, KPTR, reg2oper(FP), reg2oper(SP), mkoper(OIMM,)); - - /* ensure stack is 16-byte aligned for function calls */ - if (!fn->isleaf && ((fn->stksiz) & 0xF) != 0) { - assert(usefp); - rbpoff -= 8; - fn->stksiz += 8; - } - if (fn->stksiz) Xsub(pcode, KPTR, reg2oper(SP), reg2oper(SP), mkoper(OIMM, .imm = fn->stksiz)); -} - -static void -epilogue(uchar **pcode, struct function *fn, struct frame *frame) -{ - if (fn->stksiz) Xadd(pcode, KPTR, reg2oper(SP), reg2oper(SP), mkoper(OIMM, .imm = fn->stksiz)); - if (frame->save) { - struct rpair *p = frame->pairs + frame->nfpairs + frame->ngpairs - 1; - struct oper adr = mkoper(OMEM, .m = {.mode = APOSTIDX, .base = SP, .disp = 16}); - for (int i = 0; i < frame->ngpairs; ++i, --p) - Xldp(pcode, KPTR, reg2oper(p->a), reg2oper(p->b), adr); - adr.m.disp = 8; - if (frame->single[1]) Xldr(pcode, KPTR, reg2oper(frame->single[1]), adr); - if (frame->single[0]) Xfldr(pcode, KF64, reg2oper(frame->single[0]), adr); - adr.m.disp = 16; - for (int i = 0; i < frame->nfpairs; ++i, --p) - Xfldp(pcode, KF64, reg2oper(p->a), reg2oper(p->b), adr); - } -} - -static void -emitbin(struct function *fn) -{ - struct block *blk; - uchar **pcode = &objout.code; - - while ((*pcode - objout.textbegin) % 4) ++*pcode; - fnstart = *pcode; - curfnsym = fn->name; - - /** prologue **/ - - /* only use frame pointer in non-leaf functions and functions that use the stack */ - usefp = !fn->isleaf || fn->stksiz; - struct frame frame; - prologue(pcode, &frame, fn); - - if (*pcode - fnstart > 8) { - /* largue prologue -> largue epilogue -> transform to use single exit point */ - struct block *exit = NULL; - blk = fn->entry->lprev; - do { - if (blk->jmp.t == Jret) { - if (!exit) { - if (blk->ins.n == 0) { - exit = blk; - continue; - } else { - exit = newblk(fn); - exit->lnext = blk->lnext; - exit->lprev = blk; - blk->lnext = exit; - exit->lnext->lprev = exit; - exit->id = fn->nblk++; - exit->jmp.t = Jret; - } - } - blk->jmp.t = Jb; - memset(blk->jmp.arg, 0, sizeof blk->jmp.arg); - blk->s1 = exit; - } else if (exit) { - /* thread jumps to the exit block */ - if (blk->s1 && !blk->s1->ins.n && blk->s1->s1 == exit && !blk->s1->s2) blk->s1 = exit; - if (blk->s2 && !blk->s2->ins.n && blk->s2->s1 == exit && !blk->s2->s2) blk->s2 = exit; - } - } while ((blk = blk->lprev) != fn->entry); - } - - blkaddr = allocz(fn->passarena, fn->nblk * sizeof *blkaddr, 0); - - blk = fn->entry; - do { - struct blkaddr *bb = &blkaddr[blk->id]; - uint bbaddr = *pcode - objout.textbegin; - assert(!bb->resolved); - while (bb->relreloc) { - int disp = (bbaddr - bb->relreloc)/4; - assert(disp >= -(1<<18) && disp < (1<<18)); - uint tmp = rd32targ(objout.textbegin + bb->relreloc); - wr32le(objout.textbegin + bb->relreloc, (tmp &~ (0x7FFFFu<<5)) | (disp & 0x7FFFF)<<5); - bb->relreloc = tmp>>5 & 0x7FFFF; - } - bb->resolved = 1; - bb->addr = bbaddr; - - lastcmp = NULL; - for (int i = 0; i < blk->ins.n; ++i) - emitinstr(pcode, fn, blk, i, &instrtab[blk->ins.p[i]]); - if (blk->jmp.t == Jret) { - if (blk->lnext != fn->entry && blk->lnext->jmp.t == Jret && blk->lnext->ins.n == 0) - continue; /* fallthru to next blk's RET */ - epilogue(pcode, fn, &frame); - W32(0xD65F03C0); /* RET */ - } else if (blk->jmp.t == Jtrap) { - W32(0xD4200020); /* BRK #0x1 */ - } else emitbranch(pcode, blk); - } while ((blk = blk->lnext) != fn->entry); - objdeffunc(fn->name, fn->globl, fnstart - objout.textbegin, *pcode - fnstart); -} - -void -aarch64_emit(struct function *fn) -{ - fn->stksiz = alignup(fn->stksiz, 8); - if (fn->stksiz > 1<<24) error(NULL, "'%s' stack frame too big", fn->name); - emitbin(fn); -} - -/* vim:set ts=3 sw=3 expandtab: */ diff --git a/aarch64/isel.c b/aarch64/isel.c deleted file mode 100644 index 398ea28..0000000 --- a/aarch64/isel.c +++ /dev/null @@ -1,515 +0,0 @@ -#include "all.h" - -#define isimm32(r) (iscon(r) && concls(r) == KI32) - -static inline uint -clz(uvlong x) -{ -#if HAS_BUILTIN(clzll) - return __builtin_clzll(x); -#else - int i = 0; - for (uvlong mask = BIT(63);; ++i, mask >>= 1) - if (x & mask) - break; - return i; -#endif -} - -/* Encode logical immediate */ -bool -aarch64_logimm(uint *enc, enum irclass k, uvlong x) -{ - /* https://github.com/v8/v8/blob/927ccc6076e25a614787c7011315468e40fe39a4/src/codegen/arm64/assembler-arm64.cc#L4409 */ - if (k == KI32) x = (uint)x | x << 32; - bool neg; - if ((neg = x & 1)) x = ~x; - if (x == 0) return 0; - uvlong a = x & (~x + 1), - xa = x + a, - b = xa & (~xa + 1), - xa_b = xa - b, - c = xa_b & (~xa_b + 1), - mask; - uint clza = clz(a), - d, outn; - if (c != 0) { - d = clza - clz(c); - mask = BIT(d) - 1; - outn = 0; - } else { - assert(a != 0); - d = 64; - mask = ~0ull; - outn = 1; - } - if (!ispo2(d)) return 0; - if (((b - a) & ~mask) != 0) return 0; - static const uvlong M[] = { - 0x0000000000000001, 0x0000000100000001, 0x0001000100010001, - 0x0101010101010101, 0x1111111111111111, 0x5555555555555555, - }; - int i = clz(d) - 57; - assert((uint)i < countof(M)); - uvlong m = M[i]; - uvlong y = (b - a) * m; - if (y != x) return 0; - if (enc) { - int clzb = b == 0 ? -1 : clz(b), - s = clza - clzb, r; - if (neg) { - s = d - s; - r = (clzb + 1) & (d - 1); - } else { - r = (clza + 1) & (d - 1); - } - *enc = outn<<12 | r<<6 | (((-d * 2) | (s - 1)) & 0x3F); - } - return 1; -} - - -static void fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi); -static void -regarg(union ref *r, enum irclass k, struct block *blk, int *curi) -{ - if (r->t != RTMP) { - *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, k, *r)); - if (kisflt(k) || instrtab[r->i].l.t == RSTACK) { - int iprev = *curi-1; - fixarg(&instrtab[r->i].l, &instrtab[r->i], blk, &iprev); - *curi = iprev+1; - } - } -} - -static void -fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi) -{ - enum op op = ins ? ins->op : 0; - if (isintcon(*r)) { - vlong x = intconval(*r); - switch (op) { - case Ocopy: return; - default: - if (oiscmp(op)) { - case Oadd: case Osub: - /* imm12 (lsl 12) */ - if ((x &~ 0xFFF) == 0 || (x &~ 0xFFF000) == 0) return; - break; - case Oshl: case Osar: case Oslr: - if ((uvlong)x < (ins->cls == KI32 ? 32 : 64)) return; - break; - case Oand: case Oior: case Oxor: - if (aarch64_logimm(NULL, ins->cls, x)) return; - break; - } - } - goto Reg; - } else if (isfltcon(*r)) { - enum irclass k = concls(*r), ki = KI32 + k-KF32; - if (contab.p[r->i].f != 0.0) { - union { - vlong i64; - int i32; - float f32; - double f64; - } pun; - vlong i; - if (k == KF32) { - pun.f32 = contab.p[r->i].f; - i = pun.i32; - } else { - pun.f64 = contab.p[r->i].f; - i = pun.i64; - } - union ref gpr = insertinstr(blk, (*curi)++, mkinstr(Ocopy, ki, mkintcon(ki, i))); - *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, k, gpr)); - } else if (oiscmp(op)) { - return; - } else { - *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, k, *r)); - } - } else if (r->t == RSTACK) { - struct instr adr = mkinstr(Osub, KPTR, mkref(RREG, FP), mkintcon(KI32, r->i)); - if (op == Ocopy) - *ins = adr; - else - *r = insertinstr(blk, (*curi)++, adr); - } else if (r->t != RTMP) Reg: { - regarg(r, r->t == RTMP ? instrtab[r->i].cls : ins->cls ? ins->cls : KI32, blk, curi); - } -} - -static bool -arithfold(struct instr *ins) -{ - if (isnumcon(ins->l) && (!ins->r.t || isnumcon(ins->r))) { - union ref r; - bool ok = ins->r.t ? foldbinop(&r, ins->op, ins->cls, ins->l, ins->r) : foldunop(&r, ins->op, ins->cls, ins->l); - assert(ok && "fold?"); - *ins = mkinstr(Ocopy, insrescls(*ins), r); - return 1; - } - return 0; -} - -static void -selcall(struct function *fn, struct instr *ins, struct block *blk, int *curi) -{ - const struct call *call = &calltab.p[ins->r.i]; - int iarg = *curi - 1; - enum irclass cls; - uint argstksiz = alignup(call->argstksiz, 16); - - for (int i = call->narg - 1; i >= 0; --i) { - struct abiarg abi = call->abiarg[i]; - struct instr *arg; - for (;; --iarg) { - assert(iarg >= 0 && i >= 0 && "arg?"); - if ((arg = &instrtab[blk->ins.p[iarg]])->op == Oarg) - break; - } - - if (!abi.isstk) { - assert(!abi.ty.isagg); - *arg = mkinstr(Omove, call->abiarg[i].ty.cls, mkref(RREG, abi.reg), arg->r); - } else { - union ref adr = mkaddr((struct addr){mkref(RREG, SP), .disp = abi.stk}); - int iargsave = iarg; - if (!abi.ty.isagg) { /* scalar arg in stack */ - *arg = mkinstr(cls2store[abi.ty.cls], 0, adr, arg->r); - if (isaddrcon(arg->r,1) || arg->r.t == RADDR) - arg->r = insertinstr(blk, iarg++, mkinstr(Ocopy, abi.ty.cls, arg->r)); - else - fixarg(&ins->r, ins, blk, &iarg); - } else { /* aggregate arg in stack, callee stack frame destination address */ - *arg = mkinstr(Ocopy, KPTR, adr); - } - *curi += iarg - iargsave; - } - } - if (call->argstksiz) { - union ref disp = mkref(RICON, argstksiz); - insertinstr(blk, iarg--, (struct instr){Osub, KPTR, .keep=1, .reg = SP+1, .l=mkref(RREG,SP), disp}); - ++*curi; - insertinstr(blk, *curi+1, (struct instr){Oadd, KPTR, .keep=1, .reg = SP+1, .l=mkref(RREG,SP), disp}); - } - if (isimm32(ins->l)) - ins->l = mkaddr((struct addr){.base = ins->l}); - else if (isintcon(ins->l)) - ins->l = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, ins->l)); - - cls = ins->cls; - ins->cls = 0; - if (cls) { - /* duplicate to reuse same TMP ref */ - insertinstr(blk, (*curi)++, *ins); - *ins = mkinstr(Ocopy, cls, mkref(RREG, call->abiret[0].reg)); - for (int i = 1; i <= 2; ++i) { - if (*curi + i >= blk->ins.n) break; - if (instrtab[blk->ins.p[*curi + i]].op == Ocall2r) { - ins = &instrtab[blk->ins.p[*curi += i]]; - *ins = mkinstr(Ocopy, ins->cls, mkref(RREG, call->abiret[1].reg)); - break; - } - } - } -} - -static bool -aimm(struct addr *addr, int disp) -{ - if (addr->index.bits) return 0; - vlong a = addr->disp; - a += disp; - if ((int)a == a) { - addr->disp = a; - return 1; - } - return 0; -} - -static bool -ascale(struct addr *addr, union ref a, union ref b, uint siz/*1,2,4,8*/) -{ - if (b.t != RICON) return 0; - if (addr->index.bits || (addr->disp && !isaddrcon(addr->base,1))) return 0; - if ((unsigned)b.i > 3 || 1<index = a; - addr->shift = b.i; - return 1; - } - return 0; -} - -static bool -aadd(struct addr *addr, struct block *blk, int *curi, union ref r, uint siz/*1,2,4,8*/) -{ - if (r.t == RSTACK) { - if (addr->base.bits || addr->index.bits || !aimm(addr, -r.i)) goto Ref; - addr->base = mkref(RREG, FP); - } else if (r.t == RTMP) { - struct instr *ins = &instrtab[r.i]; - if (ins->op == Oadd) { - if (!aadd(addr, blk, curi, ins->l, siz)) goto Ref; - if (!aadd(addr, blk, curi, ins->r, siz)) goto Ref; - ins->skip = 1; - } else if (ins->op == Osub) { - if (!aadd(addr, blk, curi, ins->l, siz)) goto Ref; - if (!isintcon(ins->r)) goto Ref; - if (!aimm(addr, -intconval(ins->r))) goto Ref; - ins->skip = 1; - } else if (ins->op == Oshl) { - if (!ascale(addr, ins->l, ins->r, siz)) goto Ref; - ins->skip = 1; - } else if (ins->op == Ocopy) { - if (!aadd(addr, blk, curi, ins->l, siz)) goto Ref; - ins->skip = 1; - } else goto Ref; - } else if (isnumcon(r)) { - assert(isintcon(r)); - return aimm(addr, intconval(r)); - } else if (isaddrcon(r,1)) { - if (!addr->base.bits && !isaddrcon(addr->index,1)) addr->base = r; - else return 0; - } else if (r.t == RREG) { - /* temporaries are single assignment, but register aren't, so they can't be * - * safely hoisted into an address value, unless they have global lifetime */ - if (!rstest(mctarg->rglob, r.i)) return 0; - Ref: - if (r.t == RSTACK && (addr->base.bits || addr->index.bits)) { - r = insertinstr(blk, (*curi)++, mkinstr(Oadd, KPTR, mkref(RREG, FP), mkref(RICON, -r.i))); - } - if (!addr->base.bits) addr->base = r; - else if (!addr->index.bits) addr->index = r; - else return 0; - } else return 0; - return 1; -} - -static bool -fuseaddr(union ref *r, struct block *blk, int *curi, uint siz/*1,2,4,8*/) -{ - struct addr addr = {0}; - - if (isaddrcon(*r,1)) return 1; - - if (r->t != RSTACK && r->t != RTMP) return 0; - if (!aadd(&addr, blk, curi, *r, siz)) return 0; - if (!(addr.disp >= -256 && addr.disp < 256) /* for 9-bit signed unscaled offset */ - && !(!(addr.disp & (siz-1)) && (uvlong)addr.disp < (1<<12)*siz)) /* 12-bit unsigned scaled offset */ - return 0; - if (isaddrcon(addr.base,0) && (!(contab.p[addr.base.i].flag & SLOCAL) || addr.index.bits)) { - /* first load symbol address into a temp register */ - if (addr.disp && (ccopt.pic || (contab.p[addr.base.i].flag & SFUNC)) && !addr.index.bits) { - addr.base = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, .l = addr.base)); - } else { - addr.base = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, - mkaddr((struct addr){addr.base, .disp = addr.disp}))); - addr.disp = 0; - } - } - *r = mkaddr(addr); - return 1; -} - -static const uchar loadsz[] = { - [Oloads8 - Oloads8] = 1, [Oloadu8 - Oloads8] = 1, - [Oloads16 - Oloads8] = 2, [Oloadu16 - Oloads8] = 2, - [Oloads32 - Oloads8] = 4, [Oloadu32 - Oloads8] = 4, - [Oloadi64 - Oloads8] = 8, - [Oloadf32 - Oloads8] = 4, - [Oloadf64 - Oloads8] = 8, -}; -static const uchar storesz[] = { - [Ostorei8 - Ostorei8] = 1, - [Ostorei16 - Ostorei8] = 2, - [Ostorei32 - Ostorei8] = 4, - [Ostorei64 - Ostorei8] = 8, - [Ostoref32 - Ostorei8] = 4, - [Ostoref64 - Ostorei8] = 8, -}; -static void -loadstoreaddr(struct block *blk, union ref *r, int *curi, enum op op) -{ - uint siz = oisload(op) ? loadsz[op-Oloads8] : storesz[op-Ostorei8]; - if (isimm32(*r)) { - *r = mkaddr((struct addr){.base = *r}); - } else if (isaddrcon(*r, 0)) { - bool pcrelok = in_range(op, Oloads32, Oloadi64); /* LDR-LDRSW have PC-relative literal form */ - if (!pcrelok || !(contab.p[r->i].flag & SLOCAL)) - regarg(r, KPTR, blk, curi); - } else if (r->t == RTMP || r->t == RSTACK) { - fuseaddr(r, blk, curi, siz); - } else if (r->t != RREG) { - *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, *r)); - } -} - -static void -sel(struct function *fn, struct instr *ins, struct block *blk, int *curi) -{ - enum op op = ins->op; - enum irclass cls; - - if (oisarith(ins->op) && arithfold(ins)) { - fixarg(&ins->l, ins, blk, curi); - return; - } - - switch (op) { - //default: assert(0); - case Onop: break; - case Oalloca1: case Oalloca2: case Oalloca4: case Oalloca8: case Oalloca16: - assert(!"unlowered alloca"); - break; - case Ocopy: - fixarg(&ins->l, ins, blk, curi); - break; - case Oparam: - assert(ins->l.t == RICON && ins->l.i < fn->nabiarg); - if (!fn->abiarg[ins->l.i].isstk) - *ins = mkinstr(Ocopy, ins->cls, mkref(RREG, fn->abiarg[ins->l.i].reg)); - else /* stack */ - *ins = mkinstr(Oadd, KPTR, mkref(RREG, FP), mkref(RICON, 16+fn->abiarg[ins->l.i].stk)); - break; - case Oneg: case Onot: - case Ocvtf32s: case Ocvtf32u: - case Ocvtf32f64: case Ocvtf64s: - case Ocvtf64u: case Ocvtf64f32: - case Ocvts32f: case Ocvtu32f: - case Ocvts64f: case Ocvtu64f: - case Oexts8: case Oextu8: - case Oexts16: case Oextu16: - case Oexts32: - regarg(&ins->l, ins->cls, blk, curi); - break; - case Oextu32: - regarg(&ins->l, ins->cls, blk, curi); - ins->op = Ocopy; - break; - case Oadd: - if (isnumcon(ins->l)) { - /* swap to have const in rhs */ - union ref tmp = ins->l; - ins->l = ins->r; - ins->r = tmp; - } - case Osub: - if (ins->r.t == RICON && ins->r.i < 0) { - op = ins->op ^= 1; - ins->r.i = -ins->r.i; - } - if (!(isaddrcon(ins->l,0) && (contab.p[ins->l.i].flag & SLOCAL))) - regarg(&ins->l, ins->cls, blk, curi); - fixarg(&ins->r, ins, blk, curi); - break; - case Oand: case Oior: case Oxor: - if (isnumcon(ins->l)) { - /* swap to have const in rhs */ - union ref tmp = ins->l; - ins->l = ins->r; - ins->r = tmp; - } - case Oshl: case Osar: case Oslr: - case Oequ: case Oneq: - case Olth: case Ogth: case Olte: case Ogte: - case Oulth: case Ougth: case Oulte: case Ougte: - case Omove: - regarg(&ins->l, ins->cls, blk, curi); - fixarg(&ins->r, ins, blk, curi); - break; - case Omul: case Odiv: case Oudiv: case Ourem: - regarg(&ins->l, ins->cls, blk, curi); - regarg(&ins->r, ins->cls, blk, curi); - break; - case Oarg: - fixarg(&ins->r, ins, blk, curi); - break; - case Ocall: - selcall(fn, ins, blk, curi); - break; - case Oloads8: case Oloadu8: case Oloads16: case Oloadu16: - case Oloads32: case Oloadu32: case Oloadi64: case Oloadf32: case Oloadf64: - loadstoreaddr(blk, &ins->l, curi, op); - break; - case Ostorei8: case Ostorei16: case Ostorei32: cls = KI32; goto Store; - case Ostorei64: cls = KI64; goto Store; - case Ostoref32: cls = KF32; goto Store; - case Ostoref64: cls = KF64; Store: - loadstoreaddr(blk, &ins->l, curi, op); - regarg(&ins->r, cls, blk, curi); - break; - } -} - -static void -seljmp(struct function *fn, struct block *blk) -{ - if (blk->jmp.t == Jb && blk->jmp.arg[0].bits) { - int curi = blk->ins.n; - fixarg(&blk->jmp.arg[0], NULL, blk, &curi); - union ref c = blk->jmp.arg[0]; - if (c.t != RTMP) { - enum irclass cls = c.t == RICON ? KI32 : c.t == RXCON && contab.p[c.i].cls ? contab.p[c.i].cls : KPTR; - int curi = blk->ins.n; - - c = insertinstr(blk, blk->ins.n, mkinstr(Ocopy, cls, c)); - sel(fn, &instrtab[c.i], blk, &curi); - } - if (!oiscmp(instrtab[c.i].op)) { - enum irclass k = insrescls(instrtab[c.i]); - blk->jmp.arg[0] = insertinstr(blk, blk->ins.n, mkinstr(Oneq, k, c, kisint(k) ? ZEROREF : mkfltcon(k, 0))); - struct instr *ins = &instrtab[blk->jmp.arg[0].i]; - ins->keep = 1; - } else { - instrtab[c.i].keep = 1; - } - } else if (blk->jmp.t == Jret) { - if (blk->jmp.arg[0].bits) { - union ref r = mkref(RREG, fn->abiret[0].reg); - struct instr *ins = &instrtab[insertinstr(blk, blk->ins.n, mkinstr(Omove, fn->abiret[0].ty.cls, r, blk->jmp.arg[0])).i]; - int curi = blk->ins.n-1; - fixarg(&ins->r, ins, blk, &curi); - blk->jmp.arg[0] = r; - if (blk->jmp.arg[1].bits) { - r = mkref(RREG, fn->abiret[1].reg); - ins = &instrtab[insertinstr(blk, blk->ins.n, mkinstr(Omove, fn->abiret[1].ty.cls, r, blk->jmp.arg[1])).i]; - } - } - } -} - -void -aarch64_isel(struct function *fn) -{ - struct block *blk = fn->entry; - - do { - int i; - for (i = 0; i < blk->phi.n; ++i) { - struct instr *ins = &instrtab[blk->phi.p[i]]; - union ref *phi = phitab.p[ins->l.i]; - for (int i = 0; i < blk->npred; ++i) { - int curi = blkpred(blk, i)->ins.n; - fixarg(&phi[i], ins, blkpred(blk, i), &curi); - } - } - for (i = 0; i < blk->ins.n; ++i) { - struct instr *ins = &instrtab[blk->ins.p[i]]; - sel(fn, ins, blk, &i); - } - seljmp(fn, blk); - } while ((blk = blk->lnext) != fn->entry); - - if (ccopt.dbg.i) { - bfmt(ccopt.dbgout, "<< After isel >>\n"); - irdump(fn); - } - - fn->prop = 0; -} - -/* vim:set ts=3 sw=3 expandtab: */ -- cgit v1.2.3