diff options
| author | 2026-01-02 14:40:06 +0100 | |
|---|---|---|
| committer | 2026-01-02 14:40:06 +0100 | |
| commit | 12974932af785a2ab2cefb5bc80da3ee1211e3c3 (patch) | |
| tree | f845c7e05b8a95151141e0b627d729e4ce4aea74 | |
| parent | ba1f40078b458a3071bd847e820f951f8231523b (diff) | |
aarch64: LDR literal, cmp value
| -rw-r--r-- | aarch64/emit.c | 41 | ||||
| -rw-r--r-- | obj/elf.c | 2 | ||||
| -rw-r--r-- | obj/obj.h | 1 |
3 files changed, 34 insertions, 10 deletions
diff --git a/aarch64/emit.c b/aarch64/emit.c index 11ee552..8fe3677 100644 --- a/aarch64/emit.c +++ b/aarch64/emit.c @@ -51,6 +51,8 @@ mkmemoper(uint msiz, union ref r) 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 = &addrht[r.i]; assert(addr->shift <= 3 && (!addr->disp || !addr->index.bits)); @@ -137,12 +139,13 @@ enum operenc { EN_ADRSYMLO21, /* for ADR <sym> */ EN_ADRSYMPGHI21, /* for ADRP <sym:pghi21> */ EN_ADDSYMLO12, /* for ADD x,x, <sym:lo12> */ - EN_FP2R, - EN_FP1GPR1, - EN_FP3R, - EN_FPIMM, - EN_FPCMPZ, - EN_FPCMP, + 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} */ @@ -273,6 +276,10 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o 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; @@ -385,6 +392,8 @@ DEFINSTR2(Xldr, {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}, ) @@ -634,6 +643,8 @@ emitbranch(uchar **pcode, struct block *blk) 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) { @@ -726,12 +737,21 @@ emitinstr(uchar **pcode, struct function *fn, struct block *blk, int curi, struc case Oequ: case Oneq: if (!ins->reg && kisint(cls) && ins->r.bits == ZEROREF.bits) break; /* handled by emitbranch for CBZ/CBNZ */ case Olth: case Ogth: case Olte: case Ogte: - if (kisflt(cls)) - Xfcmp(pcode, cls, ref2oper(ins->l), ref2oper(ins->r)); - else case Oulth: case Ougth: case Oulte: case Ougte: - /* CMP ... ==> SUBS zr, ... */ + 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; @@ -887,6 +907,7 @@ emitbin(struct function *fn) 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) { @@ -151,9 +151,11 @@ static const ushort relktab[][NRELOCKIND] = { [REL_PCREL32] = 261, /* R_AARCH64_PREL2 */ [REL_PLT32] = 314, /* R_AARCH64_PLT32 */ [REL_CALL26] = 283, /* R_AARCH64_CALL26 */ + [REL_LD_PREL_LO19] = 273, /* R_AARCH64_LD_PREL_LO19 */ [REL_ADR_PREL_LO21] = 274, /* R_AARCH64_ADR_PREL_LO21 */ [REL_ADR_PREL_PG_HI21] = 276, /* R_AARCH64_ADR_PREL_PG_HI21_NC */ [REL_ADD_ABS_LO12_NC] = 277, /* R_AARCH64_ADD_ABS_LO12_NC */ + } }; @@ -21,6 +21,7 @@ enum relockind { REL_ADR_PREL_LO21, REL_ADR_PREL_PG_HI21, REL_ADD_ABS_LO12_NC, + REL_LD_PREL_LO19, NRELOCKIND, }; enum section { Snone, Stext, Srodata, Sdata, Sbss }; |