| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763 |
- #include "all.h"
- #include <stdarg.h>
- typedef struct Bitset Bitset;
- typedef struct Vec Vec;
- typedef struct Bucket Bucket;
- struct Vec {
- ulong mag;
- Pool pool;
- size_t esz;
- ulong cap;
- union {
- long long ll;
- long double ld;
- void *ptr;
- } align[];
- };
- struct Bucket {
- uint nstr;
- char **str;
- };
- enum {
- VMin = 2,
- VMag = 0xcabba9e,
- NPtr = 256,
- IBits = 12,
- IMask = (1<<IBits) - 1,
- };
- Typ *typ;
- Ins insb[NIns], *curi;
- static void *ptr[NPtr];
- static void **pool = ptr;
- static int nptr = 1;
- static Bucket itbl[IMask+1]; /* string interning table */
- uint32_t
- hash(char *s)
- {
- uint32_t h;
- for (h=0; *s; ++s)
- h = *s + 17*h;
- return h;
- }
- void
- die_(char *file, char *s, ...)
- {
- va_list ap;
- fprintf(stderr, "%s: dying: ", file);
- va_start(ap, s);
- vfprintf(stderr, s, ap);
- va_end(ap);
- fputc('\n', stderr);
- abort();
- }
- void *
- emalloc(size_t n)
- {
- void *p;
- p = calloc(1, n);
- if (!p)
- die("emalloc, out of memory");
- return p;
- }
- void *
- alloc(size_t n)
- {
- void **pp;
- if (n == 0)
- return 0;
- if (nptr >= NPtr) {
- pp = emalloc(NPtr * sizeof(void *));
- pp[0] = pool;
- pool = pp;
- nptr = 1;
- }
- return pool[nptr++] = emalloc(n);
- }
- void
- freeall()
- {
- void **pp;
- for (;;) {
- for (pp = &pool[1]; pp < &pool[nptr]; pp++)
- free(*pp);
- pp = pool[0];
- if (!pp)
- break;
- free(pool);
- pool = pp;
- nptr = NPtr;
- }
- nptr = 1;
- }
- void *
- vnew(ulong len, size_t esz, Pool pool)
- {
- void *(*f)(size_t);
- ulong cap;
- Vec *v;
- for (cap=VMin; cap<len; cap*=2)
- ;
- f = pool == PHeap ? emalloc : alloc;
- v = f(cap * esz + sizeof(Vec));
- v->mag = VMag;
- v->cap = cap;
- v->esz = esz;
- v->pool = pool;
- return v + 1;
- }
- void
- vfree(void *p)
- {
- Vec *v;
- v = (Vec *)p - 1;
- assert(v->mag == VMag);
- if (v->pool == PHeap) {
- v->mag = 0;
- free(v);
- }
- }
- void
- vgrow(void *vp, ulong len)
- {
- Vec *v;
- void *v1;
- v = *(Vec **)vp - 1;
- assert(v+1 && v->mag == VMag);
- if (v->cap >= len)
- return;
- v1 = vnew(len, v->esz, v->pool);
- memcpy(v1, v+1, v->cap * v->esz);
- vfree(v+1);
- *(Vec **)vp = v1;
- }
- void
- addins(Ins **pvins, uint *pnins, Ins *i)
- {
- if (i->op == Onop)
- return;
- vgrow(pvins, ++(*pnins));
- (*pvins)[(*pnins)-1] = *i;
- }
- void
- addbins(Blk *b, Ins **pvins, uint *pnins)
- {
- Ins *i;
- for (i=b->ins; i<&b->ins[b->nins]; i++)
- addins(pvins, pnins, i);
- }
- void
- strf(char str[NString], char *s, ...)
- {
- va_list ap;
- va_start(ap, s);
- vsnprintf(str, NString, s, ap);
- va_end(ap);
- }
- uint32_t
- intern(char *s)
- {
- Bucket *b;
- uint32_t h;
- uint i, n;
- h = hash(s) & IMask;
- b = &itbl[h];
- n = b->nstr;
- for (i=0; i<n; i++)
- if (strcmp(s, b->str[i]) == 0)
- return h + (i<<IBits);
- if (n == 1<<(32-IBits))
- die("interning table overflow");
- if (n == 0)
- b->str = vnew(1, sizeof b->str[0], PHeap);
- else if ((n & (n-1)) == 0)
- vgrow(&b->str, n+n);
- b->str[n] = emalloc(strlen(s)+1);
- b->nstr = n + 1;
- strcpy(b->str[n], s);
- return h + (n<<IBits);
- }
- char *
- str(uint32_t id)
- {
- assert(id>>IBits < itbl[id&IMask].nstr);
- return itbl[id&IMask].str[id>>IBits];
- }
- int
- isreg(Ref r)
- {
- return rtype(r) == RTmp && r.val < Tmp0;
- }
- int
- iscmp(int op, int *pk, int *pc)
- {
- if (Ocmpw <= op && op <= Ocmpw1) {
- *pc = op - Ocmpw;
- *pk = Kw;
- }
- else if (Ocmpl <= op && op <= Ocmpl1) {
- *pc = op - Ocmpl;
- *pk = Kl;
- }
- else if (Ocmps <= op && op <= Ocmps1) {
- *pc = NCmpI + op - Ocmps;
- *pk = Ks;
- }
- else if (Ocmpd <= op && op <= Ocmpd1) {
- *pc = NCmpI + op - Ocmpd;
- *pk = Kd;
- }
- else
- return 0;
- return 1;
- }
- void
- igroup(Blk *b, Ins *i, Ins **i0, Ins **i1)
- {
- Ins *ib, *ie;
- ib = b->ins;
- ie = ib + b->nins;
- switch (i->op) {
- case Oblit0:
- *i0 = i;
- *i1 = i + 2;
- return;
- case Oblit1:
- *i0 = i - 1;
- *i1 = i + 1;
- return;
- case_Opar:
- for (; i>ib && ispar((i-1)->op); i--)
- ;
- *i0 = i;
- for (; i<ie && ispar(i->op); i++)
- ;
- *i1 = i;
- return;
- case Ocall:
- case_Oarg:
- for (; i>ib && isarg((i-1)->op); i--)
- ;
- *i0 = i;
- for (; i<ie && i->op != Ocall; i++)
- ;
- assert(i < ie);
- *i1 = i + 1;
- return;
- default:
- if (ispar(i->op))
- goto case_Opar;
- if (isarg(i->op))
- goto case_Oarg;
- *i0 = i;
- *i1 = i + 1;
- return;
- }
- }
- int
- argcls(Ins *i, int n)
- {
- return optab[i->op].argcls[n][i->cls];
- }
- void
- emit(int op, int k, Ref to, Ref arg0, Ref arg1)
- {
- if (curi == insb)
- die("emit, too many instructions");
- *--curi = (Ins){
- .op = op, .cls = k,
- .to = to, .arg = {arg0, arg1}
- };
- }
- void
- emiti(Ins i)
- {
- emit(i.op, i.cls, i.to, i.arg[0], i.arg[1]);
- }
- void
- idup(Blk *b, Ins *s, ulong n)
- {
- vgrow(&b->ins, n);
- icpy(b->ins, s, n);
- b->nins = n;
- }
- Ins *
- icpy(Ins *d, Ins *s, ulong n)
- {
- if (n)
- memmove(d, s, n * sizeof(Ins));
- return d + n;
- }
- static int cmptab[][2] ={
- /* negation swap */
- [Ciule] = {Ciugt, Ciuge},
- [Ciult] = {Ciuge, Ciugt},
- [Ciugt] = {Ciule, Ciult},
- [Ciuge] = {Ciult, Ciule},
- [Cisle] = {Cisgt, Cisge},
- [Cislt] = {Cisge, Cisgt},
- [Cisgt] = {Cisle, Cislt},
- [Cisge] = {Cislt, Cisle},
- [Cieq] = {Cine, Cieq},
- [Cine] = {Cieq, Cine},
- [NCmpI+Cfle] = {NCmpI+Cfgt, NCmpI+Cfge},
- [NCmpI+Cflt] = {NCmpI+Cfge, NCmpI+Cfgt},
- [NCmpI+Cfgt] = {NCmpI+Cfle, NCmpI+Cflt},
- [NCmpI+Cfge] = {NCmpI+Cflt, NCmpI+Cfle},
- [NCmpI+Cfeq] = {NCmpI+Cfne, NCmpI+Cfeq},
- [NCmpI+Cfne] = {NCmpI+Cfeq, NCmpI+Cfne},
- [NCmpI+Cfo] = {NCmpI+Cfuo, NCmpI+Cfo},
- [NCmpI+Cfuo] = {NCmpI+Cfo, NCmpI+Cfuo},
- };
- int
- cmpneg(int c)
- {
- assert(0 <= c && c < NCmp);
- return cmptab[c][0];
- }
- int
- cmpop(int c)
- {
- assert(0 <= c && c < NCmp);
- return cmptab[c][1];
- }
- int
- cmpwlneg(int op)
- {
- if (INRANGE(op, Ocmpw, Ocmpw1))
- return cmpneg(op - Ocmpw) + Ocmpw;
- if (INRANGE(op, Ocmpl, Ocmpl1))
- return cmpneg(op - Ocmpl) + Ocmpl;
- die("not a wl comparison");
- }
- int
- clsmerge(short *pk, short k)
- {
- short k1;
- k1 = *pk;
- if (k1 == Kx) {
- *pk = k;
- return 0;
- }
- if ((k1 == Kw && k == Kl) || (k1 == Kl && k == Kw)) {
- *pk = Kw;
- return 0;
- }
- return k1 != k;
- }
- int
- phicls(int t, Tmp *tmp)
- {
- int t1;
- t1 = tmp[t].phi;
- if (!t1)
- return t;
- t1 = phicls(t1, tmp);
- tmp[t].phi = t1;
- return t1;
- }
- uint
- phiargn(Phi *p, Blk *b)
- {
- uint n;
- if (p)
- for (n=0; n<p->narg; n++)
- if (p->blk[n] == b)
- return n;
- return -1;
- }
- Ref
- phiarg(Phi *p, Blk *b)
- {
- uint n;
- n = phiargn(p, b);
- assert(n != -1u && "block not found");
- return p->arg[n];
- }
- Ref
- newtmp(char *prfx, int k, Fn *fn)
- {
- static int n;
- int t;
- t = fn->ntmp++;
- vgrow(&fn->tmp, fn->ntmp);
- memset(&fn->tmp[t], 0, sizeof(Tmp));
- if (prfx)
- strf(fn->tmp[t].name, "%s.%d", prfx, ++n);
- fn->tmp[t].cls = k;
- fn->tmp[t].slot = -1;
- fn->tmp[t].nuse = +1;
- fn->tmp[t].ndef = +1;
- return TMP(t);
- }
- void
- chuse(Ref r, int du, Fn *fn)
- {
- if (rtype(r) == RTmp)
- fn->tmp[r.val].nuse += du;
- }
- int
- symeq(Sym s0, Sym s1)
- {
- return s0.type == s1.type && s0.id == s1.id;
- }
- Ref
- newcon(Con *c0, Fn *fn)
- {
- Con *c1;
- int i;
- for (i=1; i<fn->ncon; i++) {
- c1 = &fn->con[i];
- if (c0->type == c1->type
- && symeq(c0->sym, c1->sym)
- && c0->bits.i == c1->bits.i)
- return CON(i);
- }
- vgrow(&fn->con, ++fn->ncon);
- fn->con[i] = *c0;
- return CON(i);
- }
- Ref
- getcon(int64_t val, Fn *fn)
- {
- int c;
- for (c=1; c<fn->ncon; c++)
- if (fn->con[c].type == CBits
- && fn->con[c].bits.i == val)
- return CON(c);
- vgrow(&fn->con, ++fn->ncon);
- fn->con[c] = (Con){.type = CBits, .bits.i = val};
- return CON(c);
- }
- int
- addcon(Con *c0, Con *c1, int m)
- {
- if (m != 1 && c1->type == CAddr)
- return 0;
- if (c0->type == CUndef) {
- *c0 = *c1;
- c0->bits.i *= m;
- } else {
- if (c1->type == CAddr) {
- if (c0->type == CAddr)
- return 0;
- c0->type = CAddr;
- c0->sym = c1->sym;
- }
- c0->bits.i += c1->bits.i * m;
- }
- return 1;
- }
- int
- isconbits(Fn *fn, Ref r, int64_t *v)
- {
- Con *c;
- if (rtype(r) == RCon) {
- c = &fn->con[r.val];
- if (c->type == CBits) {
- *v = c->bits.i;
- return 1;
- }
- }
- return 0;
- }
- void
- salloc(Ref rt, Ref rs, Fn *fn)
- {
- Ref r0, r1;
- int64_t sz;
- /* we need to make sure
- * the stack remains aligned
- * (rsp = 0) mod 16
- */
- fn->dynalloc = 1;
- if (rtype(rs) == RCon) {
- sz = fn->con[rs.val].bits.i;
- if (sz < 0 || sz >= INT_MAX-15)
- err("invalid alloc size %"PRId64, sz);
- sz = (sz + 15) & -16;
- emit(Osalloc, Kl, rt, getcon(sz, fn), R);
- } else {
- /* r0 = (r + 15) & -16 */
- r0 = newtmp("isel", Kl, fn);
- r1 = newtmp("isel", Kl, fn);
- emit(Osalloc, Kl, rt, r0, R);
- emit(Oand, Kl, r0, r1, getcon(-16, fn));
- emit(Oadd, Kl, r1, rs, getcon(15, fn));
- if (fn->tmp[rs.val].slot != -1)
- err("unlikely alloc argument %%%s for %%%s",
- fn->tmp[rs.val].name, fn->tmp[rt.val].name);
- }
- }
- void
- bsinit(BSet *bs, uint n)
- {
- n = (n + NBit-1) / NBit;
- bs->nt = n;
- bs->t = alloc(n * sizeof bs->t[0]);
- }
- MAKESURE(NBit_is_64, NBit == 64);
- inline static uint
- popcnt(bits b)
- {
- b = (b & 0x5555555555555555) + ((b>>1) & 0x5555555555555555);
- b = (b & 0x3333333333333333) + ((b>>2) & 0x3333333333333333);
- b = (b & 0x0f0f0f0f0f0f0f0f) + ((b>>4) & 0x0f0f0f0f0f0f0f0f);
- b += (b>>8);
- b += (b>>16);
- b += (b>>32);
- return b & 0xff;
- }
- inline static int
- firstbit(bits b)
- {
- int n;
- n = 0;
- if (!(b & 0xffffffff)) {
- n += 32;
- b >>= 32;
- }
- if (!(b & 0xffff)) {
- n += 16;
- b >>= 16;
- }
- if (!(b & 0xff)) {
- n += 8;
- b >>= 8;
- }
- if (!(b & 0xf)) {
- n += 4;
- b >>= 4;
- }
- n += (char[16]){4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0}[b & 0xf];
- return n;
- }
- uint
- bscount(BSet *bs)
- {
- uint i, n;
- n = 0;
- for (i=0; i<bs->nt; i++)
- n += popcnt(bs->t[i]);
- return n;
- }
- static inline uint
- bsmax(BSet *bs)
- {
- return bs->nt * NBit;
- }
- void
- bsset(BSet *bs, uint elt)
- {
- assert(elt < bsmax(bs));
- bs->t[elt/NBit] |= BIT(elt%NBit);
- }
- void
- bsclr(BSet *bs, uint elt)
- {
- assert(elt < bsmax(bs));
- bs->t[elt/NBit] &= ~BIT(elt%NBit);
- }
- #define BSOP(f, op) \
- void \
- f(BSet *a, BSet *b) \
- { \
- uint i; \
- \
- assert(a->nt == b->nt); \
- for (i=0; i<a->nt; i++) \
- a->t[i] op b->t[i]; \
- }
- BSOP(bscopy, =)
- BSOP(bsunion, |=)
- BSOP(bsinter, &=)
- BSOP(bsdiff, &= ~)
- int
- bsequal(BSet *a, BSet *b)
- {
- uint i;
- assert(a->nt == b->nt);
- for (i=0; i<a->nt; i++)
- if (a->t[i] != b->t[i])
- return 0;
- return 1;
- }
- void
- bszero(BSet *bs)
- {
- memset(bs->t, 0, bs->nt * sizeof bs->t[0]);
- }
- /* iterates on a bitset, use as follows
- *
- * for (i=0; bsiter(set, &i); i++)
- * use(i);
- *
- */
- int
- bsiter(BSet *bs, int *elt)
- {
- bits b;
- uint t, i;
- i = *elt;
- t = i/NBit;
- if (t >= bs->nt)
- return 0;
- b = bs->t[t];
- b &= ~(BIT(i%NBit) - 1);
- while (!b) {
- ++t;
- if (t >= bs->nt)
- return 0;
- b = bs->t[t];
- }
- *elt = NBit*t + firstbit(b);
- return 1;
- }
- void
- dumpts(BSet *bs, Tmp *tmp, FILE *f)
- {
- int t;
- fprintf(f, "[");
- for (t=Tmp0; bsiter(bs, &t); t++)
- fprintf(f, " %s", tmp[t].name);
- fprintf(f, " ]\n");
- }
- void
- runmatch(uchar *code, Num *tn, Ref ref, Ref *var)
- {
- Ref stkbuf[20], *stk;
- uchar *s, *pc;
- int bc, i;
- int n, nl, nr;
- assert(rtype(ref) == RTmp);
- stk = stkbuf;
- pc = code;
- while ((bc = *pc))
- switch (bc) {
- case 1: /* pushsym */
- case 2: /* push */
- assert(stk < &stkbuf[20]);
- assert(rtype(ref) == RTmp);
- nl = tn[ref.val].nl;
- nr = tn[ref.val].nr;
- if (bc == 1 && nl > nr) {
- *stk++ = tn[ref.val].l;
- ref = tn[ref.val].r;
- } else {
- *stk++ = tn[ref.val].r;
- ref = tn[ref.val].l;
- }
- pc++;
- break;
- case 3: /* set */
- var[*++pc] = ref;
- if (*(pc + 1) == 0)
- return;
- /* fall through */
- case 4: /* pop */
- assert(stk > &stkbuf[0]);
- ref = *--stk;
- pc++;
- break;
- case 5: /* switch */
- assert(rtype(ref) == RTmp);
- n = tn[ref.val].n;
- s = pc + 1;
- for (i=*s++; i>0; i--, s++)
- if (n == *s++)
- break;
- pc += *s;
- break;
- default: /* jump */
- assert(bc >= 10);
- pc = code + (bc - 10);
- break;
- }
- }
|