From ad8067a1ab1871cf57936828fb1b40c15cd3349d Mon Sep 17 00:00:00 2001 From: lemon Date: Thu, 19 Feb 2026 20:29:16 +0100 Subject: IR: just use an array for extended constants The extra work of using a hashtable to intern them is probably unnecessary. --- aarch64/emit.c | 12 ++++++------ aarch64/isel.c | 16 ++++++++-------- ir/dump.c | 2 +- ir/inliner.c | 7 +++---- ir/ir.c | 36 ++++++++++++------------------------ ir/ir.h | 15 ++++++++------- ir/ssa.c | 2 +- x86_64/emit.c | 22 +++++++++++----------- x86_64/isel.c | 8 ++++---- 9 files changed, 54 insertions(+), 66 deletions(-) diff --git a/aarch64/emit.c b/aarch64/emit.c index d49906e..6db1bd6 100644 --- a/aarch64/emit.c +++ b/aarch64/emit.c @@ -86,12 +86,12 @@ ref2oper(union ref r) case RREG: return reg2oper(r.i); case RICON: return mkoper(OIMM, .imm = r.i); case RXCON: - if (kisint(conht[r.i].cls)) - return mkoper(OIMM, .imm = conht[r.i].i); - else if (kisflt(conht[r.i].cls)) { - assert(conht[r.i].f == 0.0); + 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 (!conht[r.i].cls) { + } else if (!contab.p[r.i].cls) { return mkoper(OSYM, .con = r.i); } assert(0); @@ -553,7 +553,7 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope Xfmov(pcode, cls, dst, REGZR); else assert(0); } else if (isaddrcon(val,0) || (val.t == RADDR && isaddrcon(addrht[val.i].base,0))) { - if ((ccopt.pic || (conht[val.i].flag & SFUNC)) && !(conht[val.i].flag & SLOCAL)) { + 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 { diff --git a/aarch64/isel.c b/aarch64/isel.c index 390793b..bcabf2c 100644 --- a/aarch64/isel.c +++ b/aarch64/isel.c @@ -108,7 +108,7 @@ fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi) goto Reg; } else if (isfltcon(*r)) { enum irclass k = concls(*r), ki = KI32 + k-KF32; - if (conht[r->i].f != 0.0) { + if (contab.p[r->i].f != 0.0) { union { vlong i64; int i32; @@ -117,10 +117,10 @@ fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi) } pun; vlong i; if (k == KF32) { - pun.f32 = conht[r->i].f; + pun.f32 = contab.p[r->i].f; i = pun.i32; } else { - pun.f64 = conht[r->i].f; + pun.f64 = contab.p[r->i].f; i = pun.i64; } union ref gpr = insertinstr(blk, (*curi)++, mkinstr(Ocopy, ki, mkintcon(ki, i))); @@ -301,9 +301,9 @@ fuseaddr(union ref *r, struct block *blk, int *curi, uint siz/*1,2,4,8*/) 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)) { + 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 || (conht[addr.base.i].flag & SFUNC)) && !addr.index.bits) { + 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, @@ -339,7 +339,7 @@ loadstoreaddr(struct block *blk, union ref *r, int *curi, enum op op) *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 || !(conht[r->i].flag & SLOCAL)) + 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); @@ -390,7 +390,7 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi) op = ins->op ^= 1; ins->r.i = -ins->r.i; } - if (!(isaddrcon(ins->l,0) && (conht[ins->l.i].flag & SLOCAL))) + 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; @@ -445,7 +445,7 @@ seljmp(struct function *fn, struct block *blk) 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 && conht[c.i].cls ? conht[c.i].cls : KPTR; + 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)); diff --git a/ir/dump.c b/ir/dump.c index cf8d788..bb6a2fd 100644 --- a/ir/dump.c +++ b/ir/dump.c @@ -107,7 +107,7 @@ dumpref(enum op o, union ref ref) else bfmt(out, "%d", ref.i); break; case RXCON: - con = &conht[ref.i]; + con = &contab.p[ref.i]; if (con->deref) bfmt(out, "*["); if (con->issym || con->isdat) { bfmt(out, "$%y", xcon2sym(ref.i)); diff --git a/ir/inliner.c b/ir/inliner.c index 0853d26..2ce817b 100644 --- a/ir/inliner.c +++ b/ir/inliner.c @@ -4,7 +4,7 @@ struct savedfunc { int mark; uint ninstr; struct instr *instrtab; - struct xcon *conht; + struct xcon *contab; struct call *calltab; union ref **phitab; struct block *entry; @@ -82,7 +82,7 @@ maybeinlinee(struct function *fn) } while ((b = b->lnext)); sv->instrtab = alloccopy(&savearena, instrtab, sizeof *instrtab * (sv->ninstr = ninstr), 0); - sv->conht = alloccopy(&savearena, conht, sizeof *conht * (1<<12), 0); // HACK + sv->contab = alloccopy(&savearena, contab.p, sizeof *contab.p * contab.n, 0); if (calltab.n) { sv->calltab = alloccopy(&savearena, calltab.p, sizeof *calltab.p * calltab.n, 0); for (int i = 0; i < calltab.n; ++i) { @@ -104,9 +104,8 @@ maybeinlinee(struct function *fn) static union ref mapref(short *instrmap, struct savedfunc *sv, union ref r) { - int newcon(const struct xcon *con); if (r.t == RTMP) return r.i = instrmap[r.i], r; - if (r.t == RXCON) return r.i = newcon(&sv->conht[r.i]), r; + if (r.t == RXCON) return newxcon(&sv->contab[r.i]); assert(r.t != RADDR); assert(r.t != RSTACK); return r; diff --git a/ir/ir.c b/ir/ir.c index 01d8060..b5f9de8 100644 --- a/ir/ir.c +++ b/ir/ir.c @@ -35,10 +35,9 @@ static struct arena **usearena; struct calltab calltab; struct phitab phitab; struct dattab dattab; +struct contab contab; struct addr addrht[1 << 12]; static int naddrht; -struct xcon conht[1 << 12]; -static int nconht; int visitmark; void @@ -47,6 +46,7 @@ irinit(struct function *fn) static struct call callsbuf[64]; static union ref *phisbuf[64]; static struct irdat datsbuf[64]; + static struct xcon consbuf[64]; assert(fn->arena && !fn->passarena); @@ -57,11 +57,10 @@ irinit(struct function *fn) vinit(&calltab, callsbuf, countof(callsbuf)); for (int i = 0; i < phitab.n; ++i) xbfree(phitab.p[i]); vinit(&phitab, phisbuf, countof(phisbuf)); + vinit(&contab, consbuf, countof(consbuf)); if (!dattab.p) vinit(&dattab, datsbuf, countof(datsbuf)); if (naddrht >= countof(addrht)/2) memset(addrht, naddrht = 0, sizeof addrht); - if (nconht >= countof(conht)/2) - memset(conht, nconht = 0, sizeof conht); if (!type2cls[TYINT]) { for (int i = TYBOOL; i <= TYUVLONG; ++i) { int siz = targ_primsizes[i]; @@ -100,23 +99,12 @@ newaddr(const struct addr *addr) } } -int -newcon(const struct xcon *con) +union ref +newxcon(const struct xcon *con) { - uint h = hashb(0, con, sizeof *con); - uint i = h, n = countof(conht); assert((con->issym ^ con->isdat) || con->cls); - for (;; ++i) { - i &= countof(conht) - 1; - if (!conht[i].issym && !conht[i].isdat && !conht[i].cls) { - conht[i] = *con; - ++nconht; - return i; - } else if (!memcmp(&conht[i], con, sizeof *con)) { - return i; - } - assert(--n > 0 && "conht full"); - } + vpush(&contab, *con); + return mkref(RXCON, contab.n-1); } union irtype @@ -137,7 +125,7 @@ mkintcon(enum irclass k, vlong i) struct xcon con = { .cls = k, .i = i }; if (cls2siz[k] == 4) /* check upper half is zero or -1 */ assert(in_range((i >> 32) + 1, 0, 1)); - return mkref(RXCON, newcon(&con)); + return newxcon(&con); } } @@ -145,14 +133,14 @@ union ref mkfltcon(enum irclass k, double f) { struct xcon con = { .cls = k, .f = k == KF32 ? (float) f : f }; - return mkref(RXCON, newcon(&con)); + return newxcon(&con); } union ref mksymref(internstr s, enum symflags symflags) { struct xcon con = { .issym = 1, .sym = s, .flag = symflags }; - return mkref(RXCON, newcon(&con)); + return newxcon(&con); } union ref @@ -176,13 +164,13 @@ mkdatref(internstr name, union type ctype, uint siz, uint align, const void *byt if (n) memcpy(p, bytes, n); if (dat.section != Stext) memset(p+n, 0, siz - n); vpush(&dattab, dat); - return mkref(RXCON, newcon(&(struct xcon){.isdat = 1, .deref = deref, .dat = dattab.n - 1, .flag = SLOCAL})); + return newxcon(&(struct xcon){.isdat = 1, .deref = deref, .dat = dattab.n - 1, .flag = SLOCAL}); } internstr xcon2sym(int ref) { - struct xcon con = conht[ref]; + struct xcon con = contab.p[ref]; assert(con.issym ^ con.isdat); return con.issym ? con.sym : dattab.p[con.dat].name; } diff --git a/ir/ir.h b/ir/ir.h index 73a50bd..c7abaa7 100644 --- a/ir/ir.h +++ b/ir/ir.h @@ -241,10 +241,10 @@ extern uchar cls2store[]; extern const uchar siz2intcls[]; extern struct instr instrtab[]; extern struct use *instruse[]; -extern struct xcon conht[]; extern struct calltab {vec_of(struct call);} calltab; extern struct phitab {vec_of(union ref *);} phitab; extern struct dattab {vec_of(struct irdat);} dattab; +extern struct contab {vec_of(struct xcon);} contab; extern struct addr addrht[]; extern int visitmark; #define mkinstr(O, C, ...) ((struct instr) { .op = (O), .cls = (C), .reg=0, __VA_ARGS__ }) @@ -253,16 +253,17 @@ void irinit(struct function *); void irfini(struct function *); #define cls2type(k) ((union irtype){.cls=(k)}) union irtype mkirtype(union type); +union ref newxcon(const struct xcon *); union ref mkintcon(enum irclass, vlong); union ref mkfltcon(enum irclass, double); #define iscon(r) in_range((r).t, RICON, RXCON) -#define concls(r) ((r).t == RICON ? KI32 : conht[(r).i].cls) +#define concls(r) ((r).t == RICON ? KI32 : contab.p[(r).i].cls) #define isintcon(r) (iscon(r) && kisint(concls(r))) -#define isfltcon(r) ((r).t == RXCON && kisflt(conht[(r).i].cls)) -#define isnumcon(r) ((r).t == RICON || ((r).t == RXCON && conht[(r).i].cls)) -#define isaddrcon(r,derefok) ((r).t == RXCON && !conht[(r).i].cls && (derefok || !conht[(r).i].deref)) -#define intconval(r) ((r).t == RICON ? (r).i : conht[(r).i].i) -#define fltconval(r) ((r).t == RICON ? (r).i : conht[(r).i].f) +#define isfltcon(r) ((r).t == RXCON && kisflt(contab.p[(r).i].cls)) +#define isnumcon(r) ((r).t == RICON || ((r).t == RXCON && contab.p[(r).i].cls)) +#define isaddrcon(r,derefok) ((r).t == RXCON && !contab.p[(r).i].cls && (derefok || !contab.p[(r).i].deref)) +#define intconval(r) ((r).t == RICON ? (r).i : contab.p[(r).i].i) +#define fltconval(r) ((r).t == RICON ? (r).i : contab.p[(r).i].f) union ref mksymref(internstr, enum symflags); union ref mkdatref(internstr name, union type ctype, uint siz, uint align, const void *, uint n, bool deref); internstr xcon2sym(int ref); diff --git a/ir/ssa.c b/ir/ssa.c index 9d248f4..6598fba 100644 --- a/ir/ssa.c +++ b/ir/ssa.c @@ -30,7 +30,7 @@ copyopt(struct function *fn) union ref arg = ins->l; if (arg.t == RTMP) k = insrescls(instrtab[arg.i]); else if (arg.t == RICON) k = cls2siz[ins->cls] == 4 ? KI32 : KI64; - else if (arg.t == RXCON) k = isnumcon(arg) ? conht[arg.i].cls : KPTR; + else if (arg.t == RXCON) k = isnumcon(arg) ? concls(arg) : KPTR; else continue; if (ins->cls != k) continue; diff --git a/x86_64/emit.c b/x86_64/emit.c index 17ea1f3..0d7b77a 100644 --- a/x86_64/emit.c +++ b/x86_64/emit.c @@ -46,13 +46,13 @@ ref2oper(union ref r) case RREG: return reg2oper(r.i); case RICON: return mkoper(OIMM, .imm = r.i); case RXCON: - if (conht[r.i].cls == KI32) - return mkoper(OIMM, .imm = conht[r.i].i); - else if (conht[r.i].cls == KI64) { - vlong i = conht[r.i].i; + if (contab.p[r.i].cls == KI32) + return mkoper(OIMM, .imm = contab.p[r.i].i); + else if (contab.p[r.i].cls == KI64) { + vlong i = contab.p[r.i].i; assert(i == (int)i); return mkoper(OIMM, .imm = i); - } else if (!conht[r.i].cls) { + } else if (!contab.p[r.i].cls) { return mkoper(OSYM, .con = r.i, .cindex = NOINDEX); } assert(0); @@ -107,14 +107,14 @@ mkimmregoper(union ref r) static inline struct oper mkdatregoper(union ref r) { - assert(isregref(r) || (r.t == RXCON && conht[r.i].deref)); + assert(isregref(r) || (r.t == RXCON && contab.p[r.i].deref)); return ref2oper(r); } static inline struct oper mkimmdatregoper(union ref r) { - assert(isregref(r) || r.t == RICON || (r.t == RXCON && (conht[r.i].cls == KI32 || conht[r.i].deref))); + assert(isregref(r) || r.t == RICON || (r.t == RXCON && (contab.p[r.i].cls == KI32 || contab.p[r.i].deref))); return ref2oper(r); } @@ -151,7 +151,7 @@ mkmemoper(union ref r) .disp = addr->disp, .shift = addr->shift); } else if (r.t == RXCON) { - assert(!conht[r.i].cls); + assert(!contab.p[r.i].cls); return mkoper(OSYM, .con = r.i, .cindex = NOINDEX); } else { return mkoper(OMEM, .base = isregref(r) ? ref2oper(r).reg : NOBASE, @@ -869,8 +869,8 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope } /* normal (not 2-address) case */ Lea: - if (isaddrcon(addr->base,0) && (ccopt.pic || (conht[addr->base.i].flag & SFUNC)) - && !(conht[addr->base.i].flag & SLOCAL)) { + if (isaddrcon(addr->base,0) && (ccopt.pic || (contab.p[addr->base.i].flag & SFUNC)) + && !(contab.p[addr->base.i].flag & SLOCAL)) { assert(!addr->disp && !addr->index.bits); val = addr->base; goto GOTLoad; @@ -880,7 +880,7 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope /* dst = 0 -> xor dst, dst; but only if it is ok to clobber flags */ Xxor(pcode, kisint(cls) ? KI32 : cls, dst, dst); } else if (isaddrcon(val,0)) { - if ((ccopt.pic || (conht[val.i].flag & SFUNC)) && !(conht[val.i].flag & SLOCAL)) { + if ((ccopt.pic || (contab.p[val.i].flag & SFUNC)) && !(contab.p[val.i].flag & SLOCAL)) { GOTLoad: /* for mov reg, [rip(sym@GOTPCREL)] */ Xmov(pcode, cls, dst, mkoper(OSYMGOT, .con = val.i, .cindex = NOINDEX)); diff --git a/x86_64/isel.c b/x86_64/isel.c index 3faa7fc..7f82984 100644 --- a/x86_64/isel.c +++ b/x86_64/isel.c @@ -54,7 +54,7 @@ fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi) enum op op = ins ? ins->op : 0; if (r->t == RXCON) { - struct xcon *con = &conht[r->i]; + struct xcon *con = &contab.p[r->i]; if (in_range(op, Oshl, Oslr) && r == &ins->r) { sh = con->i; goto ShiftImm; @@ -293,7 +293,7 @@ fuseaddr(union ref *r, struct block *blk, int *curi) if (r->t != RSTACK && r->t != RTMP) return 0; if (!aadd(&addr, blk, curi, *r)) return 0; - if (isaddrcon(addr.base,0) && (ccopt.pic || (ccopt.pie && addr.index.bits) || (conht[addr.base.i].flag & SFUNC))) { + if (isaddrcon(addr.base,0) && (ccopt.pic || (ccopt.pie && addr.index.bits) || (contab.p[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 */ @@ -318,7 +318,7 @@ static bool addarg4addrp(union ref r) { struct instr *ins; - if (r.t == RXCON && !conht[r.i].cls && !conht[r.i].deref) return 1; /* sym or dat ref */ + if (r.t == RXCON && !contab.p[r.i].cls && !contab.p[r.i].deref) return 1; /* sym or dat ref */ if (r.t == RSTACK) return 1; if (r.t != RTMP) return 0; ins = &instrtab[r.i]; @@ -574,7 +574,7 @@ seljmp(struct function *fn, struct block *blk) 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 && conht[c.i].cls ? conht[c.i].cls : KPTR; + 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)); -- cgit v1.2.3