diff options
| author | 2023-05-10 20:38:32 +0200 | |
|---|---|---|
| committer | 2023-05-10 20:38:32 +0200 | |
| commit | 9100ed2b5dd01df8e6b766c7bc2a12c0dd44f1ff (patch) | |
| tree | 0598b126bdddb7db462a2f0915e272d4345c0c39 /ir.c | |
initial commit
Diffstat (limited to 'ir.c')
| -rw-r--r-- | ir.c | 221 |
1 files changed, 221 insertions, 0 deletions
@@ -0,0 +1,221 @@ +#include "ir.h" +#include "common.h" + +uchar type2cls[TYARRAY + 1]; +uchar cls2siz[KF8+1]; +const uchar siz2intcls[] = { [1] = KI4, [2] = KI4, [4] = KI4, [8] = KI8 }; + +static vec_of(struct irdat) dats; +struct instr instr[1<<14]; +static int ninstr; +vec_of(struct ircall) calls; + +void +irinit(struct function *fn) +{ + static struct ircall callsbuf[64]; + + ninstr = 0; + vinit(&calls, callsbuf, arraylength(callsbuf)); + if (!type2cls[TYINT]) { + for (int i = TYCHAR; i <= TYUVLONG; ++i) { + int siz = targ_primsizes[i]; + type2cls[i] = siz < 8 ? KI4 : KI8; + } + type2cls[TYFLOAT] = KF4; + type2cls[TYDOUBLE] = KF8; + type2cls[TYPTR] = KIP; + type2cls[TYARRAY] = KIP; + cls2siz[KI4] = cls2siz[KF4] = 4; + cls2siz[KI8] = cls2siz[KF8] = 8; + cls2siz[KIP] = targ_primsizes[TYPTR]; + } + fn->entry = fn->curblk = alloc(&fn->arena, sizeof(struct block), 0); + fn->entry->lprev = fn->entry->lnext = fn->entry; +} + +struct xcon conht[1 << 12]; + +static int +addcon(const struct xcon *con) +{ + uint h = hashb(0, con, sizeof *con); + uint i = h, n = arraylength(conht); + assert(con->issym || con->cls); + for (;; ++i) { + i &= arraylength(conht) - 1; + if (!conht[i].issym && !conht[i].cls) { + conht[i] = *con; + return i; + } else if (!memcmp(&conht[i], con, sizeof *con)) { + return i; + } + assert(--n > 0 && "conht full"); + } +} + +union irref +adddat(struct function *fn, const struct irdat *dat) +{ + assert(dats.n < 1u<<29); + vpush(&dats, *dat); + /* return mkref(RDAT, dats.n - 1); */ +} + +static void +targwrite2(uchar *d, ushort x) +{ + if (targ_bigendian) + d[0] = x >> 8, d[1] = x; + else + d[0] = x, d[1] = x >> 8; +} + +static void +targwrite4(uchar *d, uint x) +{ + if (targ_bigendian) + d[0] = x >> 24, d[1] = x >> 16, d[2] = x >> 8, d[3] = x; + else + d[0] = x, d[1] = x >> 8, d[2] = x >> 16, d[3] = x >> 24; +} + +static void +targwrite8(uchar *d, uvlong x) +{ + if (targ_bigendian) + targwrite4(d, x >> 32), targwrite4(d + 4, x); + else + targwrite4(d, x), targwrite4(d + 4, x >> 32); +} + +void +conputdat(struct irdat *dat, uint off, enum typetag t, const void *src) +{ + uint siz = targ_primsizes[t]; + bool iszero = 1; + uchar *pdat; + assert(off + siz <= dat->siz); + for (uint i = 0; i < siz; ++i) { + if (((uchar *)src) != 0) { + iszero = 0; + break; + } + } + if (iszero && (dat->siz <= 8 || dat->dat.n < off)) + return; + + if (dat->siz > 8) + while (off + siz > dat->dat.n) + vpush(&dat->dat, 0); + pdat = dat->siz <= 8 ? dat->sdat : dat->dat.p; + + switch (siz) { + case 1: pdat[off] = *(uchar *)src; break; + case 2: targwrite2(&pdat[off], *(ushort *)src); break; + case 4: targwrite4(&pdat[off], *(uint *)src); break; + case 8: targwrite8(&pdat[off], *(uvlong *)src); break; + default: assert(0); + } +} + +union irtype +mkirtype(union type t) +{ + assert(t.t != TYVOID); + if (isscalar(t)) return (union irtype) { .cls = type2cls[t.t] }; + assert(isagg(t)); + return (union irtype) { .isagg = 1, .dat = t.dat }; +} + +union irref +mkintcon(struct function *fn, enum irclass k, vlong i) +{ + if (i < 1ll << 28 && i >= -(1ll << 28)) { + return mkref(RICON, i); + } else if (k == KI4) { + struct xcon con = { 0, k, .i4 = i }; + return mkref(RXCON, addcon(&con)); + } else { + struct xcon con = { 0, k, .i8 = i }; + return mkref(RXCON, addcon(&con)); + } +} + +union irref +mkfltcon(struct function *fn, enum irclass k, double f) +{ + struct xcon con = { 0, k }; + if (k == KF4) con.fs = f; + else con.fd = f; + return mkref(RXCON, addcon(&con)); +} + +union irref +mksymref(struct function *fn, const char *s) +{ + struct xcon con = { 1, KIP, .sym = s }; + return mkref(RXCON, addcon(&con)); +} + +union irref +mkcall(struct function *fn, union type fnty, uint narg, union irref *args, union irtype *typs) +{ + const struct typedata *td = &typedata[fnty.dat]; + struct ircall call = { narg, td->variadic ? td->nmemb : -1 }; + + assert(td->variadic ? narg >= td->nmemb : narg == td->nmemb); + if (narg) { + call.args = alloc(&fn->arena, narg*sizeof *args + narg*sizeof(union irtype), 0); + call.typs = (union irtype *)((char *)call.args + narg*sizeof *args); + memcpy(call.args, args, narg*sizeof *args); + memcpy(call.typs, typs, narg*sizeof *typs); + } + vpush(&calls, call); + return mkref(RCALL, calls.n-1); +} + +union irref +addinstr(struct function *fn, struct instr ins) +{ + assert(ninstr < arraylength(instr)); + assert(fn->curblk != NULL); + instr[ninstr] = ins; + vpush(&fn->curblk->ins, ninstr); + return mkref(RTMP, ninstr++); +} + +struct block * +newblk(struct function *fn) +{ + struct block *blk = alloc(&fn->arena, sizeof(struct block), 0); + memset(blk, 0, sizeof *blk); + return blk; +} + +void +useblk(struct function *fn, struct block *blk) +{ + if (fn->curblk) assert(fn->curblk->jmp.t && "never finished block"); + if (blk) assert(!blk->jmp.t && "reusing built block"); + if (!blk->lprev) { /* initialize */ + blk->lnext = fn->entry; + blk->lprev = fn->entry->lprev; + blk->lprev->lnext = blk; + blk->id = blk->lprev->id + 1; + fn->entry->lprev = blk; + } + fn->curblk = blk; +} + +void +putjump(struct function *fn, enum jumpkind j, union irref arg, struct block *t, struct block *f) +{ + fn->curblk->jmp.t = j; + fn->curblk->jmp.arg = arg; + fn->curblk->s1 = t; + fn->curblk->s2 = f; + fn->curblk = NULL; +} + +/* vim:set ts=3 sw=3 expandtab: */ |