diff options
| -rw-r--r-- | aarch64/emit.c | 10 | ||||
| -rw-r--r-- | aarch64/isel.c | 81 | ||||
| -rw-r--r-- | ir/stack.c | 9 |
3 files changed, 59 insertions, 41 deletions
diff --git a/aarch64/emit.c b/aarch64/emit.c index 217fef9..2ca3af9 100644 --- a/aarch64/emit.c +++ b/aarch64/emit.c @@ -259,15 +259,15 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o break; case EN_ADRSYMLO21: ins |= o[0].reg; - objreloc(xcon2sym(o[1].con), REL_ADR_PREL_LO21, Stext, *pcode - objout.textbegin, 0); + 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, 0); + 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, 0); + objreloc(xcon2sym(o[2].con), REL_ADD_ABS_LO12_NC, Stext, *pcode - objout.textbegin, o[1].cdisp); break; } W32(ins); @@ -463,8 +463,8 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope } } else if (val.t == RREG || val.t == RTMP) { Xorr(pcode, cls, dst, REGZR, ref2oper(val)); /* MOV Rd, Rn ==> ORR Rd, zr, Rn */ - } else if (isaddrcon(val,0)) { - struct oper sym = mkoper(OSYM, .con = val.i); + } else if (isaddrcon(val,0) || (val.t == RADDR && isaddrcon(addrht[val.i].base,0))) { + struct oper sym = mkmemoper(0, val); if ((ccopt.pic || (conht[val.i].flag & SFUNC)) && !(conht[val.i].flag & SLOCAL)) { Xadrp(pcode, KPTR, dst, sym); Xadd(pcode, KPTR, dst, dst, sym); diff --git a/aarch64/isel.c b/aarch64/isel.c index 5a8c67b..6e457d0 100644 --- a/aarch64/isel.c +++ b/aarch64/isel.c @@ -2,13 +2,6 @@ #define isimm32(r) (iscon(r) && concls(r) == KI32) -static void -picfixsym(union ref *r, struct block *blk, int *curi) -{ - if (!ccopt.pic || !isaddrcon(*r,0)) return; - *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, .l = *r)); -} - static inline uint clz(uvlong x) { @@ -73,7 +66,14 @@ aarch64_logimm(uint *enc, enum irclass k, uvlong x) *enc = outn<<12 | r<<6 | (((-d * 2) | (s - 1)) & 0x3F); } return 1; +} + +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)); } static void @@ -83,6 +83,7 @@ fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi) if (isintcon(*r)) { vlong x = intconval(*r); switch (op) { + case Ocopy: return; default: if (oiscmp(op)) { case Oadd: case Osub: @@ -97,15 +98,15 @@ fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi) break; } } - goto Copy; + goto Reg; } else if (r->t == RSTACK) { struct instr adr = mkinstr(Oadd, KPTR, mkref(RREG, FP), mkintcon(KI32, -r->i)); if (op == Ocopy) *ins = adr; else *r = insertinstr(blk, (*curi)++, adr); - } else if (r->t != RTMP) Copy: { - *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, r->t == RTMP ? instrtab[r->i].cls : ins->cls ? ins->cls : KI32, *r)); + } else if (r->t != RTMP) Reg: { + regarg(r, r->t == RTMP ? instrtab[r->i].cls : ins->cls ? ins->cls : KI32, blk, curi); } } @@ -202,7 +203,7 @@ 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) 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; @@ -266,29 +267,34 @@ fuseaddr(union ref *r, struct block *blk, int *curi, uint siz/*1,2,4,8*/) if (r->t != RSTACK && r->t != RTMP) return 0; if (!aadd(&addr, blk, curi, *r, siz)) return 0; - if (isaddrcon(addr.base,0) && (ccopt.pic || (ccopt.pie && addr.index.bits) || (conht[addr.base.i].flag & SFUNC))) { - /* pic needs to load from GOT */ - /* pie cannot encode RIP-relative address with index register */ - /* first load symbol address into a temp register */ - union ref temp = mkaddr((struct addr){.base = addr.base, .disp = ccopt.pic ? 0 : addr.disp}); - addr.base = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, .l = temp)); - if (!ccopt.pic) addr.disp = 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) && (!(conht[addr.base.i].flag & SLOCAL) || addr.index.bits)) { + /* first load symbol address into a temp register */ + if (addr.disp && (ccopt.pic || (conht[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 void -loadstoreaddr(struct block *blk, union ref *r, int *curi, uint siz) +loadstoreaddr(struct block *blk, union ref *r, int *curi, enum op op) { + uint siz = oisload(op) ? 1<<(op - Oloads8)/2 : 1<<(op - Ostore8); if (isimm32(*r)) { *r = mkaddr((struct addr){.base = *r}); } else if (isaddrcon(*r, 0)) { - picfixsym(r, blk, curi); + bool pcrelok = in_range(op, Oloads32, Oloadi64); /* LDR-LDRSW have PC-relative literal form */ + if (!pcrelok || !(conht[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) { @@ -299,9 +305,6 @@ loadstoreaddr(struct block *blk, union ref *r, int *curi, uint siz) static void sel(struct function *fn, struct instr *ins, struct block *blk, int *curi) { - uint siz, alignlog2; - int t = ins - instrtab; - struct instr temp = {0}; enum op op = ins->op; if (oisarith(ins->op) && arithfold(ins)) { @@ -315,6 +318,9 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi) 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) @@ -322,16 +328,31 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi) else /* stack */ *ins = mkinstr(Oadd, KPTR, mkref(RREG, FP), mkref(RICON, 16+fn->abiarg[ins->l.i].stk)); break; - case Oadd: case Osub: + 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; } - fixarg(&ins->l, ins, blk, curi); + if (!(isaddrcon(ins->l,0) && (conht[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: + regarg(&ins->l, ins->cls, blk, curi); fixarg(&ins->r, ins, blk, curi); break; case Omul: case Odiv: @@ -343,6 +364,7 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi) case Oequ: case Oneq: case Olth: case Ogth: case Olte: case Ogte: case Oulth: case Ougth: case Oulte: case Ougte: + regarg(&ins->l, ins->cls, blk, curi); fixarg(&ins->r, ins, blk, curi); break; case Oarg: @@ -353,11 +375,11 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi) break; case Oloads8: case Oloadu8: case Oloads16: case Oloadu16: case Oloads32: case Oloadu32: case Oloadi64: - loadstoreaddr(blk, &ins->l, curi, 1<<((op - Oloads8)/2)); + loadstoreaddr(blk, &ins->l, curi, op); break; case Ostore8: case Ostore16: case Ostore32: case Ostore64: - loadstoreaddr(blk, &ins->l, curi, 1<<(op - Ostore8)); - fixarg(&ins->r, ins, blk, curi); + loadstoreaddr(blk, &ins->l, curi, op); + regarg(&ins->r, op == Ostore64 ? KI64 : KI32, blk, curi); break; } } @@ -408,7 +430,6 @@ aarch64_isel(struct function *fn) extern int ninstr; struct block *blk = fn->entry; - fn->stksiz = 0; do { int i; for (i = 0; i < blk->phi.n; ++i) { @@ -10,20 +10,17 @@ lowerstack(struct function *fn) struct block *blk = fn->entry; do { for (int i = 0; i < blk->ins.n; ++i) { - uint alignlog2, siz; int t = blk->ins.p[i]; struct instr *ins = &instrtab[t]; - switch (ins->op) { - case Oalloca1: case Oalloca2: case Oalloca4: case Oalloca8: case Oalloca16: - alignlog2 = ins->op - Oalloca1; + if (oisalloca(ins->op)) { + uint alignlog2 = ins->op - Oalloca1; assert(ins->l.i > 0); - siz = ins->l.i << alignlog2; + uint siz = ins->l.i << alignlog2; fn->stksiz += siz; fn->stksiz = alignup(fn->stksiz, 1 << alignlog2); if (fn->stksiz > (1<<16)-1) error(NULL, "'%s' stack frame too big", fn->name); *ins = mkinstr(Onop,0,); replcuses(mkref(RTMP, t), mkref(RSTACK, fn->stksiz)); - continue; } } } while ((blk = blk->lnext) != fn->entry); |