aboutsummaryrefslogtreecommitdiffhomepage
path: root/aarch64
diff options
context:
space:
mode:
Diffstat (limited to 'aarch64')
-rw-r--r--aarch64/aapcs.c77
-rw-r--r--aarch64/all.h16
-rw-r--r--aarch64/emit.c1023
-rw-r--r--aarch64/isel.c515
4 files changed, 0 insertions, 1631 deletions
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<<addr->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 <sym> */
- EN_ADRSYMPGHI21, /* for ADRP <sym:pghi21> */
- EN_ADDSYMLO12, /* for ADD x,x, <sym:lo12> */
- 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 <rel26> */
- } 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, <invcond> */
- }
- 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<<b.i != siz) return 0;
- if (a.t == RREG || a.t == RTMP) {
- addr->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: */