From 8531896f8d21ba1e727262aaf5cd96043590b480 Mon Sep 17 00:00:00 2001 From: Ori Bernstein Date: Tue, 17 Nov 2015 20:53:32 -0800 Subject: MEGAPATCH: Tabification. Tabs > spaces. By 4 spaces, to be precise. Let's use them. --- 6/asm.h | 316 ++-- 6/blob.c | 378 ++--- 6/gen.c | 220 +-- 6/gengas.c | 726 +++++----- 6/genp9.c | 766 +++++----- 6/isel.c | 1744 +++++++++++----------- 6/locs.c | 336 ++--- 6/main.c | 376 ++--- 6/peep.c | 96 +- 6/ra.c | 2183 ++++++++++++++-------------- 6/simp.c | 2886 ++++++++++++++++++------------------- 6/typeinfo.c | 595 ++++---- bench/runner.c | 84 -- mi/cfg.c | 456 +++--- mi/dfcheck.c | 184 +-- mi/fold.c | 390 ++--- mi/match.c | 1288 ++++++++--------- mi/mi.h | 48 +- mi/reaching.c | 233 ++- mk/lexyacc.mk | 2 +- muse/muse.c | 140 +- parse/bitset.c | 240 ++-- parse/dump.c | 408 +++--- parse/gram.y | 1387 +++++++++--------- parse/htab.c | 377 +++-- parse/infer.c | 4048 ++++++++++++++++++++++++++-------------------------- parse/names.c | 11 +- parse/node.c | 532 ++++--- parse/parse.h | 625 ++++---- parse/specialize.c | 832 ++++++----- parse/stab.c | 644 ++++----- parse/tok.c | 1330 +++++++++-------- parse/type.c | 1341 +++++++++-------- parse/use.c | 1826 ++++++++++++------------ parse/util.c | 653 +++++---- 35 files changed, 13770 insertions(+), 13931 deletions(-) delete mode 100644 bench/runner.c diff --git a/6/asm.h b/6/asm.h index ceb720a..9b6dd1a 100644 --- a/6/asm.h +++ b/6/asm.h @@ -21,218 +21,218 @@ typedef enum { #define Reg(r, gasname, p9name, mode) r, #include "regs.def" #undef Reg - Nreg + Nreg } Reg; typedef enum { - Locnone, - Loclbl, /* label */ - Locreg, /* register */ - Locmem, /* reg offset mem */ - Locmeml, /* label offset mem */ - Loclit, /* literal value */ - Loclitl /* label address */ + Locnone, + Loclbl, /* label */ + Locreg, /* register */ + Locmem, /* reg offset mem */ + Locmeml, /* label offset mem */ + Loclit, /* literal value */ + Loclitl /* label address */ } Loctype; typedef enum { - ModeNone, - ModeB, /* byte */ - ModeW, /* short */ - ModeL, /* long */ - ModeQ, /* quad */ - ModeF, /* float32 */ - ModeD, /* float64 */ - Nmode, + ModeNone, + ModeB, /* byte */ + ModeW, /* short */ + ModeL, /* long */ + ModeQ, /* quad */ + ModeF, /* float32 */ + ModeD, /* float64 */ + Nmode, } Mode; typedef enum { - Classbad, - Classint, - Classflt, - Nclass, + Classbad, + Classint, + Classflt, + Nclass, } Rclass; typedef enum { - Gnugas, - Plan9, + Gnugas, + Plan9, } Asmsyntax; typedef enum { - Bti8, - Bti16, - Bti32, - Bti64, - Btimin, /* byte-packed uint */ - Btref, - Btbytes, - Btseq, - Btpad, + Bti8, + Bti16, + Bti32, + Bti64, + Btimin, /* byte-packed uint */ + Btref, + Btbytes, + Btseq, + Btpad, } Blobtype; struct Blob { - Blobtype type; - size_t align; - char *lbl; /* may be null */ - char isglobl; - union { - uint64_t npad; - uint64_t ival; - struct { - char *str; - char isextern; - size_t off; - } ref; - struct { - size_t len; - char *buf; - } bytes; - struct { - size_t nsub; - Blob **sub; - } seq; - }; + Blobtype type; + size_t align; + char *lbl; /* may be null */ + char isglobl; + union { + uint64_t npad; + uint64_t ival; + struct { + char *str; + char isextern; + size_t off; + } ref; + struct { + size_t len; + char *buf; + } bytes; + struct { + size_t nsub; + Blob **sub; + } seq; + }; }; /* a register, label, or memory location */ struct Loc { - Loctype type; /* the type of loc */ - Mode mode; /* the mode of this location */ - void *list; - union { - char *lbl; /* for Loclbl, Loclitl */ - struct { /* for Locreg */ - regid id; - Reg colour; - } reg; - long lit; /* for Loclit */ - /* - * for Locmem, Locmeml. - * address format is - * disp(base + index) - */ - struct { - /* only one of lbldisp and constdisp may be used */ - char *lbldisp; - long constdisp; - int scale; /* 0,1,2,4, or 8 */ - Loc *base; /* needed */ - Loc *idx; /* optional */ - } mem; - }; + Loctype type; /* the type of loc */ + Mode mode; /* the mode of this location */ + void *list; + union { + char *lbl; /* for Loclbl, Loclitl */ + struct { /* for Locreg */ + regid id; + Reg colour; + } reg; + long lit; /* for Loclit */ + /* + * for Locmem, Locmeml. + * address format is + * disp(base + index) + */ + struct { + /* only one of lbldisp and constdisp may be used */ + char *lbldisp; + long constdisp; + int scale; /* 0,1,2,4, or 8 */ + Loc *base; /* needed */ + Loc *idx; /* optional */ + } mem; + }; }; struct Insn { - size_t uid; - AsmOp op; - Loc *args[Maxarg]; - size_t nargs; + size_t uid; + AsmOp op; + Loc *args[Maxarg]; + size_t nargs; }; struct Func { - char *name; /* function name */ - Type *type; /* type of function */ - - Node **args; /* argument list */ - size_t nargs; /* number of args, including hidden ones */ - Htab *stkoff; /* Loc* -> int stkoff map */ - Htab *envoff; /* Loc* -> int envoff map */ - size_t stksz; /* stack size */ - Node *ret; /* return value */ - - Cfg *cfg; /* flow graph */ - char isexport; /* is this exported from the asm? */ - char hasenv; /* do we have an environment? */ + char *name; /* function name */ + Type *type; /* type of function */ + + Node **args; /* argument list */ + size_t nargs; /* number of args, including hidden ones */ + Htab *stkoff; /* Loc* -> int stkoff map */ + Htab *envoff; /* Loc* -> int envoff map */ + size_t stksz; /* stack size */ + Node *ret; /* return value */ + + Cfg *cfg; /* flow graph */ + char isexport; /* is this exported from the asm? */ + char hasenv; /* do we have an environment? */ }; struct Asmbb { - int id; /* unique identifier */ - char **lbls; /* list of BB labels */ - size_t nlbls; /* number of labels */ - Insn **il; /* instructions */ - size_t ni; /* number of instructions */ - - Bitset *pred; /* set of predecessor BB ids */ - Bitset *succ; /* set of successor BB ids */ - Bitset *use; /* registers used by this BB */ - Bitset *def; /* registers defined by this BB */ - Bitset *livein; /* variables live on entrance to BB */ - Bitset *liveout; /* variables live on exit from BB */ + int id; /* unique identifier */ + char **lbls; /* list of BB labels */ + size_t nlbls; /* number of labels */ + Insn **il; /* instructions */ + size_t ni; /* number of instructions */ + + Bitset *pred; /* set of predecessor BB ids */ + Bitset *succ; /* set of successor BB ids */ + Bitset *use; /* registers used by this BB */ + Bitset *def; /* registers defined by this BB */ + Bitset *livein; /* variables live on entrance to BB */ + Bitset *liveout; /* variables live on exit from BB */ }; /* instruction selection state */ struct Isel { - Cfg *cfg; /* cfg built with nodes */ + Cfg *cfg; /* cfg built with nodes */ - Asmbb **bb; /* 1:1 mappings with the Node bbs in the CFG */ - size_t nbb; - Asmbb *curbb; + Asmbb **bb; /* 1:1 mappings with the Node bbs in the CFG */ + size_t nbb; + Asmbb *curbb; - Node *ret; /* we store the return into here */ - Htab *spillslots; /* reg id => int stkoff */ - Htab *reglocs; /* decl id => Loc *reg */ - Htab *stkoff; /* decl id => int stkoff */ - Htab *envoff; /* decl id => int envoff */ - Htab *globls; /* decl id => char *globlname */ + Node *ret; /* we store the return into here */ + Htab *spillslots; /* reg id => int stkoff */ + Htab *reglocs; /* decl id => Loc *reg */ + Htab *stkoff; /* decl id => int stkoff */ + Htab *envoff; /* decl id => int envoff */ + Htab *globls; /* decl id => char *globlname */ - Loc *envp; + Loc *envp; - /* increased when we spill */ - Loc *stksz; - Loc *calleesave[Nreg]; - size_t nsaved; + /* increased when we spill */ + Loc *stksz; + Loc *calleesave[Nreg]; + size_t nsaved; - /* register allocator state */ + /* register allocator state */ - size_t *gbits; /* igraph matrix repr */ - regid **gadj; /* igraph adj set repr */ - size_t *ngadj; - size_t nreg; /* maxregid at time of alloc */ - int *degree; /* degree of nodes */ - int *nuses; /* number of uses of nodes */ - Loc **aliasmap; /* mapping of aliases */ + size_t *gbits; /* igraph matrix repr */ + regid **gadj; /* igraph adj set repr */ + size_t *ngadj; + size_t nreg; /* maxregid at time of alloc */ + int *degree; /* degree of nodes */ + int *nuses; /* number of uses of nodes */ + Loc **aliasmap; /* mapping of aliases */ - Bitset *shouldspill; /* the first registers we should try to spill */ - Bitset *neverspill; /* registers we should never spill */ + Bitset *shouldspill; /* the first registers we should try to spill */ + Bitset *neverspill; /* registers we should never spill */ - Insn ***rmoves; - size_t *nrmoves; + Insn ***rmoves; + size_t *nrmoves; - /* move sets */ - Insn **mcoalesced; - size_t nmcoalesced; + /* move sets */ + Insn **mcoalesced; + size_t nmcoalesced; - Insn **mconstrained; - size_t nmconstrained; + Insn **mconstrained; + size_t nmconstrained; - Insn **mfrozen; - size_t nmfrozen; + Insn **mfrozen; + size_t nmfrozen; - Bitset *mactiveset; - Insn **mactive; - size_t nmactive; + Bitset *mactiveset; + Insn **mactive; + size_t nmactive; - /* worklists */ - Bitset *wlmoveset; - Insn **wlmove; - size_t nwlmove; + /* worklists */ + Bitset *wlmoveset; + Insn **wlmove; + size_t nwlmove; - Loc **wlspill; - size_t nwlspill; + Loc **wlspill; + size_t nwlspill; - Loc **wlfreeze; - size_t nwlfreeze; + Loc **wlfreeze; + size_t nwlfreeze; - Loc **wlsimp; - size_t nwlsimp; + Loc **wlsimp; + size_t nwlsimp; - Loc **selstk; - size_t nselstk; + Loc **selstk; + size_t nselstk; - Bitset *coalesced; - Bitset *spilled; - Bitset *prepainted; /* locations that need to be a specific colour */ - Bitset *initial; /* initial set of locations used by this fn */ + Bitset *coalesced; + Bitset *spilled; + Bitset *prepainted; /* locations that need to be a specific colour */ + Bitset *initial; /* initial set of locations used by this fn */ }; /* globals */ diff --git a/6/blob.c b/6/blob.c index 95e5678..df48b7e 100644 --- a/6/blob.c +++ b/6/blob.c @@ -19,260 +19,260 @@ static size_t blobrec(Blob *b, Htab *globls, Htab *strtab, Node *n); Blob *mkblobi(Blobtype type, uint64_t ival) { - Blob *b; + Blob *b; - b = zalloc(sizeof(Blob)); - b->type = type; - b->ival = ival; - return b; + b = zalloc(sizeof(Blob)); + b->type = type; + b->ival = ival; + return b; } Blob *mkblobpad(size_t sz) { - Blob *b; + Blob *b; - b = zalloc(sizeof(Blob)); - b->type = Btpad; - b->npad = sz; - return b; + b = zalloc(sizeof(Blob)); + b->type = Btpad; + b->npad = sz; + return b; } Blob *mkblobbytes(char *buf, size_t len) { - Blob *b; + Blob *b; - b = zalloc(sizeof(Blob)); - b->type = Btbytes; - b->bytes.buf = buf; - b->bytes.len = len; - return b; + b = zalloc(sizeof(Blob)); + b->type = Btbytes; + b->bytes.buf = buf; + b->bytes.len = len; + return b; } Blob *mkblobseq(Blob **sub, size_t nsub) { - Blob *b; + Blob *b; - b = zalloc(sizeof(Blob)); - b->type = Btseq; - b->seq.sub = sub; - b->seq.nsub = nsub; - return b; + b = zalloc(sizeof(Blob)); + b->type = Btseq; + b->seq.sub = sub; + b->seq.nsub = nsub; + return b; } Blob *mkblobref(char *lbl, size_t off, int isextern) { - Blob *b; - - b = zalloc(sizeof(Blob)); - b->type = Btref; - b->ref.str = strdup(lbl); - b->ref.isextern = isextern; - b->ref.off = off; - return b; + Blob *b; + + b = zalloc(sizeof(Blob)); + b->type = Btref; + b->ref.str = strdup(lbl); + b->ref.isextern = isextern; + b->ref.off = off; + return b; } void blobfree(Blob *b) { - size_t i; - - if (!b) - return; - switch (b->type) { - case Btref: - free(b->lbl); - break; - case Btseq: - for (i = 0; i < b->seq.nsub; i++) - blobfree(b->seq.sub[i]); - break; - default: - break; - } - free(b); + size_t i; + + if (!b) + return; + switch (b->type) { + case Btref: + free(b->lbl); + break; + case Btseq: + for (i = 0; i < b->seq.nsub; i++) + blobfree(b->seq.sub[i]); + break; + default: + break; + } + free(b); } static size_t getintlit(Node *n, char *failmsg) { - if (exprop(n) != Olit) - fatal(n, "%s", failmsg); - n = n->expr.args[0]; - if (n->lit.littype != Lint) - fatal(n, "%s", failmsg); - return n->lit.intval; + if (exprop(n) != Olit) + fatal(n, "%s", failmsg); + n = n->expr.args[0]; + if (n->lit.littype != Lint) + fatal(n, "%s", failmsg); + return n->lit.intval; } void b(Blob *b, Blob *n) { - lappend(&b->seq.sub, &b->seq.nsub, n); + lappend(&b->seq.sub, &b->seq.nsub, n); } static size_t blobpad(Blob *seq, size_t sz) { - b(seq, mkblobpad(sz)); - return sz; + b(seq, mkblobpad(sz)); + return sz; } static size_t bloblit(Blob *seq, Htab *strtab, Node *v, Type *ty) { - char buf[128]; - char *lbl; - size_t sz; - Blobtype intsz[] = { - [1] = Bti8, - [2] = Bti16, - [4] = Bti32, - [8] = Bti64 - }; - union { - float fv; - double dv; - uint64_t qv; - uint32_t lv; - } u; - - assert(v->type == Nlit); - sz = tysize(ty); - switch (v->lit.littype) { - case Lint: b(seq, mkblobi(intsz[sz], v->lit.intval)); break; - case Lbool: b(seq, mkblobi(Bti8, v->lit.boolval)); break; - case Lchr: b(seq, mkblobi(Bti32, v->lit.chrval)); break; - case Lflt: - if (tybase(v->lit.type)->type == Tyflt32) { - u.fv = v->lit.fltval; - b(seq, mkblobi(Bti32, u.lv)); - } else if (tybase(v->lit.type)->type == Tyflt64) { - u.dv = v->lit.fltval; - b(seq, mkblobi(Bti64, u.qv)); - } - break; - case Lstr: - if (hthas(strtab, &v->lit.strval)) { - lbl = htget(strtab, &v->lit.strval); - } else { - lbl = genlocallblstr(buf, sizeof buf); - htput(strtab, &v->lit.strval, strdup(lbl)); - } - if (v->lit.strval.len > 0) - b(seq, mkblobref(lbl, 0, 1)); - else - b(seq, mkblobi(Bti64, 0)); - b(seq, mkblobi(Bti64, v->lit.strval.len)); - break; - case Lfunc: - die("Generating this shit ain't ready yet "); - break; - case Llbl: - die("Can't generate literal labels, ffs. They're not data."); - break; - } - return sz; + char buf[128]; + char *lbl; + size_t sz; + Blobtype intsz[] = { + [1] = Bti8, + [2] = Bti16, + [4] = Bti32, + [8] = Bti64 + }; + union { + float fv; + double dv; + uint64_t qv; + uint32_t lv; + } u; + + assert(v->type == Nlit); + sz = tysize(ty); + switch (v->lit.littype) { + case Lint: b(seq, mkblobi(intsz[sz], v->lit.intval)); break; + case Lbool: b(seq, mkblobi(Bti8, v->lit.boolval)); break; + case Lchr: b(seq, mkblobi(Bti32, v->lit.chrval)); break; + case Lflt: + if (tybase(v->lit.type)->type == Tyflt32) { + u.fv = v->lit.fltval; + b(seq, mkblobi(Bti32, u.lv)); + } else if (tybase(v->lit.type)->type == Tyflt64) { + u.dv = v->lit.fltval; + b(seq, mkblobi(Bti64, u.qv)); + } + break; + case Lstr: + if (hthas(strtab, &v->lit.strval)) { + lbl = htget(strtab, &v->lit.strval); + } else { + lbl = genlocallblstr(buf, sizeof buf); + htput(strtab, &v->lit.strval, strdup(lbl)); + } + if (v->lit.strval.len > 0) + b(seq, mkblobref(lbl, 0, 1)); + else + b(seq, mkblobi(Bti64, 0)); + b(seq, mkblobi(Bti64, v->lit.strval.len)); + break; + case Lfunc: + die("Generating this shit ain't ready yet "); + break; + case Llbl: + die("Can't generate literal labels, ffs. They're not data."); + break; + } + return sz; } static size_t blobslice(Blob *seq, Htab *globls, Htab *strtab, Node *n) { - Node *base, *lo, *hi; - ssize_t loval, hival, sz; - char *lbl; - - base = n->expr.args[0]; - lo = n->expr.args[1]; - hi = n->expr.args[2]; - - /* by this point, all slicing operations should have had their bases - * pulled out, and we should have vars with their pseudo-decls in their - * place */ - if (exprop(base) != Ovar || !base->expr.isconst) - fatal(base, "slice base is not a constant value"); - loval = getintlit(lo, "lower bound in slice is not constant literal"); - hival = getintlit(hi, "upper bound in slice is not constant literal"); - sz = tysize(tybase(exprtype(base))->sub[0]); - - lbl = htget(globls, base); - b(seq, mkblobref(lbl, loval*sz, 1)); - b(seq, mkblobi(Bti64, (hival - loval))); - return 16; + Node *base, *lo, *hi; + ssize_t loval, hival, sz; + char *lbl; + + base = n->expr.args[0]; + lo = n->expr.args[1]; + hi = n->expr.args[2]; + + /* by this point, all slicing operations should have had their bases + * pulled out, and we should have vars with their pseudo-decls in their + * place */ + if (exprop(base) != Ovar || !base->expr.isconst) + fatal(base, "slice base is not a constant value"); + loval = getintlit(lo, "lower bound in slice is not constant literal"); + hival = getintlit(hi, "upper bound in slice is not constant literal"); + sz = tysize(tybase(exprtype(base))->sub[0]); + + lbl = htget(globls, base); + b(seq, mkblobref(lbl, loval*sz, 1)); + b(seq, mkblobi(Bti64, (hival - loval))); + return 16; } static Node *structmemb(Node *n, char *dcl) { - size_t i; + size_t i; - for (i = 0; i < n->expr.nargs; i++) - if (!strcmp(namestr(n->expr.args[i]->expr.idx), dcl)) - return n->expr.args[i]; - return NULL; + for (i = 0; i < n->expr.nargs; i++) + if (!strcmp(namestr(n->expr.args[i]->expr.idx), dcl)) + return n->expr.args[i]; + return NULL; } static size_t blobstruct(Blob *seq, Htab *globls, Htab *strtab, Node *n) { - size_t i, sz, pad, end, ndcl; - Node **dcl, *m; - Type *t; - - sz = 0; - t = tybase(exprtype(n)); - assert(t->type == Tystruct); - dcl = t->sdecls; - ndcl = t->nmemb; - - for (i = 0; i < ndcl; i++) { - pad = alignto(sz, decltype(dcl[i])); - m = structmemb(n, declname(dcl[i])); - sz += blobpad(seq, pad - sz); - if (m) - sz += blobrec(seq, globls, strtab, m); - else - sz += blobpad(seq, size(dcl[i])); - } - end = alignto(sz, t); - sz += blobpad(seq, end - sz); - return sz; + size_t i, sz, pad, end, ndcl; + Node **dcl, *m; + Type *t; + + sz = 0; + t = tybase(exprtype(n)); + assert(t->type == Tystruct); + dcl = t->sdecls; + ndcl = t->nmemb; + + for (i = 0; i < ndcl; i++) { + pad = alignto(sz, decltype(dcl[i])); + m = structmemb(n, declname(dcl[i])); + sz += blobpad(seq, pad - sz); + if (m) + sz += blobrec(seq, globls, strtab, m); + else + sz += blobpad(seq, size(dcl[i])); + } + end = alignto(sz, t); + sz += blobpad(seq, end - sz); + return sz; } static size_t blobucon(Blob *seq, Htab *globls, Htab *strtab, Node *n) { - size_t sz; - Ucon *uc; - - sz = 4; - uc = finducon(exprtype(n), n->expr.args[0]); - b(seq, mkblobi(Bti32, uc->id)); - if (n->expr.nargs > 1) - sz += blobrec(seq, globls, strtab, n->expr.args[1]); - sz += blobpad(seq, size(n) - sz); - return sz; + size_t sz; + Ucon *uc; + + sz = 4; + uc = finducon(exprtype(n), n->expr.args[0]); + b(seq, mkblobi(Bti32, uc->id)); + if (n->expr.nargs > 1) + sz += blobrec(seq, globls, strtab, n->expr.args[1]); + sz += blobpad(seq, size(n) - sz); + return sz; } static size_t blobrec(Blob *b, Htab *globls, Htab *strtab, Node *n) { - size_t i, sz; - - switch(exprop(n)) { - case Oucon: sz = blobucon(b, globls, strtab, n); break; - case Oslice: sz = blobslice(b, globls, strtab, n); break; - case Ostruct: sz = blobstruct(b, globls, strtab, n); break; - case Olit: sz = bloblit(b, strtab, n->expr.args[0], exprtype(n)); break; - case Otup: - case Oarr: - /* Assumption: We sorted this while folding */ - sz = 0; - for (i = 0; i < n->expr.nargs; i++) - sz += blobrec(b, globls, strtab, n->expr.args[i]); - break; - default: - dump(n, stdout); - die("Nonliteral initializer for global"); - break; - } - return sz; + size_t i, sz; + + switch(exprop(n)) { + case Oucon: sz = blobucon(b, globls, strtab, n); break; + case Oslice: sz = blobslice(b, globls, strtab, n); break; + case Ostruct: sz = blobstruct(b, globls, strtab, n); break; + case Olit: sz = bloblit(b, strtab, n->expr.args[0], exprtype(n)); break; + case Otup: + case Oarr: + /* Assumption: We sorted this while folding */ + sz = 0; + for (i = 0; i < n->expr.nargs; i++) + sz += blobrec(b, globls, strtab, n->expr.args[i]); + break; + default: + dump(n, stdout); + die("Nonliteral initializer for global"); + break; + } + return sz; } Blob *litblob(Htab *globls, Htab *strtab, Node *n) { - Blob *b; + Blob *b; - b = mkblobseq(NULL, 0); - blobrec(b, globls, strtab, n); - return b; + b = mkblobseq(NULL, 0); + blobrec(b, globls, strtab, n); + return b; } diff --git a/6/gen.c b/6/gen.c index 5290e6d..608ca66 100644 --- a/6/gen.c +++ b/6/gen.c @@ -17,88 +17,88 @@ void fillglobls(Stab *st, Htab *globls) { - size_t i, j, nk, nns; - void **k, **ns; - Stab *stab; - Node *s; - - k = htkeys(st->dcl, &nk); - for (i = 0; i < nk; i++) { - s = htget(st->dcl, k[i]); - if (isconstfn(s)) - s->decl.type = codetype(s->decl.type); - htput(globls, s, asmname(s)); - } - free(k); - - ns = htkeys(file->file.ns, &nns); - for (j = 0; j < nns; j++) { - stab = htget(file->file.ns, ns[j]); - k = htkeys(stab->dcl, &nk); - for (i = 0; i < nk; i++) { - s = htget(stab->dcl, k[i]); - htput(globls, s, asmname(s)); - } - free(k); - } - free(ns); + size_t i, j, nk, nns; + void **k, **ns; + Stab *stab; + Node *s; + + k = htkeys(st->dcl, &nk); + for (i = 0; i < nk; i++) { + s = htget(st->dcl, k[i]); + if (isconstfn(s)) + s->decl.type = codetype(s->decl.type); + htput(globls, s, asmname(s)); + } + free(k); + + ns = htkeys(file->file.ns, &nns); + for (j = 0; j < nns; j++) { + stab = htget(file->file.ns, ns[j]); + k = htkeys(stab->dcl, &nk); + for (i = 0; i < nk; i++) { + s = htget(stab->dcl, k[i]); + htput(globls, s, asmname(s)); + } + free(k); + } + free(ns); } Type *codetype(Type *ft) { - ft = tybase(ft); - if (ft->type == Tycode) - return ft; - assert(ft->type == Tyfunc); - ft = tydup(ft); - ft->type = Tycode; - return ft; + ft = tybase(ft); + if (ft->type == Tycode) + return ft; + assert(ft->type == Tyfunc); + ft = tydup(ft); + ft->type = Tycode; + return ft; } Type *closuretype(Type *ft) { - ft = tybase(ft); - if (ft->type == Tyfunc) - return ft; - assert(ft->type == Tycode); - ft = tydup(ft); - ft->type = Tyfunc; - return ft; + ft = tybase(ft); + if (ft->type == Tyfunc) + return ft; + assert(ft->type == Tycode); + ft = tydup(ft); + ft->type = Tyfunc; + return ft; } static int islocal(Node *dcl) { - if (dcl->decl.vis != Visintern) - return 0; - if (dcl->decl.isimport || dcl->decl.isextern) - return 0; - return 1; + if (dcl->decl.vis != Visintern) + return 0; + if (dcl->decl.isimport || dcl->decl.isextern) + return 0; + return 1; } char *genlocallblstr(char *buf, size_t sz) { - if (asmsyntax == Plan9) - return genlblstr(buf, 128, "<>"); - else - return genlblstr(buf, 128, ""); + if (asmsyntax == Plan9) + return genlblstr(buf, 128, "<>"); + else + return genlblstr(buf, 128, ""); } int isconstfn(Node *n) { - Node *d; - Type *t; - - if (n->type == Nexpr) { - if (exprop(n) != Ovar) - return 0; - d = decls[n->expr.did]; - } else { - d = n; - } - t = tybase(decltype(d)); - if (d && d->decl.isconst && d->decl.isglobl) - return t->type == Tyfunc || t->type == Tycode; - return 0; + Node *d; + Type *t; + + if (n->type == Nexpr) { + if (exprop(n) != Ovar) + return 0; + d = decls[n->expr.did]; + } else { + d = n; + } + t = tybase(decltype(d)); + if (d && d->decl.isconst && d->decl.isglobl) + return t->type == Tyfunc || t->type == Tycode; + return 0; } /* @@ -110,60 +110,60 @@ int isconstfn(Node *n) */ char *asmname(Node *dcl) { - char buf[1024]; - char *vis, *pf, *ns, *name, *sep; - Node *n; - - n = dcl->decl.name; - pf = Symprefix; - ns = n->name.ns; - name = n->name.name; - vis = ""; - sep = ""; - if (asmsyntax == Plan9) - if (islocal(dcl)) - vis = "<>"; - if (!ns || !ns[0]) - ns = ""; - else - sep = "$"; - if (name[0] == '.') - pf = ""; - - bprintf(buf, sizeof buf, "%s%s%s%s%s", pf, ns, sep, name, vis); - return strdup(buf); + char buf[1024]; + char *vis, *pf, *ns, *name, *sep; + Node *n; + + n = dcl->decl.name; + pf = Symprefix; + ns = n->name.ns; + name = n->name.name; + vis = ""; + sep = ""; + if (asmsyntax == Plan9) + if (islocal(dcl)) + vis = "<>"; + if (!ns || !ns[0]) + ns = ""; + else + sep = "$"; + if (name[0] == '.') + pf = ""; + + bprintf(buf, sizeof buf, "%s%s%s%s%s", pf, ns, sep, name, vis); + return strdup(buf); } char *tydescid(char *buf, size_t bufsz, Type *ty) { - char *sep, *ns; - - sep = ""; - ns = ""; - if (ty->type == Tyname) { - if (ty->name->name.ns) { - ns = ty->name->name.ns; - sep = "$"; - } - if (ty->vis == Visexport || ty->isimport) - bprintf(buf, bufsz, "_tydesc$%s%s%s", ns, sep, ty->name->name.name); - else - bprintf(buf, bufsz, "_tydesc$%s%s%s$%d", ns, sep, ty->name->name.name, ty->tid); - } else { - if (file->file.globls->name) { - ns = file->file.globls->name; - sep = "$"; - } - bprintf(buf, bufsz, "_tydesc%s%s$%d",sep, ns, ty->tid); - } - return buf; + char *sep, *ns; + + sep = ""; + ns = ""; + if (ty->type == Tyname) { + if (ty->name->name.ns) { + ns = ty->name->name.ns; + sep = "$"; + } + if (ty->vis == Visexport || ty->isimport) + bprintf(buf, bufsz, "_tydesc$%s%s%s", ns, sep, ty->name->name.name); + else + bprintf(buf, bufsz, "_tydesc$%s%s%s$%d", ns, sep, ty->name->name.name, ty->tid); + } else { + if (file->file.globls->name) { + ns = file->file.globls->name; + sep = "$"; + } + bprintf(buf, bufsz, "_tydesc%s%s$%d",sep, ns, ty->tid); + } + return buf; } void gen(Node *file, char *out) { - switch (asmsyntax) { - case Plan9: genp9(file, out); break; - case Gnugas: gengas(file, out); break; - default: die("unknown target"); break; - } + switch (asmsyntax) { + case Plan9: genp9(file, out); break; + case Gnugas: gengas(file, out); break; + default: die("unknown target"); break; + } } diff --git a/6/gengas.c b/6/gengas.c index 08a2b04..1578a09 100644 --- a/6/gengas.c +++ b/6/gengas.c @@ -30,312 +30,312 @@ static char *regnames[] = { }; static char* modenames[] = { - [ModeB] = "b", - [ModeW] = "w", - [ModeL] = "l", - [ModeQ] = "q", - [ModeF] = "s", - [ModeD] = "d" + [ModeB] = "b", + [ModeW] = "w", + [ModeL] = "l", + [ModeQ] = "q", + [ModeF] = "s", + [ModeD] = "d" }; static void locprint(FILE *fd, Loc *l, char spec); static void initconsts(Htab *globls) { - Type *ty; - Node *name; - Node *dcl; - - tyintptr = mktype(Zloc, Tyuint64); - tyword = mktype(Zloc, Tyuint); - tyvoid = mktype(Zloc, Tyvoid); - - ty = mktyfunc(Zloc, NULL, 0, mktype(Zloc, Tyvoid)); - ty->type = Tycode; - name = mknsname(Zloc, "_rt", "abort_oob"); - dcl = mkdecl(Zloc, name, ty); - dcl->decl.isconst = 1; - dcl->decl.isextern = 1; - dcl->decl.isglobl = 1; - htput(globls, dcl, asmname(dcl)); - - abortoob = mkexpr(Zloc, Ovar, name, NULL); - abortoob->expr.type = ty; - abortoob->expr.did = dcl->decl.did; - abortoob->expr.isconst = 1; + Type *ty; + Node *name; + Node *dcl; + + tyintptr = mktype(Zloc, Tyuint64); + tyword = mktype(Zloc, Tyuint); + tyvoid = mktype(Zloc, Tyvoid); + + ty = mktyfunc(Zloc, NULL, 0, mktype(Zloc, Tyvoid)); + ty->type = Tycode; + name = mknsname(Zloc, "_rt", "abort_oob"); + dcl = mkdecl(Zloc, name, ty); + dcl->decl.isconst = 1; + dcl->decl.isextern = 1; + dcl->decl.isglobl = 1; + htput(globls, dcl, asmname(dcl)); + + abortoob = mkexpr(Zloc, Ovar, name, NULL); + abortoob->expr.type = ty; + abortoob->expr.did = dcl->decl.did; + abortoob->expr.isconst = 1; } void printmem(FILE *fd, Loc *l, char spec) { - if (l->type == Locmem) { - if (l->mem.constdisp) - fprintf(fd, "%ld", l->mem.constdisp); - } else { - if (l->mem.lbldisp) - fprintf(fd, "%s", l->mem.lbldisp); - } - if (l->mem.base) { - fprintf(fd, "("); - locprint(fd, l->mem.base, 'r'); - if (l->mem.idx) { - fprintf(fd, ","); - locprint(fd, l->mem.idx, 'r'); - } - if (l->mem.scale > 1) - fprintf(fd, ",%d", l->mem.scale); - if (l->mem.base) - fprintf(fd, ")"); - } else if (l->type != Locmeml) { - die("Only locmeml can have unspecified base reg"); - } + if (l->type == Locmem) { + if (l->mem.constdisp) + fprintf(fd, "%ld", l->mem.constdisp); + } else { + if (l->mem.lbldisp) + fprintf(fd, "%s", l->mem.lbldisp); + } + if (l->mem.base) { + fprintf(fd, "("); + locprint(fd, l->mem.base, 'r'); + if (l->mem.idx) { + fprintf(fd, ","); + locprint(fd, l->mem.idx, 'r'); + } + if (l->mem.scale > 1) + fprintf(fd, ",%d", l->mem.scale); + if (l->mem.base) + fprintf(fd, ")"); + } else if (l->type != Locmeml) { + die("Only locmeml can have unspecified base reg"); + } } static void locprint(FILE *fd, Loc *l, char spec) { - assert(l->mode); - switch (l->type) { - case Loclitl: - assert(spec == 'i' || spec == 'x' || spec == 'u'); - fprintf(fd, "$%s", l->lbl); - break; - case Loclbl: - assert(spec == 'm' || spec == 'v' || spec == 'x'); - fprintf(fd, "%s", l->lbl); - break; - case Locreg: - assert((spec == 'r' && isintmode(l->mode)) || - (spec == 'f' && isfloatmode(l->mode)) || - spec == 'v' || - spec == 'x' || - spec == 'u'); - if (l->reg.colour == Rnone) - fprintf(fd, "%%P.%zd%s", l->reg.id, modenames[l->mode]); - else - fprintf(fd, "%s", regnames[l->reg.colour]); - break; - case Locmem: - case Locmeml: - assert(spec == 'm' || spec == 'v' || spec == 'x'); - printmem(fd, l, spec); - break; - case Loclit: - assert(spec == 'i' || spec == 'x' || spec == 'u'); - fprintf(fd, "$%ld", l->lit); - break; - case Locnone: - die("Bad location in locprint()"); - break; - } + assert(l->mode); + switch (l->type) { + case Loclitl: + assert(spec == 'i' || spec == 'x' || spec == 'u'); + fprintf(fd, "$%s", l->lbl); + break; + case Loclbl: + assert(spec == 'm' || spec == 'v' || spec == 'x'); + fprintf(fd, "%s", l->lbl); + break; + case Locreg: + assert((spec == 'r' && isintmode(l->mode)) || + (spec == 'f' && isfloatmode(l->mode)) || + spec == 'v' || + spec == 'x' || + spec == 'u'); + if (l->reg.colour == Rnone) + fprintf(fd, "%%P.%zd%s", l->reg.id, modenames[l->mode]); + else + fprintf(fd, "%s", regnames[l->reg.colour]); + break; + case Locmem: + case Locmeml: + assert(spec == 'm' || spec == 'v' || spec == 'x'); + printmem(fd, l, spec); + break; + case Loclit: + assert(spec == 'i' || spec == 'x' || spec == 'u'); + fprintf(fd, "$%ld", l->lit); + break; + case Locnone: + die("Bad location in locprint()"); + break; + } } static int issubreg(Loc *a, Loc *b) { - return rclass(a) == rclass(b) && a->mode != b->mode; + return rclass(a) == rclass(b) && a->mode != b->mode; } void iprintf(FILE *fd, Insn *insn) { - char *p; - int i; - int idx; - - /* x64 has a quirk; it has no movzlq because mov zero extends. This - * means that we need to do a movl when we really want a movzlq. Since - * we don't know the name of the reg to use, we need to sub it in when - * writing... */ - switch (insn->op) { - case Imovzx: - if (insn->args[0]->mode == ModeL && insn->args[1]->mode == ModeQ) { - if (insn->args[1]->reg.colour) { - insn->op = Imov; - insn->args[1] = coreg(insn->args[1]->reg.colour, ModeL); - } - } - break; - case Imovs: - if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone) - break; - /* moving a reg to itself is dumb. */ - if (insn->args[0]->reg.colour == insn->args[1]->reg.colour) - return; - break; - case Imov: - assert(!isfloatmode(insn->args[0]->mode)); - if (insn->args[0]->type != Locreg || insn->args[1]->type != Locreg) - break; - if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone) - break; - /* if one reg is a subreg of another, we can just use the right - * mode to move between them. */ - if (issubreg(insn->args[0], insn->args[1])) - insn->args[0] = coreg(insn->args[0]->reg.colour, insn->args[1]->mode); - /* moving a reg to itself is dumb. */ - if (insn->args[0]->reg.colour == insn->args[1]->reg.colour) - return; - break; - default: - break; - } - p = insnfmt[insn->op]; - i = 0; - for (; *p; p++) { - if (*p != '%') { - fputc(*p, fd); - continue; - } - - /* %-formating */ - p++; - idx = i; + char *p; + int i; + int idx; + + /* x64 has a quirk; it has no movzlq because mov zero extends. This + * means that we need to do a movl when we really want a movzlq. Since + * we don't know the name of the reg to use, we need to sub it in when + * writing... */ + switch (insn->op) { + case Imovzx: + if (insn->args[0]->mode == ModeL && insn->args[1]->mode == ModeQ) { + if (insn->args[1]->reg.colour) { + insn->op = Imov; + insn->args[1] = coreg(insn->args[1]->reg.colour, ModeL); + } + } + break; + case Imovs: + if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone) + break; + /* moving a reg to itself is dumb. */ + if (insn->args[0]->reg.colour == insn->args[1]->reg.colour) + return; + break; + case Imov: + assert(!isfloatmode(insn->args[0]->mode)); + if (insn->args[0]->type != Locreg || insn->args[1]->type != Locreg) + break; + if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone) + break; + /* if one reg is a subreg of another, we can just use the right + * mode to move between them. */ + if (issubreg(insn->args[0], insn->args[1])) + insn->args[0] = coreg(insn->args[0]->reg.colour, insn->args[1]->mode); + /* moving a reg to itself is dumb. */ + if (insn->args[0]->reg.colour == insn->args[1]->reg.colour) + return; + break; + default: + break; + } + p = insnfmt[insn->op]; + i = 0; + for (; *p; p++) { + if (*p != '%') { + fputc(*p, fd); + continue; + } + + /* %-formating */ + p++; + idx = i; again: - switch (*p) { - case '\0': - goto done; /* skip the final p++ */ - case 'r': /* int register */ - case 'f': /* float register */ - case 'm': /* memory */ - case 'i': /* imm */ - case 'v': /* reg/mem */ - case 'u': /* reg/imm */ - case 'x': /* reg/mem/imm */ - locprint(fd, insn->args[idx], *p); - i++; - break; - case 't': - fputs(modenames[insn->args[idx]->mode], fd); - break; - default: - /* the asm description uses 1-based indexing, so that 0 - * can be used as a sentinel. */ - if (!isdigit(*p)) - die("Invalid %%-specifier '%c'", *p); - idx = strtol(p, &p, 10) - 1; - goto again; - break; - } - } + switch (*p) { + case '\0': + goto done; /* skip the final p++ */ + case 'r': /* int register */ + case 'f': /* float register */ + case 'm': /* memory */ + case 'i': /* imm */ + case 'v': /* reg/mem */ + case 'u': /* reg/imm */ + case 'x': /* reg/mem/imm */ + locprint(fd, insn->args[idx], *p); + i++; + break; + case 't': + fputs(modenames[insn->args[idx]->mode], fd); + break; + default: + /* the asm description uses 1-based indexing, so that 0 + * can be used as a sentinel. */ + if (!isdigit(*p)) + die("Invalid %%-specifier '%c'", *p); + idx = strtol(p, &p, 10) - 1; + goto again; + break; + } + } done: - return; + return; } static void writebytes(FILE *fd, char *p, size_t sz) { - size_t i; - - for (i = 0; i < sz; i++) { - if (i % 60 == 0) - fprintf(fd, "\t.ascii \""); - if (p[i] == '"' || p[i] == '\\') - fprintf(fd, "\\"); - if (isprint(p[i])) - fprintf(fd, "%c", p[i]); - else - fprintf(fd, "\\%03o", (uint8_t)p[i] & 0xff); - /* line wrapping for readability */ - if (i % 60 == 59 || i == sz - 1) - fprintf(fd, "\"\n"); - } + size_t i; + + for (i = 0; i < sz; i++) { + if (i % 60 == 0) + fprintf(fd, "\t.ascii \""); + if (p[i] == '"' || p[i] == '\\') + fprintf(fd, "\\"); + if (isprint(p[i])) + fprintf(fd, "%c", p[i]); + else + fprintf(fd, "\\%03o", (uint8_t)p[i] & 0xff); + /* line wrapping for readability */ + if (i % 60 == 59 || i == sz - 1) + fprintf(fd, "\"\n"); + } } void genstrings(FILE *fd, Htab *strtab) { - void **k; - Str *s; - size_t i, nk; - - k = htkeys(strtab, &nk); - for (i = 0; i < nk; i++) { - s = k[i]; - fprintf(fd, "%s:\n", (char*)htget(strtab, k[i])); - writebytes(fd, s->buf, s->len); - } + void **k; + Str *s; + size_t i, nk; + + k = htkeys(strtab, &nk); + for (i = 0; i < nk; i++) { + s = k[i]; + fprintf(fd, "%s:\n", (char*)htget(strtab, k[i])); + writebytes(fd, s->buf, s->len); + } } static void writeasm(FILE *fd, Isel *s, Func *fn) { - size_t i, j; - - if (fn->isexport) - fprintf(fd, ".globl %s\n", fn->name); - fprintf(fd, "%s:\n", fn->name); - for (j = 0; j < s->cfg->nbb; j++) { - if (!s->bb[j]) - continue; - for (i = 0; i < s->bb[j]->nlbls; i++) - fprintf(fd, "%s:\n", s->bb[j]->lbls[i]); - for (i = 0; i < s->bb[j]->ni; i++) - iprintf(fd, s->bb[j]->il[i]); - } + size_t i, j; + + if (fn->isexport) + fprintf(fd, ".globl %s\n", fn->name); + fprintf(fd, "%s:\n", fn->name); + for (j = 0; j < s->cfg->nbb; j++) { + if (!s->bb[j]) + continue; + for (i = 0; i < s->bb[j]->nlbls; i++) + fprintf(fd, "%s:\n", s->bb[j]->lbls[i]); + for (i = 0; i < s->bb[j]->ni; i++) + iprintf(fd, s->bb[j]->il[i]); + } } static void encodemin(FILE *fd, uint64_t val) { - size_t i, shift; - uint8_t b; - - if (val < 128) { - fprintf(fd, "\t.byte %zd\n", val); - return; - } - - for (i = 1; i < 8; i++) - if (val < 1ULL << (7*i)) - break; - shift = 8 - i; - b = ~0 << (shift + 1); - b |= val & ((1 << (8 - shift)) - 1); - fprintf(fd, "\t.byte %u\n", b); - val >>= shift; - while (val != 0) { - fprintf(fd, "\t.byte %u\n", (uint)val & 0xff); - val >>= 8; - } + size_t i, shift; + uint8_t b; + + if (val < 128) { + fprintf(fd, "\t.byte %zd\n", val); + return; + } + + for (i = 1; i < 8; i++) + if (val < 1ULL << (7*i)) + break; + shift = 8 - i; + b = ~0 << (shift + 1); + b |= val & ((1 << (8 - shift)) - 1); + fprintf(fd, "\t.byte %u\n", b); + val >>= shift; + while (val != 0) { + fprintf(fd, "\t.byte %u\n", (uint)val & 0xff); + val >>= 8; + } } static void writeblob(FILE *fd, Blob *b) { - size_t i; - - if (!b) - return; - if (b->lbl) { - if (b->isglobl) - fprintf(fd, ".globl %s%s\n", Symprefix, b->lbl); - fprintf(fd, "%s%s:\n", Symprefix, b->lbl); - } - switch (b->type) { - case Bti8: - fprintf(fd, "\t.byte %zd\n", b->ival); - break; - case Bti16: - fprintf(fd, "\t.short %zd\n", b->ival); - break; - case Bti32: - fprintf(fd, "\t.long %zd\n", b->ival); - break; - case Bti64: - fprintf(fd, "\t.quad %zd\n", b->ival); - break; - case Btimin: - encodemin(fd, b->ival); - break; - case Btref: - fprintf(fd, "\t.quad %s + %zd\n", b->ref.str, b->ref.off); - break; - case Btbytes: - writebytes(fd, b->bytes.buf, b->bytes.len); - break; - case Btseq: - for (i = 0; i < b->seq.nsub; i++) - writeblob(fd, b->seq.sub[i]); - break; - case Btpad: - for (i = 0; i < b->npad; i++) - fprintf(fd, "\t.byte 0\n"); - break; - - } + size_t i; + + if (!b) + return; + if (b->lbl) { + if (b->isglobl) + fprintf(fd, ".globl %s%s\n", Symprefix, b->lbl); + fprintf(fd, "%s%s:\n", Symprefix, b->lbl); + } + switch (b->type) { + case Bti8: + fprintf(fd, "\t.byte %zd\n", b->ival); + break; + case Bti16: + fprintf(fd, "\t.short %zd\n", b->ival); + break; + case Bti32: + fprintf(fd, "\t.long %zd\n", b->ival); + break; + case Bti64: + fprintf(fd, "\t.quad %zd\n", b->ival); + break; + case Btimin: + encodemin(fd, b->ival); + break; + case Btref: + fprintf(fd, "\t.quad %s + %zd\n", b->ref.str, b->ref.off); + break; + case Btbytes: + writebytes(fd, b->bytes.buf, b->bytes.len); + break; + case Btseq: + for (i = 0; i < b->seq.nsub; i++) + writeblob(fd, b->seq.sub[i]); + break; + case Btpad: + for (i = 0; i < b->npad; i++) + fprintf(fd, "\t.byte 0\n"); + break; + + } } /* genfunc requires all nodes in 'nl' to map cleanly to operations that are @@ -343,127 +343,127 @@ static void writeblob(FILE *fd, Blob *b) * operations on x32, no structures, and so on. */ static void genfunc(FILE *fd, Func *fn, Htab *globls, Htab *strtab) { - Isel is = {0,}; - - is.reglocs = mkht(varhash, vareq); - is.stkoff = fn->stkoff; - is.envoff = fn->envoff; - is.globls = globls; - is.ret = fn->ret; - is.cfg = fn->cfg; - if (fn->hasenv) - is.envp = locreg(ModeQ); - - selfunc(&is, fn, globls, strtab); - if (debugopt['i']) - writeasm(stdout, &is, fn); - writeasm(fd, &is, fn); + Isel is = {0,}; + + is.reglocs = mkht(varhash, vareq); + is.stkoff = fn->stkoff; + is.envoff = fn->envoff; + is.globls = globls; + is.ret = fn->ret; + is.cfg = fn->cfg; + if (fn->hasenv) + is.envp = locreg(ModeQ); + + selfunc(&is, fn, globls, strtab); + if (debugopt['i']) + writeasm(stdout, &is, fn); + writeasm(fd, &is, fn); } void gentype(FILE *fd, Type *ty) { - Blob *b; + Blob *b; - if (ty->type == Tyvar) - return; - b = tydescblob(ty); - writeblob(fd, b); - blobfree(b); + if (ty->type == Tyvar) + return; + b = tydescblob(ty); + writeblob(fd, b); + blobfree(b); } void genblob(FILE *fd, Node *blob, Htab *globls, Htab *strtab) { - char *lbl; - Blob *b; - - /* lits and such also get wrapped in decls */ - assert(blob->type == Ndecl); - - lbl = htget(globls, blob); - if (blob->decl.vis != Visintern) - fprintf(fd, ".globl %s\n", lbl); - fprintf(fd, ".align %zd\n", tyalign(decltype(blob))); - fprintf(fd, "%s:\n", lbl); - if (blob->decl.init) - b = litblob(globls, strtab, blob->decl.init); - else - b = mkblobpad(size(blob)); - writeblob(fd, b); - blobfree(b); + char *lbl; + Blob *b; + + /* lits and such also get wrapped in decls */ + assert(blob->type == Ndecl); + + lbl = htget(globls, blob); + if (blob->decl.vis != Visintern) + fprintf(fd, ".globl %s\n", lbl); + fprintf(fd, ".align %zd\n", tyalign(decltype(blob))); + fprintf(fd, "%s:\n", lbl); + if (blob->decl.init) + b = litblob(globls, strtab, blob->decl.init); + else + b = mkblobpad(size(blob)); + writeblob(fd, b); + blobfree(b); } void gengas(Node *file, char *out) { - Htab *globls, *strtab; - Node *n, **blob; - Func **fn; - size_t nfn, nblob; - size_t i; - FILE *fd; - - /* ensure that all physical registers have a loc created before any - * other locs, so that locmap[Physreg] maps to the Loc for the physreg - * in question */ - for (i = 0; i < Nreg; i++) - locphysreg(i); - - fn = NULL; - nfn = 0; - blob = NULL; - nblob = 0; - globls = mkht(varhash, vareq); - initconsts(globls); - - /* We need to define all global variables before use */ - fillglobls(file->file.globls, globls); - - pushstab(file->file.globls); - for (i = 0; i < file->file.nstmts; i++) { - n = file->file.stmts[i]; - switch (n->type) { - case Nuse: /* nothing to do */ - case Nimpl: - break; - case Ndecl: - simpglobl(n, globls, &fn, &nfn, &blob, &nblob); - break; - default: - die("Bad node %s in toplevel", nodestr[n->type]); - break; - } - } - popstab(); - - fd = fopen(out, "w"); - if (!fd) - die("Couldn't open fd %s", out); - - strtab = mkht(strlithash, strliteq); - fprintf(fd, ".data\n"); - for (i = 0; i < nblob; i++) - genblob(fd, blob[i], globls, strtab); - fprintf(fd, "\n"); - - fprintf(fd, ".text\n"); - for (i = 0; i < nfn; i++) - genfunc(fd, fn[i], globls, strtab); - fprintf(fd, "\n"); - - for (i = 0; i < ntypes; i++) - if (types[i]->isreflect && !types[i]->isimport) - gentype(fd, types[i]); - fprintf(fd, "\n"); - - genstrings(fd, strtab); - fclose(fd); + Htab *globls, *strtab; + Node *n, **blob; + Func **fn; + size_t nfn, nblob; + size_t i; + FILE *fd; + + /* ensure that all physical registers have a loc created before any + * other locs, so that locmap[Physreg] maps to the Loc for the physreg + * in question */ + for (i = 0; i < Nreg; i++) + locphysreg(i); + + fn = NULL; + nfn = 0; + blob = NULL; + nblob = 0; + globls = mkht(varhash, vareq); + initconsts(globls); + + /* We need to define all global variables before use */ + fillglobls(file->file.globls, globls); + + pushstab(file->file.globls); + for (i = 0; i < file->file.nstmts; i++) { + n = file->file.stmts[i]; + switch (n->type) { + case Nuse: /* nothing to do */ + case Nimpl: + break; + case Ndecl: + simpglobl(n, globls, &fn, &nfn, &blob, &nblob); + break; + default: + die("Bad node %s in toplevel", nodestr[n->type]); + break; + } + } + popstab(); + + fd = fopen(out, "w"); + if (!fd) + die("Couldn't open fd %s", out); + + strtab = mkht(strlithash, strliteq); + fprintf(fd, ".data\n"); + for (i = 0; i < nblob; i++) + genblob(fd, blob[i], globls, strtab); + fprintf(fd, "\n"); + + fprintf(fd, ".text\n"); + for (i = 0; i < nfn; i++) + genfunc(fd, fn[i], globls, strtab); + fprintf(fd, "\n"); + + for (i = 0; i < ntypes; i++) + if (types[i]->isreflect && !types[i]->isimport) + gentype(fd, types[i]); + fprintf(fd, "\n"); + + genstrings(fd, strtab); + fclose(fd); } void dbglocprint(FILE *fd, Loc *l, char spec) { - locprint(fd, l, spec); + locprint(fd, l, spec); } void dbgiprintf(FILE *fd, Insn *i) { - iprintf(fd, i); + iprintf(fd, i); } diff --git a/6/genp9.c b/6/genp9.c index 0a83335..68e9d1b 100644 --- a/6/genp9.c +++ b/6/genp9.c @@ -29,334 +29,334 @@ static char *regnames[] = { }; static char* modenames[] = { - [ModeB] = "B", - [ModeW] = "W", - [ModeL] = "L", - [ModeQ] = "Q", - [ModeF] = "S", - [ModeD] = "D" + [ModeB] = "B", + [ModeW] = "W", + [ModeL] = "L", + [ModeQ] = "Q", + [ModeF] = "S", + [ModeD] = "D" }; static void locprint(FILE *fd, Loc *l, char spec); static void initconsts(Htab *globls) { - Type *ty; - Node *name; - Node *dcl; - - tyintptr = mktype(Zloc, Tyuint64); - tyword = mktype(Zloc, Tyuint); - tyvoid = mktype(Zloc, Tyvoid); - - ty = mktyfunc(Zloc, NULL, 0, mktype(Zloc, Tyvoid)); - ty->type = Tycode; - name = mknsname(Zloc, "_rt", "abort_oob"); - dcl = mkdecl(Zloc, name, ty); - dcl->decl.isconst = 1; - dcl->decl.isextern = 1; - htput(globls, dcl, asmname(dcl)); - - abortoob = mkexpr(Zloc, Ovar, name, NULL); - abortoob->expr.type = ty; - abortoob->expr.did = dcl->decl.did; - abortoob->expr.isconst = 1; + Type *ty; + Node *name; + Node *dcl; + + tyintptr = mktype(Zloc, Tyuint64); + tyword = mktype(Zloc, Tyuint); + tyvoid = mktype(Zloc, Tyvoid); + + ty = mktyfunc(Zloc, NULL, 0, mktype(Zloc, Tyvoid)); + ty->type = Tycode; + name = mknsname(Zloc, "_rt", "abort_oob"); + dcl = mkdecl(Zloc, name, ty); + dcl->decl.isconst = 1; + dcl->decl.isextern = 1; + htput(globls, dcl, asmname(dcl)); + + abortoob = mkexpr(Zloc, Ovar, name, NULL); + abortoob->expr.type = ty; + abortoob->expr.did = dcl->decl.did; + abortoob->expr.isconst = 1; } static void printmem(FILE *fd, Loc *l, char spec) { - if (l->type == Locmem) { - if (l->mem.constdisp) - fprintf(fd, "%ld", l->mem.constdisp); - } else if (l->mem.lbldisp) { - fprintf(fd, "%s", l->mem.lbldisp); - } - if (!l->mem.base || l->mem.base->reg.colour == Rrip) { - fprintf(fd, "+0(SB)"); - } else { - fprintf(fd, "("); - locprint(fd, l->mem.base, 'r'); - fprintf(fd, ")"); - } - if (l->mem.idx) { - fprintf(fd, "("); - locprint(fd, l->mem.idx, 'r'); - fprintf(fd, "*%d", l->mem.scale); - fprintf(fd, ")"); - } + if (l->type == Locmem) { + if (l->mem.constdisp) + fprintf(fd, "%ld", l->mem.constdisp); + } else if (l->mem.lbldisp) { + fprintf(fd, "%s", l->mem.lbldisp); + } + if (!l->mem.base || l->mem.base->reg.colour == Rrip) { + fprintf(fd, "+0(SB)"); + } else { + fprintf(fd, "("); + locprint(fd, l->mem.base, 'r'); + fprintf(fd, ")"); + } + if (l->mem.idx) { + fprintf(fd, "("); + locprint(fd, l->mem.idx, 'r'); + fprintf(fd, "*%d", l->mem.scale); + fprintf(fd, ")"); + } } static void locprint(FILE *fd, Loc *l, char spec) { - spec = tolower(spec); - assert(l->mode); - switch (l->type) { - case Loclitl: - assert(spec == 'i' || spec == 'x' || spec == 'u'); - fprintf(fd, "$%s", l->lbl); - break; - case Loclbl: - assert(spec == 'm' || spec == 'v' || spec == 'x'); - fprintf(fd, "%s", l->lbl); - break; - case Locreg: - assert((spec == 'r' && isintmode(l->mode)) || - (spec == 'f' && isfloatmode(l->mode)) || - spec == 'v' || - spec == 'x' || - spec == 'u'); - if (l->reg.colour == Rnone) - fprintf(fd, "%%P.%zd%s", l->reg.id, modenames[l->mode]); - else - fprintf(fd, "%s", regnames[l->reg.colour]); - break; - case Locmem: - case Locmeml: - assert(spec == 'm' || spec == 'v' || spec == 'x'); - printmem(fd, l, spec); - break; - case Loclit: - assert(spec == 'i' || spec == 'x' || spec == 'u'); - fprintf(fd, "$%ld", l->lit); - break; - case Locnone: - die("Bad location in locprint()"); - break; - } + spec = tolower(spec); + assert(l->mode); + switch (l->type) { + case Loclitl: + assert(spec == 'i' || spec == 'x' || spec == 'u'); + fprintf(fd, "$%s", l->lbl); + break; + case Loclbl: + assert(spec == 'm' || spec == 'v' || spec == 'x'); + fprintf(fd, "%s", l->lbl); + break; + case Locreg: + assert((spec == 'r' && isintmode(l->mode)) || + (spec == 'f' && isfloatmode(l->mode)) || + spec == 'v' || + spec == 'x' || + spec == 'u'); + if (l->reg.colour == Rnone) + fprintf(fd, "%%P.%zd%s", l->reg.id, modenames[l->mode]); + else + fprintf(fd, "%s", regnames[l->reg.colour]); + break; + case Locmem: + case Locmeml: + assert(spec == 'm' || spec == 'v' || spec == 'x'); + printmem(fd, l, spec); + break; + case Loclit: + assert(spec == 'i' || spec == 'x' || spec == 'u'); + fprintf(fd, "$%ld", l->lit); + break; + case Locnone: + die("Bad location in locprint()"); + break; + } } static int issubreg(Loc *a, Loc *b) { - return rclass(a) == rclass(b) && a->mode != b->mode; + return rclass(a) == rclass(b) && a->mode != b->mode; } static void iprintf(FILE *fd, Insn *insn) { - char *p; - int i; - int idx; - - /* x64 has a quirk; it has no movzlq because mov zero extends. This - * means that we need to do a movl when we really want a movzlq. Since - * we don't know the name of the reg to use, we need to sub it in when - * writing... */ - switch (insn->op) { - case Imovzx: - if (insn->args[0]->mode == ModeL && insn->args[1]->mode == ModeQ) { - if (insn->args[1]->reg.colour) { - insn->op = Imov; - insn->args[1] = coreg(insn->args[1]->reg.colour, ModeL); - } - } - break; - case Imovs: - if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone) - break; - /* moving a reg to itself is dumb. */ - if (insn->args[0]->reg.colour == insn->args[1]->reg.colour) - return; - break; - case Imov: - assert(!isfloatmode(insn->args[0]->mode)); - if (insn->args[0]->type != Locreg || insn->args[1]->type != Locreg) - break; - if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone) - break; - /* if one reg is a subreg of another, we can just use the right - * mode to move between them. */ - if (issubreg(insn->args[0], insn->args[1])) - insn->args[0] = coreg(insn->args[0]->reg.colour, insn->args[1]->mode); - /* moving a reg to itself is dumb. */ - if (insn->args[0]->reg.colour == insn->args[1]->reg.colour) - return; - break; - default: - break; - } - p = insnfmt[insn->op]; - i = 0; /* NB: this is 1 based indexing */ - for (; *p; p++) { - if (*p != '%') { - fputc(*p, fd); - continue; - } - - /* %-formating */ - p++; - idx = i; + char *p; + int i; + int idx; + + /* x64 has a quirk; it has no movzlq because mov zero extends. This + * means that we need to do a movl when we really want a movzlq. Since + * we don't know the name of the reg to use, we need to sub it in when + * writing... */ + switch (insn->op) { + case Imovzx: + if (insn->args[0]->mode == ModeL && insn->args[1]->mode == ModeQ) { + if (insn->args[1]->reg.colour) { + insn->op = Imov; + insn->args[1] = coreg(insn->args[1]->reg.colour, ModeL); + } + } + break; + case Imovs: + if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone) + break; + /* moving a reg to itself is dumb. */ + if (insn->args[0]->reg.colour == insn->args[1]->reg.colour) + return; + break; + case Imov: + assert(!isfloatmode(insn->args[0]->mode)); + if (insn->args[0]->type != Locreg || insn->args[1]->type != Locreg) + break; + if (insn->args[0]->reg.colour == Rnone || insn->args[1]->reg.colour == Rnone) + break; + /* if one reg is a subreg of another, we can just use the right + * mode to move between them. */ + if (issubreg(insn->args[0], insn->args[1])) + insn->args[0] = coreg(insn->args[0]->reg.colour, insn->args[1]->mode); + /* moving a reg to itself is dumb. */ + if (insn->args[0]->reg.colour == insn->args[1]->reg.colour) + return; + break; + default: + break; + } + p = insnfmt[insn->op]; + i = 0; /* NB: this is 1 based indexing */ + for (; *p; p++) { + if (*p != '%') { + fputc(*p, fd); + continue; + } + + /* %-formating */ + p++; + idx = i; again: - switch (*p) { - case '\0': - goto done; /* skip the final p++ */ - break; - case 'R': /* int register */ - case 'F': /* float register */ - case 'M': /* memory */ - case 'I': /* imm */ - case 'V': /* reg/mem */ - case 'U': /* reg/imm */ - case 'X': /* reg/mem/imm */ - locprint(fd, insn->args[idx], *p); - i++; - break; - case 'T': - fputs(modenames[insn->args[idx]->mode], fd); - break; - default: - /* the asm description uses 1-based indexing, so that 0 - * can be used as a sentinel. */ - if (!isdigit(*p)) - die("Invalid %%-specifier '%c'", *p); - idx = strtol(p, &p, 10) - 1; - goto again; - break; - } - } + switch (*p) { + case '\0': + goto done; /* skip the final p++ */ + break; + case 'R': /* int register */ + case 'F': /* float register */ + case 'M': /* memory */ + case 'I': /* imm */ + case 'V': /* reg/mem */ + case 'U': /* reg/imm */ + case 'X': /* reg/mem/imm */ + locprint(fd, insn->args[idx], *p); + i++; + break; + case 'T': + fputs(modenames[insn->args[idx]->mode], fd); + break; + default: + /* the asm description uses 1-based indexing, so that 0 + * can be used as a sentinel. */ + if (!isdigit(*p)) + die("Invalid %%-specifier '%c'", *p); + idx = strtol(p, &p, 10) - 1; + goto again; + break; + } + } done: - return; + return; } static size_t writebytes(FILE *fd, char *name, size_t off, char *p, size_t sz) { - size_t i, len; - - assert(sz != 0); - for (i = 0; i < sz; i++) { - len = min(sz - i, 8); - if (i % 8 == 0) - fprintf(fd, "DATA %s+%zd(SB)/%zd,$\"", name, off + i, len); - if (p[i] == '"' || p[i] == '\\') - fprintf(fd, "\\"); - if (isprint(p[i])) - fprintf(fd, "%c", p[i]); - else - fprintf(fd, "\\%03o", (uint8_t)p[i] & 0xff); - /* line wrapping for readability */ - if (i % 8 == 7 || i == sz - 1) - fprintf(fd, "\"\n"); - } - - return sz; + size_t i, len; + + assert(sz != 0); + for (i = 0; i < sz; i++) { + len = min(sz - i, 8); + if (i % 8 == 0) + fprintf(fd, "DATA %s+%zd(SB)/%zd,$\"", name, off + i, len); + if (p[i] == '"' || p[i] == '\\') + fprintf(fd, "\\"); + if (isprint(p[i])) + fprintf(fd, "%c", p[i]); + else + fprintf(fd, "\\%03o", (uint8_t)p[i] & 0xff); + /* line wrapping for readability */ + if (i % 8 == 7 || i == sz - 1) + fprintf(fd, "\"\n"); + } + + return sz; } static void genstrings(FILE *fd, Htab *strtab) { - void **k; - char *lbl; - Str *s; - size_t i, nk; - - k = htkeys(strtab, &nk); - for (i = 0; i < nk; i++) { - s = k[i]; - lbl = htget(strtab, k[i]); - if (s->len) { - fprintf(fd, "GLOBL %s+0(SB),$%lld\n", lbl, (vlong)s->len); - writebytes(fd, lbl, 0, s->buf, s->len); - } - } + void **k; + char *lbl; + Str *s; + size_t i, nk; + + k = htkeys(strtab, &nk); + for (i = 0; i < nk; i++) { + s = k[i]; + lbl = htget(strtab, k[i]); + if (s->len) { + fprintf(fd, "GLOBL %s+0(SB),$%lld\n", lbl, (vlong)s->len); + writebytes(fd, lbl, 0, s->buf, s->len); + } + } } static void writeasm(FILE *fd, Isel *s, Func *fn) { - size_t i, j; - char *hidden; - - hidden = ""; - if (fn->isexport) - hidden = ""; - /* we don't use the stack size directive: myrddin handles - * the stack frobbing on its own */ - fprintf(fd, "TEXT %s%s+0(SB),$0\n", fn->name, hidden); - for (j = 0; j < s->cfg->nbb; j++) { - if (!s->bb[j]) - continue; - for (i = 0; i < s->bb[j]->nlbls; i++) - fprintf(fd, "%s:\n", s->bb[j]->lbls[i]); - for (i = 0; i < s->bb[j]->ni; i++) - iprintf(fd, s->bb[j]->il[i]); - } + size_t i, j; + char *hidden; + + hidden = ""; + if (fn->isexport) + hidden = ""; + /* we don't use the stack size directive: myrddin handles + * the stack frobbing on its own */ + fprintf(fd, "TEXT %s%s+0(SB),$0\n", fn->name, hidden); + for (j = 0; j < s->cfg->nbb; j++) { + if (!s->bb[j]) + continue; + for (i = 0; i < s->bb[j]->nlbls; i++) + fprintf(fd, "%s:\n", s->bb[j]->lbls[i]); + for (i = 0; i < s->bb[j]->ni; i++) + iprintf(fd, s->bb[j]->il[i]); + } } static size_t encodemin(FILE *fd, uint64_t val, size_t off, char *lbl) { - size_t i, shift, n; - uint8_t b; - - if (val < 128) { - fprintf(fd, "\tDATA %s+%zd(SB)/1,$%zd\n", lbl, off, val); - return 1; - } - - for (i = 1; i < 8; i++) - if (val < 1ULL << (7*i)) - break; - - n = 0; - shift = 8 - i; - b = ~0 << (shift + 1); - b |= val & ((1 << (8 - shift)) - 1); - fprintf(fd, "\tDATA %s+%zd(SB)/1,$%u\n", lbl, off, b); - val >>= shift; - while (val != 0) { - n++; - fprintf(fd, "\tDATA %s+%zd(SB)/1,$%u\n", lbl, off+n, (uint)val & 0xff); - val >>= 8; - } - return i; + size_t i, shift, n; + uint8_t b; + + if (val < 128) { + fprintf(fd, "\tDATA %s+%zd(SB)/1,$%zd\n", lbl, off, val); + return 1; + } + + for (i = 1; i < 8; i++) + if (val < 1ULL << (7*i)) + break; + + n = 0; + shift = 8 - i; + b = ~0 << (shift + 1); + b |= val & ((1 << (8 - shift)) - 1); + fprintf(fd, "\tDATA %s+%zd(SB)/1,$%u\n", lbl, off, b); + val >>= shift; + while (val != 0) { + n++; + fprintf(fd, "\tDATA %s+%zd(SB)/1,$%u\n", lbl, off+n, (uint)val & 0xff); + val >>= 8; + } + return i; } static size_t writeblob(FILE *fd, Blob *b, size_t off, char *lbl) { - size_t i, n; - - n = 0; - if (!b) - return 0; - switch (b->type) { - case Bti8: - fprintf(fd, "DATA %s+%zd(SB)/1,$%zd\n", lbl, off+n, b->ival); - n += 1; - break; - case Bti16: - fprintf(fd, "DATA %s+%zd(SB)/2,$%zd\n", lbl, off+n, b->ival); - n += 2; - break; - case Bti32: - fprintf(fd, "DATA %s+%zd(SB)/4,$%zd\n", lbl, off+n, b->ival); - n += 4; - break; - case Bti64: - fprintf(fd, "DATA %s+%zd(SB)/8,$%lld\n", lbl, off+n, (vlong)b->ival); - n += 8; - break; - case Btimin: - n += encodemin(fd, b->ival, off+n, lbl); - break; - case Btref: - if (b->ref.isextern || b->ref.str[0] == '.') - fprintf(fd, "DATA %s+%zd(SB)/8,$%s+%zd(SB)\n", - lbl, off+n, b->ref.str, b->ref.off); - else - fprintf(fd, "DATA %s+%zd(SB)/8,$%s<>+%zd(SB)\n", - lbl, off+n, b->ref.str, b->ref.off); - n += 8; - break; - case Btbytes: - n += writebytes(fd, lbl, off+n, b->bytes.buf, b->bytes.len); - break; - case Btseq: - for (i = 0; i < b->seq.nsub; i++) - n += writeblob(fd, b->seq.sub[i], off+n, lbl); - break; - case Btpad: - for (i = 0; i < b->npad; i++) - fprintf(fd, "DATA %s+%zd(SB)/1,$0\n", lbl, off+n+i); - n += b->npad; - break; - } - return n; + size_t i, n; + + n = 0; + if (!b) + return 0; + switch (b->type) { + case Bti8: + fprintf(fd, "DATA %s+%zd(SB)/1,$%zd\n", lbl, off+n, b->ival); + n += 1; + break; + case Bti16: + fprintf(fd, "DATA %s+%zd(SB)/2,$%zd\n", lbl, off+n, b->ival); + n += 2; + break; + case Bti32: + fprintf(fd, "DATA %s+%zd(SB)/4,$%zd\n", lbl, off+n, b->ival); + n += 4; + break; + case Bti64: + fprintf(fd, "DATA %s+%zd(SB)/8,$%lld\n", lbl, off+n, (vlong)b->ival); + n += 8; + break; + case Btimin: + n += encodemin(fd, b->ival, off+n, lbl); + break; + case Btref: + if (b->ref.isextern || b->ref.str[0] == '.') + fprintf(fd, "DATA %s+%zd(SB)/8,$%s+%zd(SB)\n", + lbl, off+n, b->ref.str, b->ref.off); + else + fprintf(fd, "DATA %s+%zd(SB)/8,$%s<>+%zd(SB)\n", + lbl, off+n, b->ref.str, b->ref.off); + n += 8; + break; + case Btbytes: + n += writebytes(fd, lbl, off+n, b->bytes.buf, b->bytes.len); + break; + case Btseq: + for (i = 0; i < b->seq.nsub; i++) + n += writeblob(fd, b->seq.sub[i], off+n, lbl); + break; + case Btpad: + for (i = 0; i < b->npad; i++) + fprintf(fd, "DATA %s+%zd(SB)/1,$0\n", lbl, off+n+i); + n += b->npad; + break; + } + return n; } /* genfunc requires all nodes in 'nl' to map cleanly to operations that are @@ -364,116 +364,116 @@ static size_t writeblob(FILE *fd, Blob *b, size_t off, char *lbl) * operations on x32, no structures, and so on. */ static void genfunc(FILE *fd, Func *fn, Htab *globls, Htab *strtab) { - Isel is = {0,}; - - is.reglocs = mkht(varhash, vareq); - is.stkoff = fn->stkoff; - is.envoff = fn->envoff; - is.globls = globls; - is.ret = fn->ret; - is.cfg = fn->cfg; - if (fn->hasenv) - is.envp = locreg(ModeQ); - - selfunc(&is, fn, globls, strtab); - if (debugopt['i']) - writeasm(stdout, &is, fn); - writeasm(fd, &is, fn); + Isel is = {0,}; + + is.reglocs = mkht(varhash, vareq); + is.stkoff = fn->stkoff; + is.envoff = fn->envoff; + is.globls = globls; + is.ret = fn->ret; + is.cfg = fn->cfg; + if (fn->hasenv) + is.envp = locreg(ModeQ); + + selfunc(&is, fn, globls, strtab); + if (debugopt['i']) + writeasm(stdout, &is, fn); + writeasm(fd, &is, fn); } static void gentype(FILE *fd, Type *ty) { - Blob *b; - char lbl[1024]; - - if (ty->type == Tyvar) - return; - b = tydescblob(ty); - if (!b) - return; - if (b->isglobl) { - fprintf(fd, "GLOBL %s%s+0(SB),$%zd\n", Symprefix, b->lbl, blobsz(b)); - bprintf(lbl, sizeof lbl, "%s%s", Symprefix, b->lbl); - } else { - fprintf(fd, "GLOBL %s%s<>+0(SB),$%zd\n", Symprefix, b->lbl, blobsz(b)); - bprintf(lbl, sizeof lbl, "%s%s<>", Symprefix, b->lbl); - } - writeblob(fd, b, 0, lbl); + Blob *b; + char lbl[1024]; + + if (ty->type == Tyvar) + return; + b = tydescblob(ty); + if (!b) + return; + if (b->isglobl) { + fprintf(fd, "GLOBL %s%s+0(SB),$%zd\n", Symprefix, b->lbl, blobsz(b)); + bprintf(lbl, sizeof lbl, "%s%s", Symprefix, b->lbl); + } else { + fprintf(fd, "GLOBL %s%s<>+0(SB),$%zd\n", Symprefix, b->lbl, blobsz(b)); + bprintf(lbl, sizeof lbl, "%s%s<>", Symprefix, b->lbl); + } + writeblob(fd, b, 0, lbl); } static void genblob(FILE *fd, Node *blob, Htab *globls, Htab *strtab) { - char *lbl; - Blob *b; - - /* lits and such also get wrapped in decls */ - assert(blob->type == Ndecl); - - lbl = htget(globls, blob); - fprintf(fd, "GLOBL %s+0(SB),$%zd\n", lbl, size(blob)); - if (blob->decl.init) - b = litblob(globls, strtab, blob->decl.init); - else - b = mkblobpad(size(blob)); - writeblob(fd, b, 0, lbl); + char *lbl; + Blob *b; + + /* lits and such also get wrapped in decls */ + assert(blob->type == Ndecl); + + lbl = htget(globls, blob); + fprintf(fd, "GLOBL %s+0(SB),$%zd\n", lbl, size(blob)); + if (blob->decl.init) + b = litblob(globls, strtab, blob->decl.init); + else + b = mkblobpad(size(blob)); + writeblob(fd, b, 0, lbl); } void genp9(Node *file, char *out) { - Htab *globls, *strtab; - Node *n, **blob; - Func **fn; - size_t nfn, nblob; - size_t i; - FILE *fd; - - /* ensure that all physical registers have a loc created before any - * other locs, so that locmap[Physreg] maps to the Loc for the physreg - * in question */ - for (i = 0; i < Nreg; i++) - locphysreg(i); - - fn = NULL; - nfn = 0; - blob = NULL; - nblob = 0; - globls = mkht(varhash, vareq); - initconsts(globls); - - /* We need to define all global variables before use */ - fillglobls(file->file.globls, globls); - - pushstab(file->file.globls); - for (i = 0; i < file->file.nstmts; i++) { - n = file->file.stmts[i]; - switch (n->type) { - case Nuse: /* nothing to do */ - case Nimpl: - break; - case Ndecl: - simpglobl(n, globls, &fn, &nfn, &blob, &nblob); - break; - default: - die("Bad node %s in toplevel", nodestr[n->type]); - break; - } - } - popstab(); - - fd = fopen(out, "w"); - if (!fd) - die("Couldn't open fd %s", out); - - strtab = mkht(strlithash, strliteq); - for (i = 0; i < nblob; i++) - genblob(fd, blob[i], globls, strtab); - for (i = 0; i < nfn; i++) - genfunc(fd, fn[i], globls, strtab); - for (i = 0; i < ntypes; i++) - if (types[i]->isreflect && !types[i]->isimport) - gentype(fd, types[i]); - fprintf(fd, "\n"); - genstrings(fd, strtab); - - fclose(fd); + Htab *globls, *strtab; + Node *n, **blob; + Func **fn; + size_t nfn, nblob; + size_t i; + FILE *fd; + + /* ensure that all physical registers have a loc created before any + * other locs, so that locmap[Physreg] maps to the Loc for the physreg + * in question */ + for (i = 0; i < Nreg; i++) + locphysreg(i); + + fn = NULL; + nfn = 0; + blob = NULL; + nblob = 0; + globls = mkht(varhash, vareq); + initconsts(globls); + + /* We need to define all global variables before use */ + fillglobls(file->file.globls, globls); + + pushstab(file->file.globls); + for (i = 0; i < file->file.nstmts; i++) { + n = file->file.stmts[i]; + switch (n->type) { + case Nuse: /* nothing to do */ + case Nimpl: + break; + case Ndecl: + simpglobl(n, globls, &fn, &nfn, &blob, &nblob); + break; + default: + die("Bad node %s in toplevel", nodestr[n->type]); + break; + } + } + popstab(); + + fd = fopen(out, "w"); + if (!fd) + die("Couldn't open fd %s", out); + + strtab = mkht(strlithash, strliteq); + for (i = 0; i < nblob; i++) + genblob(fd, blob[i], globls, strtab); + for (i = 0; i < nfn; i++) + genfunc(fd, fn[i], globls, strtab); + for (i = 0; i < ntypes; i++) + if (types[i]->isreflect && !types[i]->isimport) + gentype(fd, types[i]); + fprintf(fd, "\n"); + genstrings(fd, strtab); + + fclose(fd); } diff --git a/6/isel.c b/6/isel.c index 18b0e78..356bdca 100644 --- a/6/isel.c +++ b/6/isel.c @@ -22,244 +22,244 @@ Loc *selexpr(Isel *s, Node *n); #define Nfloatregargs 8 #define Nintregargs 6 regid floatargregs[] = { - Rxmm0d, Rxmm1d, Rxmm2d, Rxmm3d, - Rxmm4d, Rxmm5d, Rxmm6d, Rxmm7d, + Rxmm0d, Rxmm1d, Rxmm2d, Rxmm3d, + Rxmm4d, Rxmm5d, Rxmm6d, Rxmm7d, }; regid intargregs[] = {Rrdi, Rrsi, Rrdx, Rrcx, Rr8, Rr9}; /* used to decide which operator is appropriate * for implementing various conditional operators */ struct { - AsmOp test; - AsmOp jmp; - AsmOp getflag; + AsmOp test; + AsmOp jmp; + AsmOp getflag; } reloptab[Numops] = { - [Olnot] = {Itest, Ijz, Isetz}, /* lnot invalid for floats */ - /* signed int */ - [Oeq] = {Icmp, Ijz, Isetz}, - [One] = {Icmp, Ijnz, Isetnz}, - [Ogt] = {Icmp, Ijg, Isetg}, - [Oge] = {Icmp, Ijge, Isetge}, - [Olt] = {Icmp, Ijl, Isetl}, - [Ole] = {Icmp, Ijle, Isetle}, - /* unsigned int */ - [Oueq] = {Icmp, Ijz, Isetz}, - [Oune] = {Icmp, Ijnz, Isetnz}, - [Ougt] = {Icmp, Ija, Iseta}, - [Ouge] = {Icmp, Ijae, Isetae}, - [Oult] = {Icmp, Ijb, Isetb}, - [Oule] = {Icmp, Ijbe, Isetbe}, - /* float */ - [Ofeq] = {Icomis, Ijz, Isetz}, - [Ofne] = {Icomis, Ijnz, Isetnz}, - [Ofgt] = {Icomis, Ija, Iseta}, - [Ofge] = {Icomis, Ijae, Isetae}, - [Oflt] = {Icomis, Ijb, Isetb}, - [Ofle] = {Icomis, Ijbe, Isetbe}, + [Olnot] = {Itest, Ijz, Isetz}, /* lnot invalid for floats */ + /* signed int */ + [Oeq] = {Icmp, Ijz, Isetz}, + [One] = {Icmp, Ijnz, Isetnz}, + [Ogt] = {Icmp, Ijg, Isetg}, + [Oge] = {Icmp, Ijge, Isetge}, + [Olt] = {Icmp, Ijl, Isetl}, + [Ole] = {Icmp, Ijle, Isetle}, + /* unsigned int */ + [Oueq] = {Icmp, Ijz, Isetz}, + [Oune] = {Icmp, Ijnz, Isetnz}, + [Ougt] = {Icmp, Ija, Iseta}, + [Ouge] = {Icmp, Ijae, Isetae}, + [Oult] = {Icmp, Ijb, Isetb}, + [Oule] = {Icmp, Ijbe, Isetbe}, + /* float */ + [Ofeq] = {Icomis, Ijz, Isetz}, + [Ofne] = {Icomis, Ijnz, Isetnz}, + [Ofgt] = {Icomis, Ija, Iseta}, + [Ofge] = {Icomis, Ijae, Isetae}, + [Oflt] = {Icomis, Ijb, Isetb}, + [Ofle] = {Icomis, Ijbe, Isetbe}, }; static Mode tymode(Type *t) { - /* FIXME: What should the mode for, say, structs be when we have no - * intention of loading /through/ the pointer? For now, we'll just say it's - * the pointer mode, since we expect to address through the pointer */ - t = tybase(t); - switch (t->type) { - case Tyflt32: return ModeF; break; - case Tyflt64: return ModeD; break; - default: - if (isstacktype(t)) - return ModeQ; - switch (tysize(t)) { - case 1: return ModeB; break; - case 2: return ModeW; break; - case 4: return ModeL; break; - case 8: return ModeQ; break; - } - break; - } - return ModeQ; + /* FIXME: What should the mode for, say, structs be when we have no + * intention of loading /through/ the pointer? For now, we'll just say it's + * the pointer mode, since we expect to address through the pointer */ + t = tybase(t); + switch (t->type) { + case Tyflt32: return ModeF; break; + case Tyflt64: return ModeD; break; + default: + if (isstacktype(t)) + return ModeQ; + switch (tysize(t)) { + case 1: return ModeB; break; + case 2: return ModeW; break; + case 4: return ModeL; break; + case 8: return ModeQ; break; + } + break; + } + return ModeQ; } static Mode mode(Node *n) { - if (n->type == Nexpr) - return tymode(exprtype(n)); - else if (n->type == Ndecl) - return tymode(n->decl.type); - else - die("invalid node type"); - return ModeNone; + if (n->type == Nexpr) + return tymode(exprtype(n)); + else if (n->type == Ndecl) + return tymode(n->decl.type); + else + die("invalid node type"); + return ModeNone; } static Loc *varloc(Isel *s, Node *n) { - ssize_t off; - Loc *l, *rip; - - /* we need to try getting it from the stack first, in case we - * forced it to stack for addressing */ - if (hthas(s->globls, n)) { - rip = locphysreg(Rrip); - l = locmeml(htget(s->globls, n), rip, NULL, mode(n)); - } else if (hthas(s->envoff, n)) { - off = ptoi(htget(s->envoff, n)); - l = locmem(off, s->envp, NULL, mode(n)); - } else if (hthas(s->stkoff, n)) { - off = ptoi(htget(s->stkoff, n)); - l = locmem(-off, locphysreg(Rrbp), NULL, mode(n)); - } else { - l = htget(s->reglocs, n); - if (!l) { - l = locreg(mode(n)); - htput(s->reglocs, n, l); - } - } - return l; + ssize_t off; + Loc *l, *rip; + + /* we need to try getting it from the stack first, in case we + * forced it to stack for addressing */ + if (hthas(s->globls, n)) { + rip = locphysreg(Rrip); + l = locmeml(htget(s->globls, n), rip, NULL, mode(n)); + } else if (hthas(s->envoff, n)) { + off = ptoi(htget(s->envoff, n)); + l = locmem(off, s->envp, NULL, mode(n)); + } else if (hthas(s->stkoff, n)) { + off = ptoi(htget(s->stkoff, n)); + l = locmem(-off, locphysreg(Rrbp), NULL, mode(n)); + } else { + l = htget(s->reglocs, n); + if (!l) { + l = locreg(mode(n)); + htput(s->reglocs, n, l); + } + } + return l; } static Loc *loc(Isel *s, Node *n) { - Node *v; - Loc *l; - - if (n->type == Ndecl) { - l = varloc(s, n); - } else { - switch (exprop(n)) { - case Ovar: - l = varloc(s, n); - break; - case Olit: - v = n->expr.args[0]; - switch (v->lit.littype) { - case Lchr: l = loclit(v->lit.chrval, mode(n)); break; - case Lbool: l = loclit(v->lit.boolval, mode(n)); break; - case Lint: l = loclit(v->lit.intval, mode(n)); break; - default: - die("Literal type %s should be blob", litstr[v->lit.littype]); - } - break; - default: - die("Node %s not leaf in loc()", opstr[exprop(n)]); - break; - } - } - return l; + Node *v; + Loc *l; + + if (n->type == Ndecl) { + l = varloc(s, n); + } else { + switch (exprop(n)) { + case Ovar: + l = varloc(s, n); + break; + case Olit: + v = n->expr.args[0]; + switch (v->lit.littype) { + case Lchr: l = loclit(v->lit.chrval, mode(n)); break; + case Lbool: l = loclit(v->lit.boolval, mode(n)); break; + case Lint: l = loclit(v->lit.intval, mode(n)); break; + default: + die("Literal type %s should be blob", litstr[v->lit.littype]); + } + break; + default: + die("Node %s not leaf in loc()", opstr[exprop(n)]); + break; + } + } + return l; } static Insn *mkinsnv(AsmOp op, va_list ap) { - Loc *l; - Insn *i; - int n; - static size_t insnid; - - n = 0; - i = malloc(sizeof(Insn)); - i->op = op; - i->uid = insnid++; - while ((l = va_arg(ap, Loc*)) != NULL) - i->args[n++] = l; - i->nargs = n; - return i; + Loc *l; + Insn *i; + int n; + static size_t insnid; + + n = 0; + i = malloc(sizeof(Insn)); + i->op = op; + i->uid = insnid++; + while ((l = va_arg(ap, Loc*)) != NULL) + i->args[n++] = l; + i->nargs = n; + return i; } Insn *mkinsn(AsmOp op, ...) { - va_list ap; - Insn *i; + va_list ap; + Insn *i; - va_start(ap, op); - i = mkinsnv(op, ap); - va_end(ap); - return i; + va_start(ap, op); + i = mkinsnv(op, ap); + va_end(ap); + return i; } static void g(Isel *s, AsmOp op, ...) { - va_list ap; - Insn *i; - - va_start(ap, op); - i = mkinsnv(op, ap); - va_end(ap); - if (debugopt['i']) { - printf("GEN[uid=%zd] ", i->uid); - dbgiprintf(stdout, i); - } - lappend(&s->curbb->il, &s->curbb->ni, i); + va_list ap; + Insn *i; + + va_start(ap, op); + i = mkinsnv(op, ap); + va_end(ap); + if (debugopt['i']) { + printf("GEN[uid=%zd] ", i->uid); + dbgiprintf(stdout, i); + } + lappend(&s->curbb->il, &s->curbb->ni, i); } static void movz(Isel *s, Loc *src, Loc *dst) { - if (src->mode == dst->mode) - g(s, Imov, src, dst, NULL); - else - g(s, Imovzx, src, dst, NULL); + if (src->mode == dst->mode) + g(s, Imov, src, dst, NULL); + else + g(s, Imovzx, src, dst, NULL); } static void load(Isel *s, Loc *a, Loc *b) { - Loc *l; - - assert(b->type == Locreg); - if (a->type == Locreg) - l = locmem(0, b, NULL, a->mode); - else - l = a; - if (isfloatmode(b->mode)) - g(s, Imovs, l, b, NULL); - else - g(s, Imov, l, b, NULL); + Loc *l; + + assert(b->type == Locreg); + if (a->type == Locreg) + l = locmem(0, b, NULL, a->mode); + else + l = a; + if (isfloatmode(b->mode)) + g(s, Imovs, l, b, NULL); + else + g(s, Imov, l, b, NULL); } static void stor(Isel *s, Loc *a, Loc *b) { - Loc *l; - - assert(a->type == Locreg || a->type == Loclit); - if (b->type == Locreg) - l = locmem(0, b, NULL, b->mode); - else - l = b; - if (isfloatmode(b->mode)) - g(s, Imovs, a, l, NULL); - else - g(s, Imov, a, l, NULL); + Loc *l; + + assert(a->type == Locreg || a->type == Loclit); + if (b->type == Locreg) + l = locmem(0, b, NULL, b->mode); + else + l = b; + if (isfloatmode(b->mode)) + g(s, Imovs, a, l, NULL); + else + g(s, Imov, a, l, NULL); } /* ensures that a location is within a reg */ static Loc *newr(Isel *s, Loc *a) { - Loc *r; - - r = locreg(a->mode); - if (a->type == Locreg) { - if (isfloatmode(a->mode)) - g(s, Imovs, a, r, NULL); - else - g(s, Imov, a, r, NULL); - } else { - load(s, a, r); - } - return r; + Loc *r; + + r = locreg(a->mode); + if (a->type == Locreg) { + if (isfloatmode(a->mode)) + g(s, Imovs, a, r, NULL); + else + g(s, Imov, a, r, NULL); + } else { + load(s, a, r); + } + return r; } static Loc *inr(Isel *s, Loc *a) { - if (a->type == Locreg) - return a; - return newr(s, a); + if (a->type == Locreg) + return a; + return newr(s, a); } /* ensures that a location is within a reg or an imm */ static Loc *inri(Isel *s, Loc *a) { - if (a->type == Locreg || a->type == Loclit) - return a; - else - return newr(s, a); + if (a->type == Locreg || a->type == Loclit) + return a; + else + return newr(s, a); } /* If we're testing equality, etc, it's a bit silly @@ -273,35 +273,35 @@ static Loc *inri(Isel *s, Loc *a) * directly */ static void selcjmp(Isel *s, Node *n, Node **args) { - Loc *a, *b; - Loc *l1, *l2; - AsmOp cond, jmp; - - cond = reloptab[exprop(args[0])].test; - jmp = reloptab[exprop(args[0])].jmp; - /* if we have a cond, we're knocking off the redundant test, - * and want to eval the children */ - if (cond) { - a = selexpr(s, args[0]->expr.args[0]); - if (args[0]->expr.nargs == 2) - b = selexpr(s, args[0]->expr.args[1]); - else - b = a; - a = newr(s, a); - } else { - cond = Itest; - jmp = Ijnz; - b = newr(s, selexpr(s, args[0])); /* cond */ - a = b; - } - - /* the jump targets will always be evaluated the same way */ - l1 = loclbl(args[1]); /* if true */ - l2 = loclbl(args[2]); /* if false */ - - g(s, cond, b, a, NULL); - g(s, jmp, l1, NULL); - g(s, Ijmp, l2, NULL); + Loc *a, *b; + Loc *l1, *l2; + AsmOp cond, jmp; + + cond = reloptab[exprop(args[0])].test; + jmp = reloptab[exprop(args[0])].jmp; + /* if we have a cond, we're knocking off the redundant test, + * and want to eval the children */ + if (cond) { + a = selexpr(s, args[0]->expr.args[0]); + if (args[0]->expr.nargs == 2) + b = selexpr(s, args[0]->expr.args[1]); + else + b = a; + a = newr(s, a); + } else { + cond = Itest; + jmp = Ijnz; + b = newr(s, selexpr(s, args[0])); /* cond */ + a = b; + } + + /* the jump targets will always be evaluated the same way */ + l1 = loclbl(args[1]); /* if true */ + l2 = loclbl(args[2]); /* if false */ + + g(s, cond, b, a, NULL); + g(s, jmp, l1, NULL); + g(s, Ijmp, l2, NULL); } /* Generate variable length jump. There are 3 cases @@ -320,13 +320,13 @@ static void selvjmp(Isel *s, Node *n, Node **args) static Loc *binop(Isel *s, AsmOp op, Node *x, Node *y) { - Loc *a, *b; + Loc *a, *b; - a = selexpr(s, x); - b = selexpr(s, y); - a = newr(s, a); - g(s, op, b, a, NULL); - return a; + a = selexpr(s, x); + b = selexpr(s, y); + a = newr(s, a); + g(s, op, b, a, NULL); + return a; } /* We have a few common cases to optimize here: @@ -344,723 +344,723 @@ static Loc *binop(Isel *s, AsmOp op, Node *x, Node *y) */ static int ismergablemul(Node *n, int *r) { - int v; - - if (exprop(n) != Omul) - return 0; - if (exprop(n->expr.args[1]) != Olit) - return 0; - if (n->expr.args[1]->expr.args[0]->type != Nlit) - return 0; - if (n->expr.args[1]->expr.args[0]->lit.littype != Lint) - return 0; - v = n->expr.args[1]->expr.args[0]->lit.intval; - if (v != 2 && v != 4 && v != 8) - return 0; - *r = v; - return 1; + int v; + + if (exprop(n) != Omul) + return 0; + if (exprop(n->expr.args[1]) != Olit) + return 0; + if (n->expr.args[1]->expr.args[0]->type != Nlit) + return 0; + if (n->expr.args[1]->expr.args[0]->lit.littype != Lint) + return 0; + v = n->expr.args[1]->expr.args[0]->lit.intval; + if (v != 2 && v != 4 && v != 8) + return 0; + *r = v; + return 1; } static Loc *memloc(Isel *s, Node *e, Mode m) { - Node **args; - Loc *l, *b, *o; /* location, base, offset */ - int scale; - - scale = 1; - l = NULL; - args = e->expr.args; - if (exprop(e) == Oadd) { - b = selexpr(s, args[0]); - if (ismergablemul(args[1], &scale)) - o = selexpr(s, args[1]->expr.args[0]); - else - o = selexpr(s, args[1]); - - if (b->type != Locreg) - b = inr(s, b); - if (o->type == Loclit) { - l = locmem(scale*o->lit, b, NULL, m); - } else { - b = inr(s, b); - o = inr(s, o); - l = locmems(0, b, o, scale, m); - } - } else { - l = selexpr(s, e); - l = inr(s, l); - l = locmem(0, l, NULL, m); - } - assert(l != NULL); - return l; + Node **args; + Loc *l, *b, *o; /* location, base, offset */ + int scale; + + scale = 1; + l = NULL; + args = e->expr.args; + if (exprop(e) == Oadd) { + b = selexpr(s, args[0]); + if (ismergablemul(args[1], &scale)) + o = selexpr(s, args[1]->expr.args[0]); + else + o = selexpr(s, args[1]); + + if (b->type != Locreg) + b = inr(s, b); + if (o->type == Loclit) { + l = locmem(scale*o->lit, b, NULL, m); + } else { + b = inr(s, b); + o = inr(s, o); + l = locmems(0, b, o, scale, m); + } + } else { + l = selexpr(s, e); + l = inr(s, l); + l = locmem(0, l, NULL, m); + } + assert(l != NULL); + return l; } static const Mode szmodes[] = { - [8] = ModeQ, - [4] = ModeL, - [2] = ModeW, - [1] = ModeB + [8] = ModeQ, + [4] = ModeL, + [2] = ModeW, + [1] = ModeB }; static void blit(Isel *s, Loc *to, Loc *from, size_t dstoff, size_t srcoff, size_t sz, size_t align) { - size_t i, modesz; - Loc *sp, *dp, *len; /* pointers to src, dst */ - Loc *tmp, *src, *dst; /* source memory, dst memory */ - - assert(szmodes[align] != ModeNone); /* make sure we have a valid alignment */ - sp = inr(s, from); - dp = inr(s, to); - - i = 0; - if (align == 0) - align = 8; - if (sz <= 128) { /* arbitrary threshold; should be tuned */ - for (modesz = align; szmodes[modesz] != ModeNone; modesz /= 2) { - tmp = locreg(szmodes[modesz]); - while (i + modesz <= sz) { - src = locmem(i + srcoff, sp, NULL, szmodes[modesz]); - dst = locmem(i + dstoff, dp, NULL, szmodes[modesz]); - g(s, Imov, src, tmp, NULL); - g(s, Imov, tmp, dst, NULL); - i += modesz; - } - } - } else { - len = loclit(sz, ModeQ); - sp = newr(s, from); - dp = newr(s, to); - - /* length to blit */ - g(s, Imov, len, locphysreg(Rrcx), NULL); - /* source address with offset */ - if (srcoff) - g(s, Ilea, locmem(srcoff, sp, NULL, ModeQ), locphysreg(Rrsi), NULL); - else - g(s, Imov, sp, locphysreg(Rrsi), NULL); - /* dest address with offset */ - if (dstoff) - g(s, Ilea, locmem(dstoff, dp, NULL, ModeQ), locphysreg(Rrdi), NULL); - else - g(s, Imov, dp, locphysreg(Rrdi), NULL); - g(s, Irepmovsb, NULL); - } - + size_t i, modesz; + Loc *sp, *dp, *len; /* pointers to src, dst */ + Loc *tmp, *src, *dst; /* source memory, dst memory */ + + assert(szmodes[align] != ModeNone); /* make sure we have a valid alignment */ + sp = inr(s, from); + dp = inr(s, to); + + i = 0; + if (align == 0) + align = 8; + if (sz <= 128) { /* arbitrary threshold; should be tuned */ + for (modesz = align; szmodes[modesz] != ModeNone; modesz /= 2) { + tmp = locreg(szmodes[modesz]); + while (i + modesz <= sz) { + src = locmem(i + srcoff, sp, NULL, szmodes[modesz]); + dst = locmem(i + dstoff, dp, NULL, szmodes[modesz]); + g(s, Imov, src, tmp, NULL); + g(s, Imov, tmp, dst, NULL); + i += modesz; + } + } + } else { + len = loclit(sz, ModeQ); + sp = newr(s, from); + dp = newr(s, to); + + /* length to blit */ + g(s, Imov, len, locphysreg(Rrcx), NULL); + /* source address with offset */ + if (srcoff) + g(s, Ilea, locmem(srcoff, sp, NULL, ModeQ), locphysreg(Rrsi), NULL); + else + g(s, Imov, sp, locphysreg(Rrsi), NULL); + /* dest address with offset */ + if (dstoff) + g(s, Ilea, locmem(dstoff, dp, NULL, ModeQ), locphysreg(Rrdi), NULL); + else + g(s, Imov, dp, locphysreg(Rrdi), NULL); + g(s, Irepmovsb, NULL); + } + } static void clear(Isel *s, Loc *val, size_t sz, size_t align) { - Loc *dp, *len, *rax; /* pointers to src, dst */ - Loc *zero, *dst; /* source memory, dst memory */ - size_t modesz, i; - - i = 0; - dp = inr(s, val); - rax = locphysreg(Rrax); - g(s, Ixor, rax, rax, NULL); - if (align == 0) - align = 8; - if (sz <= 128) { /* arbitrary threshold; should be tuned */ - for (modesz = align; szmodes[modesz] != ModeNone; modesz /= 2) { - zero = loclit(0, szmodes[modesz]); - while (i + modesz <= sz) { - zero = coreg(Rrax, szmodes[modesz]); - dst = locmem(i, dp, NULL, szmodes[modesz]); - g(s, Imov, zero, dst, NULL); - i += modesz; - } - } - } else { - len = loclit(sz, ModeQ); - /* length to blit */ - g(s, Imov, len, locphysreg(Rrcx), NULL); - g(s, Imov, dp, locphysreg(Rrdi), NULL); - g(s, Irepstosb, NULL); - } + Loc *dp, *len, *rax; /* pointers to src, dst */ + Loc *zero, *dst; /* source memory, dst memory */ + size_t modesz, i; + + i = 0; + dp = inr(s, val); + rax = locphysreg(Rrax); + g(s, Ixor, rax, rax, NULL); + if (align == 0) + align = 8; + if (sz <= 128) { /* arbitrary threshold; should be tuned */ + for (modesz = align; szmodes[modesz] != ModeNone; modesz /= 2) { + zero = loclit(0, szmodes[modesz]); + while (i + modesz <= sz) { + zero = coreg(Rrax, szmodes[modesz]); + dst = locmem(i, dp, NULL, szmodes[modesz]); + g(s, Imov, zero, dst, NULL); + i += modesz; + } + } + } else { + len = loclit(sz, ModeQ); + /* length to blit */ + g(s, Imov, len, locphysreg(Rrcx), NULL); + g(s, Imov, dp, locphysreg(Rrdi), NULL); + g(s, Irepstosb, NULL); + } } static void call(Isel *s, Node *n) { - AsmOp op; - Node *fn; - Loc *f, *e; - - if (exprop(n) == Ocall) { - op = Icall; - fn = n->expr.args[0]; - assert(tybase(exprtype(fn))->type == Tycode); - f = locmeml(htget(s->globls, fn), NULL, NULL, mode(fn)); - } else { - op = Icallind; - f = selexpr(s, n->expr.args[0]); - e = selexpr(s, n->expr.args[1]); - g(s, Imov, e, locphysreg(Rrax), NULL); - } - g(s, op, f, NULL); + AsmOp op; + Node *fn; + Loc *f, *e; + + if (exprop(n) == Ocall) { + op = Icall; + fn = n->expr.args[0]; + assert(tybase(exprtype(fn))->type == Tycode); + f = locmeml(htget(s->globls, fn), NULL, NULL, mode(fn)); + } else { + op = Icallind; + f = selexpr(s, n->expr.args[0]); + e = selexpr(s, n->expr.args[1]); + g(s, Imov, e, locphysreg(Rrax), NULL); + } + g(s, op, f, NULL); } static size_t countargs(Type *t) { - size_t nargs; - - t = tybase(t); - nargs = t->nsub - 1; - if (isstacktype(t->sub[0])) - nargs++; - /* valists are replaced with hidden type parameter, - * which we want on the stack for ease of ABI */ - if (tybase(t->sub[t->nsub - 1])->type == Tyvalist) - nargs--; - return nargs; + size_t nargs; + + t = tybase(t); + nargs = t->nsub - 1; + if (isstacktype(t->sub[0])) + nargs++; + /* valists are replaced with hidden type parameter, + * which we want on the stack for ease of ABI */ + if (tybase(t->sub[t->nsub - 1])->type == Tyvalist) + nargs--; + return nargs; } static Loc *gencall(Isel *s, Node *n) { - Loc *src, *dst, *arg; /* values we reduced */ - size_t argsz, argoff, nargs, vasplit; - size_t nfloats, nints; - Loc *retloc, *rsp, *ret; /* hard-coded registers */ - Loc *stkbump; /* calculated stack offset */ - Type *t, *fn; - Node **args; - size_t i, a; - int vararg; - - rsp = locphysreg(Rrsp); - t = exprtype(n); - if (tybase(t)->type == Tyvoid || isstacktype(t)) { - retloc = NULL; - ret = NULL; - } else if (istyfloat(t)) { - retloc = coreg(Rxmm0d, mode(n)); - ret = locreg(mode(n)); - } else { - retloc = coreg(Rrax, mode(n)); - ret = locreg(mode(n)); - } - fn = tybase(exprtype(n->expr.args[0])); - /* calculate the number of args we expect to see, adjust - * for a hidden return argument. */ - vasplit = countargs(fn); - argsz = 0; - if (exprop(n) == Ocall) { - args = &n->expr.args[1]; - nargs = n->expr.nargs - 1; - } else { - args = &n->expr.args[2]; - nargs = n->expr.nargs - 2; - } - /* Have to calculate the amount to bump the stack - * pointer by in one pass first, otherwise if we push - * one at a time, we evaluate the args in reverse order. - * Not good. - * - * Skip the first operand, since it's the function itself */ - for (i = 0; i < nargs; i++) { - argsz = align(argsz, min(size(args[i]), Ptrsz)); - argsz += size(args[i]); - } - argsz = align(argsz, 16); - stkbump = loclit(argsz, ModeQ); - if (argsz) - g(s, Isub, stkbump, rsp, NULL); - - /* Now, we can evaluate the arguments */ - argoff = 0; - nfloats = 0; - nints = 0; - vararg = 0; - for (i = 0; i < nargs; i++) { - arg = selexpr(s, args[i]); - argoff = alignto(argoff, exprtype(args[i])); - if (i >= vasplit) - vararg = 1; - if (stacknode(args[i])) { - src = locreg(ModeQ); - g(s, Ilea, arg, src, NULL); - a = tyalign(exprtype(args[i])); - blit(s, rsp, src, argoff, 0, size(args[i]), a); - argoff += size(args[i]); - } else if (!vararg && isfloatmode(arg->mode) && nfloats < Nfloatregargs) { - dst = coreg(floatargregs[nfloats], arg->mode); - arg = inri(s, arg); - g(s, Imovs, arg, dst, NULL); - nfloats++; - } else if (!vararg && isintmode(arg->mode) && nints < Nintregargs) { - dst = coreg(intargregs[nints], arg->mode); - arg = inri(s, arg); - g(s, Imov, arg, dst, NULL); - nints++; - } else { - dst = locmem(argoff, rsp, NULL, arg->mode); - arg = inri(s, arg); - stor(s, arg, dst); - argoff += size(args[i]); - } - } - call(s, n); - if (argsz) - g(s, Iadd, stkbump, rsp, NULL); - if (retloc) { - if (isfloatmode(retloc->mode)) - g(s, Imovs, retloc, ret, NULL); - else - g(s, Imov, retloc, ret, NULL); - } - return ret; + Loc *src, *dst, *arg; /* values we reduced */ + size_t argsz, argoff, nargs, vasplit; + size_t nfloats, nints; + Loc *retloc, *rsp, *ret; /* hard-coded registers */ + Loc *stkbump; /* calculated stack offset */ + Type *t, *fn; + Node **args; + size_t i, a; + int vararg; + + rsp = locphysreg(Rrsp); + t = exprtype(n); + if (tybase(t)->type == Tyvoid || isstacktype(t)) { + retloc = NULL; + ret = NULL; + } else if (istyfloat(t)) { + retloc = coreg(Rxmm0d, mode(n)); + ret = locreg(mode(n)); + } else { + retloc = coreg(Rrax, mode(n)); + ret = locreg(mode(n)); + } + fn = tybase(exprtype(n->expr.args[0])); + /* calculate the number of args we expect to see, adjust + * for a hidden return argument. */ + vasplit = countargs(fn); + argsz = 0; + if (exprop(n) == Ocall) { + args = &n->expr.args[1]; + nargs = n->expr.nargs - 1; + } else { + args = &n->expr.args[2]; + nargs = n->expr.nargs - 2; + } + /* Have to calculate the amount to bump the stack + * pointer by in one pass first, otherwise if we push + * one at a time, we evaluate the args in reverse order. + * Not good. + * + * Skip the first operand, since it's the function itself */ + for (i = 0; i < nargs; i++) { + argsz = align(argsz, min(size(args[i]), Ptrsz)); + argsz += size(args[i]); + } + argsz = align(argsz, 16); + stkbump = loclit(argsz, ModeQ); + if (argsz) + g(s, Isub, stkbump, rsp, NULL); + + /* Now, we can evaluate the arguments */ + argoff = 0; + nfloats = 0; + nints = 0; + vararg = 0; + for (i = 0; i < nargs; i++) { + arg = selexpr(s, args[i]); + argoff = alignto(argoff, exprtype(args[i])); + if (i >= vasplit) + vararg = 1; + if (stacknode(args[i])) { + src = locreg(ModeQ); + g(s, Ilea, arg, src, NULL); + a = tyalign(exprtype(args[i])); + blit(s, rsp, src, argoff, 0, size(args[i]), a); + argoff += size(args[i]); + } else if (!vararg && isfloatmode(arg->mode) && nfloats < Nfloatregargs) { + dst = coreg(floatargregs[nfloats], arg->mode); + arg = inri(s, arg); + g(s, Imovs, arg, dst, NULL); + nfloats++; + } else if (!vararg && isintmode(arg->mode) && nints < Nintregargs) { + dst = coreg(intargregs[nints], arg->mode); + arg = inri(s, arg); + g(s, Imov, arg, dst, NULL); + nints++; + } else { + dst = locmem(argoff, rsp, NULL, arg->mode); + arg = inri(s, arg); + stor(s, arg, dst); + argoff += size(args[i]); + } + } + call(s, n); + if (argsz) + g(s, Iadd, stkbump, rsp, NULL); + if (retloc) { + if (isfloatmode(retloc->mode)) + g(s, Imovs, retloc, ret, NULL); + else + g(s, Imov, retloc, ret, NULL); + } + return ret; } Loc *selexpr(Isel *s, Node *n) { - Loc *a, *b, *c, *d, *r; - Loc *edx, *cl; /* x86 wants some hard-coded regs */ - Node **args; - size_t al; - Op op; - - args = n->expr.args; - edx = locphysreg(Redx); - cl = locphysreg(Rcl); - r = NULL; - switch (exprop(n)) { - case Oadd: r = binop(s, Iadd, args[0], args[1]); break; - case Osub: r = binop(s, Isub, args[0], args[1]); break; - case Obor: r = binop(s, Ior, args[0], args[1]); break; - case Oband: r = binop(s, Iand, args[0], args[1]); break; - case Obxor: r = binop(s, Ixor, args[0], args[1]); break; - case Omul: - if (size(args[0]) == 1) { - a = selexpr(s, args[0]); - b = inr(s, selexpr(s, args[1])); - - c = locphysreg(Ral); - r = locreg(a->mode); - g(s, Imov, a, c, NULL); - g(s, Iimul_r, b, NULL); - g(s, Imov, c, r, NULL); - } else { - r = binop(s, Iimul, args[0], args[1]); - } - break; - case Odiv: - case Omod: - /* these get clobbered by the div insn */ - a = selexpr(s, args[0]); - b = selexpr(s, args[1]); - b = newr(s, b); - c = coreg(Reax, mode(n)); - r = locreg(a->mode); - g(s, Imov, a, c, NULL); - if (istysigned(exprtype(args[0]))) { - switch (r->mode) { - case ModeB: g(s, Imovsx, c, coreg(Rrax, ModeW), NULL); break; - case ModeW: g(s, Icwd, NULL); break; - case ModeL: g(s, Icdq, NULL); break; - case ModeQ: g(s, Icqo, NULL); break; - default: die("invalid mode in division"); break; - } - g(s, Iidiv, b, NULL); - } else { - if (r->mode == ModeB) - g(s, Ixor, locphysreg(Rah), locphysreg(Rah), NULL); - else - g(s, Ixor, edx, edx, NULL); - g(s, Idiv, b, NULL); - } - if (exprop(n) == Odiv) - d = coreg(Reax, mode(n)); - else if (r->mode != ModeB) - d = coreg(Redx, mode(n)); - else - d = locphysreg(Rah); - g(s, Imov, d, r, NULL); - break; - case Oneg: - r = selexpr(s, args[0]); - r = newr(s, r); - g(s, Ineg, r, NULL); - break; - - /* fp expressions */ - case Ofadd: r = binop(s, Iadds, args[0], args[1]); break; - case Ofsub: r = binop(s, Isubs, args[0], args[1]); break; - case Ofmul: r = binop(s, Imuls, args[0], args[1]); break; - case Ofdiv: r = binop(s, Idivs, args[0], args[1]); break; - case Ofneg: - r = selexpr(s, args[0]); - r = newr(s, r); - a = NULL; - b = NULL; - if (mode(args[0]) == ModeF) { - a = locreg(ModeF); - b = loclit(1LL << (31), ModeF); - g(s, Imovs, r, a); - } else if (mode(args[0]) == ModeD) { - a = locreg(ModeQ); - b = loclit(1LL << 63, ModeQ); - g(s, Imov, r, a, NULL); - } - g(s, Ixor, b, a, NULL); - g(s, Imov, a, r, NULL); - break; - case Obsl: - case Obsr: - a = newr(s, selexpr(s, args[0])); - b = selexpr(s, args[1]); - if (b->type == Loclit) { - d = b; - } else { - c = coreg(Rcl, b->mode); - g(s, Imov, b, c, NULL); - d = cl; - } - if (exprop(n) == Obsr) { - if (istysigned(n->expr.type)) - g(s, Isar, d, a, NULL); - else - g(s, Ishr, d, a, NULL); - } else { - g(s, Ishl, d, a, NULL); - } - r = a; - break; - case Obnot: - r = selexpr(s, args[0]); - r = newr(s, r); - g(s, Inot, r, NULL); - break; - - case Oderef: - r = memloc(s, args[0], mode(n)); - break; - - case Oaddr: - a = selexpr(s, args[0]); - if (a->type == Loclbl || (a->type == Locmeml && !a->mem.base)) { - r = loclitl(a->lbl); - } else { - r = locreg(ModeQ); - g(s, Ilea, a, r, NULL); - } - break; - - case Olnot: - a = newr(s, selexpr(s, args[0])); - b = locreg(ModeB); - r = locreg(mode(n)); - /* lnot only valid for integer-like values */ - g(s, reloptab[exprop(n)].test, a, a, NULL); - g(s, reloptab[exprop(n)].getflag, b, NULL); - movz(s, b, r); - break; - - case Oeq: case One: case Ogt: case Oge: case Olt: case Ole: - case Ofeq: case Ofne: case Ofgt: case Ofge: case Oflt: case Ofle: - case Oueq: case Oune: case Ougt: case Ouge: case Oult: case Oule: - a = selexpr(s, args[0]); - b = selexpr(s, args[1]); - a = newr(s, a); - c = locreg(ModeB); - r = locreg(mode(n)); - g(s, reloptab[exprop(n)].test, b, a, NULL); - g(s, reloptab[exprop(n)].getflag, c, NULL); - movz(s, c, r); - return r; - - case Oasn: /* relabel */ - die("Unimplemented op %s", opstr[exprop(n)]); - break; - case Oset: - op = exprop(args[0]); - assert(op == Ovar || op == Oderef || op == Ogap); - assert(!stacknode(args[0])); - - if (op == Ogap) - break; - - b = selexpr(s, args[1]); - if (exprop(args[0]) == Oderef) - a = memloc(s, args[0]->expr.args[0], mode(n)); - else - a = selexpr(s, args[0]); - b = inri(s, b); - if (isfloatmode(b->mode)) - g(s, Imovs, b, a, NULL); - else - g(s, Imov, b, a, NULL); - r = b; - break; - case Ocall: - case Ocallind: - r = gencall(s, n); - break; - case Oret: - a = locstrlbl(s->cfg->end->lbls[0]); - g(s, Ijmp, a, NULL); - break; - case Ojmp: - g(s, Ijmp, loclbl(args[0]), NULL); - break; - case Ocjmp: - selcjmp(s, n, args); - break; - case Ovjmp: - selvjmp(s, n, args); - break; - case Olit: /* fall through */ - r = loc(s, n); - break; - case Ovar: - if (isconstfn(n)) { - r = locreg(ModeQ); - a = loc(s, n); - g(s, Ilea, a, r, NULL); - } else { - r = loc(s, n); - } - break; - case Ogap: - break; - case Oblit: - a = selexpr(s, args[0]); - r = selexpr(s, args[1]); - al = alignto(1, args[0]->expr.type->sub[0]); - blit(s, a, r, 0, 0, args[2]->expr.args[0]->lit.intval, al); - break; - - case Oclear: - a = selexpr(s, args[0]); - clear(s, a, args[1]->expr.args[0]->lit.intval, 0); - break; - - /* cast operators that actually modify the values */ - case Otrunc: - a = selexpr(s, args[0]); - a = inr(s, a); - r = locreg(mode(n)); - g(s, Imov, a, r, NULL); - break; - case Ozwiden: - a = selexpr(s, args[0]); - a = inr(s, a); - r = locreg(mode(n)); - movz(s, a, r); - break; - case Oswiden: - a = selexpr(s, args[0]); - a = inr(s, a); - r = locreg(mode(n)); - g(s, Imovsx, a, r, NULL); - break; - case Oint2flt: - a = selexpr(s, args[0]); - r = locreg(mode(n)); - g(s, Icvttsi2sd, a, r, NULL); - break; - case Oflt2int: - a = selexpr(s, args[0]); - r = locreg(mode(n)); - g(s, Icvttsd2si, a, r, NULL); - break; - - case Oflt2flt: - a = selexpr(s, args[0]); - r = locreg(mode(n)); - if (a->mode == ModeD) - g(s, Icvttsd2ss, a, r, NULL); - else - g(s, Icvttss2sd, a, r, NULL); - break; - case Odead: - case Oundef: - case Odef: - /* nothing */ - break; - - /* These operators should never show up in the reduced trees, - * since they should have been replaced with more primitive - * expressions by now */ - case Obad: case Opreinc: case Opostinc: case Opredec: - case Opostdec: case Olor: case Oland: case Oaddeq: - case Osubeq: case Omuleq: case Odiveq: case Omodeq: case Oboreq: - case Obandeq: case Obxoreq: case Obsleq: case Obsreq: case Omemb: - case Oslbase: case Osllen: case Ocast: case Outag: case Oudata: - case Oucon: case Otup: case Oarr: case Ostruct: - case Oslice: case Oidx: case Osize: case Otupget: case Oidxlen: - case Obreak: case Ocontinue: - case Numops: - dump(n, stdout); - die("Should not see %s in isel", opstr[exprop(n)]); - break; - } - return r; + Loc *a, *b, *c, *d, *r; + Loc *edx, *cl; /* x86 wants some hard-coded regs */ + Node **args; + size_t al; + Op op; + + args = n->expr.args; + edx = locphysreg(Redx); + cl = locphysreg(Rcl); + r = NULL; + switch (exprop(n)) { + case Oadd: r = binop(s, Iadd, args[0], args[1]); break; + case Osub: r = binop(s, Isub, args[0], args[1]); break; + case Obor: r = binop(s, Ior, args[0], args[1]); break; + case Oband: r = binop(s, Iand, args[0], args[1]); break; + case Obxor: r = binop(s, Ixor, args[0], args[1]); break; + case Omul: + if (size(args[0]) == 1) { + a = selexpr(s, args[0]); + b = inr(s, selexpr(s, args[1])); + + c = locphysreg(Ral); + r = locreg(a->mode); + g(s, Imov, a, c, NULL); + g(s, Iimul_r, b, NULL); + g(s, Imov, c, r, NULL); + } else { + r = binop(s, Iimul, args[0], args[1]); + } + break; + case Odiv: + case Omod: + /* these get clobbered by the div insn */ + a = selexpr(s, args[0]); + b = selexpr(s, args[1]); + b = newr(s, b); + c = coreg(Reax, mode(n)); + r = locreg(a->mode); + g(s, Imov, a, c, NULL); + if (istysigned(exprtype(args[0]))) { + switch (r->mode) { + case ModeB: g(s, Imovsx, c, coreg(Rrax, ModeW), NULL); break; + case ModeW: g(s, Icwd, NULL); break; + case ModeL: g(s, Icdq, NULL); break; + case ModeQ: g(s, Icqo, NULL); break; + default: die("invalid mode in division"); break; + } + g(s, Iidiv, b, NULL); + } else { + if (r->mode == ModeB) + g(s, Ixor, locphysreg(Rah), locphysreg(Rah), NULL); + else + g(s, Ixor, edx, edx, NULL); + g(s, Idiv, b, NULL); + } + if (exprop(n) == Odiv) + d = coreg(Reax, mode(n)); + else if (r->mode != ModeB) + d = coreg(Redx, mode(n)); + else + d = locphysreg(Rah); + g(s, Imov, d, r, NULL); + break; + case Oneg: + r = selexpr(s, args[0]); + r = newr(s, r); + g(s, Ineg, r, NULL); + break; + + /* fp expressions */ + case Ofadd: r = binop(s, Iadds, args[0], args[1]); break; + case Ofsub: r = binop(s, Isubs, args[0], args[1]); break; + case Ofmul: r = binop(s, Imuls, args[0], args[1]); break; + case Ofdiv: r = binop(s, Idivs, args[0], args[1]); break; + case Ofneg: + r = selexpr(s, args[0]); + r = newr(s, r); + a = NULL; + b = NULL; + if (mode(args[0]) == ModeF) { + a = locreg(ModeF); + b = loclit(1LL << (31), ModeF); + g(s, Imovs, r, a); + } else if (mode(args[0]) == ModeD) { + a = locreg(ModeQ); + b = loclit(1LL << 63, ModeQ); + g(s, Imov, r, a, NULL); + } + g(s, Ixor, b, a, NULL); + g(s, Imov, a, r, NULL); + break; + case Obsl: + case Obsr: + a = newr(s, selexpr(s, args[0])); + b = selexpr(s, args[1]); + if (b->type == Loclit) { + d = b; + } else { + c = coreg(Rcl, b->mode); + g(s, Imov, b, c, NULL); + d = cl; + } + if (exprop(n) == Obsr) { + if (istysigned(n->expr.type)) + g(s, Isar, d, a, NULL); + else + g(s, Ishr, d, a, NULL); + } else { + g(s, Ishl, d, a, NULL); + } + r = a; + break; + case Obnot: + r = selexpr(s, args[0]); + r = newr(s, r); + g(s, Inot, r, NULL); + break; + + case Oderef: + r = memloc(s, args[0], mode(n)); + break; + + case Oaddr: + a = selexpr(s, args[0]); + if (a->type == Loclbl || (a->type == Locmeml && !a->mem.base)) { + r = loclitl(a->lbl); + } else { + r = locreg(ModeQ); + g(s, Ilea, a, r, NULL); + } + break; + + case Olnot: + a = newr(s, selexpr(s, args[0])); + b = locreg(ModeB); + r = locreg(mode(n)); + /* lnot only valid for integer-like values */ + g(s, reloptab[exprop(n)].test, a, a, NULL); + g(s, reloptab[exprop(n)].getflag, b, NULL); + movz(s, b, r); + break; + + case Oeq: case One: case Ogt: case Oge: case Olt: case Ole: + case Ofeq: case Ofne: case Ofgt: case Ofge: case Oflt: case Ofle: + case Oueq: case Oune: case Ougt: case Ouge: case Oult: case Oule: + a = selexpr(s, args[0]); + b = selexpr(s, args[1]); + a = newr(s, a); + c = locreg(ModeB); + r = locreg(mode(n)); + g(s, reloptab[exprop(n)].test, b, a, NULL); + g(s, reloptab[exprop(n)].getflag, c, NULL); + movz(s, c, r); + return r; + + case Oasn: /* relabel */ + die("Unimplemented op %s", opstr[exprop(n)]); + break; + case Oset: + op = exprop(args[0]); + assert(op == Ovar || op == Oderef || op == Ogap); + assert(!stacknode(args[0])); + + if (op == Ogap) + break; + + b = selexpr(s, args[1]); + if (exprop(args[0]) == Oderef) + a = memloc(s, args[0]->expr.args[0], mode(n)); + else + a = selexpr(s, args[0]); + b = inri(s, b); + if (isfloatmode(b->mode)) + g(s, Imovs, b, a, NULL); + else + g(s, Imov, b, a, NULL); + r = b; + break; + case Ocall: + case Ocallind: + r = gencall(s, n); + break; + case Oret: + a = locstrlbl(s->cfg->end->lbls[0]); + g(s, Ijmp, a, NULL); + break; + case Ojmp: + g(s, Ijmp, loclbl(args[0]), NULL); + break; + case Ocjmp: + selcjmp(s, n, args); + break; + case Ovjmp: + selvjmp(s, n, args); + break; + case Olit: /* fall through */ + r = loc(s, n); + break; + case Ovar: + if (isconstfn(n)) { + r = locreg(ModeQ); + a = loc(s, n); + g(s, Ilea, a, r, NULL); + } else { + r = loc(s, n); + } + break; + case Ogap: + break; + case Oblit: + a = selexpr(s, args[0]); + r = selexpr(s, args[1]); + al = alignto(1, args[0]->expr.type->sub[0]); + blit(s, a, r, 0, 0, args[2]->expr.args[0]->lit.intval, al); + break; + + case Oclear: + a = selexpr(s, args[0]); + clear(s, a, args[1]->expr.args[0]->lit.intval, 0); + break; + + /* cast operators that actually modify the values */ + case Otrunc: + a = selexpr(s, args[0]); + a = inr(s, a); + r = locreg(mode(n)); + g(s, Imov, a, r, NULL); + break; + case Ozwiden: + a = selexpr(s, args[0]); + a = inr(s, a); + r = locreg(mode(n)); + movz(s, a, r); + break; + case Oswiden: + a = selexpr(s, args[0]); + a = inr(s, a); + r = locreg(mode(n)); + g(s, Imovsx, a, r, NULL); + break; + case Oint2flt: + a = selexpr(s, args[0]); + r = locreg(mode(n)); + g(s, Icvttsi2sd, a, r, NULL); + break; + case Oflt2int: + a = selexpr(s, args[0]); + r = locreg(mode(n)); + g(s, Icvttsd2si, a, r, NULL); + break; + + case Oflt2flt: + a = selexpr(s, args[0]); + r = locreg(mode(n)); + if (a->mode == ModeD) + g(s, Icvttsd2ss, a, r, NULL); + else + g(s, Icvttss2sd, a, r, NULL); + break; + case Odead: + case Oundef: + case Odef: + /* nothing */ + break; + + /* These operators should never show up in the reduced trees, + * since they should have been replaced with more primitive + * expressions by now */ + case Obad: case Opreinc: case Opostinc: case Opredec: + case Opostdec: case Olor: case Oland: case Oaddeq: + case Osubeq: case Omuleq: case Odiveq: case Omodeq: case Oboreq: + case Obandeq: case Obxoreq: case Obsleq: case Obsreq: case Omemb: + case Oslbase: case Osllen: case Ocast: case Outag: case Oudata: + case Oucon: case Otup: case Oarr: case Ostruct: + case Oslice: case Oidx: case Osize: case Otupget: case Oidxlen: + case Obreak: case Ocontinue: + case Numops: + dump(n, stdout); + die("Should not see %s in isel", opstr[exprop(n)]); + break; + } + return r; } static void isel(Isel *s, Node *n) { - switch (n->type) { - case Nexpr: - selexpr(s, n); - break; - case Ndecl: - break; - default: - die("Bad node type in isel()"); - break; - } + switch (n->type) { + case Nexpr: + selexpr(s, n); + break; + case Ndecl: + break; + default: + die("Bad node type in isel()"); + break; + } } /* %rax is for int returns, %xmm0d is for floating returns */ Reg savedregs[] = { - Rr12, Rr13, Rr14, Rr15, - Rnone + Rr12, Rr13, Rr14, Rr15, + Rnone }; void addarglocs(Isel *s, Func *fn) { - size_t i, nints, nfloats, nargs; - size_t argoff; - int vararg; - Node *arg; - Loc *a, *l; - - argoff = 0; - nfloats = 0; - nints = 0; - vararg = 0; - nargs = countargs(fn->type); - for (i = 0; i < fn->nargs; i++) { - arg = fn->args[i]; - argoff = align(argoff, min(size(arg), Ptrsz)); - if (i >= nargs) - vararg = 1; - if (stacknode(arg)) { - htput(s->stkoff, arg, itop(-(argoff + 2*Ptrsz))); - argoff += size(arg); - } else if (!vararg && isfloatmode(mode(arg)) && nfloats < Nfloatregargs) { - a = coreg(floatargregs[nfloats], mode(arg)); - l = loc(s, arg); - g(s, Imovs, a, l, NULL); - htput(s->reglocs, arg, l); - nfloats++; - } else if (!vararg && isintmode(mode(arg)) && nints < Nintregargs) { - a = coreg(intargregs[nints], mode(arg)); - l = loc(s, arg); - g(s, Imov, a, l, NULL); - htput(s->reglocs, arg, l); - nints++; - } else { - htput(s->stkoff, arg, itop(-(argoff + 2*Ptrsz))); - argoff += size(arg); - } - } + size_t i, nints, nfloats, nargs; + size_t argoff; + int vararg; + Node *arg; + Loc *a, *l; + + argoff = 0; + nfloats = 0; + nints = 0; + vararg = 0; + nargs = countargs(fn->type); + for (i = 0; i < fn->nargs; i++) { + arg = fn->args[i]; + argoff = align(argoff, min(size(arg), Ptrsz)); + if (i >= nargs) + vararg = 1; + if (stacknode(arg)) { + htput(s->stkoff, arg, itop(-(argoff + 2*Ptrsz))); + argoff += size(arg); + } else if (!vararg && isfloatmode(mode(arg)) && nfloats < Nfloatregargs) { + a = coreg(floatargregs[nfloats], mode(arg)); + l = loc(s, arg); + g(s, Imovs, a, l, NULL); + htput(s->reglocs, arg, l); + nfloats++; + } else if (!vararg && isintmode(mode(arg)) && nints < Nintregargs) { + a = coreg(intargregs[nints], mode(arg)); + l = loc(s, arg); + g(s, Imov, a, l, NULL); + htput(s->reglocs, arg, l); + nints++; + } else { + htput(s->stkoff, arg, itop(-(argoff + 2*Ptrsz))); + argoff += size(arg); + } + } } static void prologue(Isel *s, Func *fn, size_t sz) { - Loc *rsp; - Loc *rbp; - Loc *stksz; - Loc *phys; - size_t i; - - rsp = locphysreg(Rrsp); - rbp = locphysreg(Rrbp); - stksz = loclit(sz, ModeQ); - /* enter function */ - g(s, Ipush, rbp, NULL); - g(s, Imov, rsp, rbp, NULL); - g(s, Isub, stksz, rsp, NULL); - /* save registers */ - for (i = 0; savedregs[i] != Rnone; i++) { - phys = locphysreg(savedregs[i]); - s->calleesave[i] = locreg(phys->mode); - if (isfloatmode(phys->mode)) { - g(s, Imovs, phys, s->calleesave[i], NULL); - } else { - g(s, Imov, phys, s->calleesave[i], NULL); - } - } - if (s->envp) - g(s, Imov, locphysreg(Rrax), s->envp, NULL); - addarglocs(s, fn); - s->nsaved = i; - s->stksz = stksz; /* need to update if we spill */ + Loc *rsp; + Loc *rbp; + Loc *stksz; + Loc *phys; + size_t i; + + rsp = locphysreg(Rrsp); + rbp = locphysreg(Rrbp); + stksz = loclit(sz, ModeQ); + /* enter function */ + g(s, Ipush, rbp, NULL); + g(s, Imov, rsp, rbp, NULL); + g(s, Isub, stksz, rsp, NULL); + /* save registers */ + for (i = 0; savedregs[i] != Rnone; i++) { + phys = locphysreg(savedregs[i]); + s->calleesave[i] = locreg(phys->mode); + if (isfloatmode(phys->mode)) { + g(s, Imovs, phys, s->calleesave[i], NULL); + } else { + g(s, Imov, phys, s->calleesave[i], NULL); + } + } + if (s->envp) + g(s, Imov, locphysreg(Rrax), s->envp, NULL); + addarglocs(s, fn); + s->nsaved = i; + s->stksz = stksz; /* need to update if we spill */ } static void epilogue(Isel *s) { - Loc *rsp, *rbp; - Loc *ret; - size_t i; - - rsp = locphysreg(Rrsp); - rbp = locphysreg(Rrbp); - if (s->ret) { - ret = loc(s, s->ret); - if (istyfloat(exprtype(s->ret))) - g(s, Imovs, ret, coreg(Rxmm0d, ret->mode), NULL); - else - g(s, Imov, ret, coreg(Rax, ret->mode), NULL); - } - /* restore registers */ - for (i = 0; savedregs[i] != Rnone; i++) { - if (isfloatmode(s->calleesave[i]->mode)) { - g(s, Imovs, s->calleesave[i], locphysreg(savedregs[i]), NULL); - } else { - g(s, Imov, s->calleesave[i], locphysreg(savedregs[i]), NULL); - } - } - /* leave function */ - g(s, Imov, rbp, rsp, NULL); - g(s, Ipop, rbp, NULL); - g(s, Iret, NULL); + Loc *rsp, *rbp; + Loc *ret; + size_t i; + + rsp = locphysreg(Rrsp); + rbp = locphysreg(Rrbp); + if (s->ret) { + ret = loc(s, s->ret); + if (istyfloat(exprtype(s->ret))) + g(s, Imovs, ret, coreg(Rxmm0d, ret->mode), NULL); + else + g(s, Imov, ret, coreg(Rax, ret->mode), NULL); + } + /* restore registers */ + for (i = 0; savedregs[i] != Rnone; i++) { + if (isfloatmode(s->calleesave[i]->mode)) { + g(s, Imovs, s->calleesave[i], locphysreg(savedregs[i]), NULL); + } else { + g(s, Imov, s->calleesave[i], locphysreg(savedregs[i]), NULL); + } + } + /* leave function */ + g(s, Imov, rbp, rsp, NULL); + g(s, Ipop, rbp, NULL); + g(s, Iret, NULL); } static Asmbb *mkasmbb(Bb *bb) { - Asmbb *as; - - if (!bb) - return NULL; - as = zalloc(sizeof(Asmbb)); - as->id = bb->id; - as->pred = bsdup(bb->pred); - as->succ = bsdup(bb->succ); - as->lbls = memdup(bb->lbls, bb->nlbls*sizeof(char*)); - as->nlbls = bb->nlbls; - return as; + Asmbb *as; + + if (!bb) + return NULL; + as = zalloc(sizeof(Asmbb)); + as->id = bb->id; + as->pred = bsdup(bb->pred); + as->succ = bsdup(bb->succ); + as->lbls = memdup(bb->lbls, bb->nlbls*sizeof(char*)); + as->nlbls = bb->nlbls; + return as; } void selfunc(Isel *is, Func *fn, Htab *globls, Htab *strtab) { - Node *n; - Bb *bb; - size_t i, j; - char buf[128]; - - - for (i = 0; i < fn->cfg->nbb; i++) - lappend(&is->bb, &is->nbb, mkasmbb(fn->cfg->bb[i])); - - is->curbb = is->bb[0]; - prologue(is, fn, fn->stksz); - for (j = 0; j < fn->cfg->nbb - 1; j++) { - is->curbb = is->bb[j]; - if (!is->bb[j]) - continue; - bb = fn->cfg->bb[j]; - for (i = 0; i < bb->nnl; i++) { - /* put in a comment that says where this line comes from */ - n = bb->nl[i]; - bprintf(buf, sizeof buf, "bb = %ld, bbidx = %ld, %s:%d", - j, i, file->file.files[n->loc.file], n->loc.line); - g(is, Icomment, locstrlbl(buf), NULL); - isel(is, fn->cfg->bb[j]->nl[i]); - } - } - is->curbb = is->bb[is->nbb - 1]; - epilogue(is); - peep(is); - regalloc(is); - is->stksz->lit = align(is->stksz->lit, 16); + Node *n; + Bb *bb; + size_t i, j; + char buf[128]; + + + for (i = 0; i < fn->cfg->nbb; i++) + lappend(&is->bb, &is->nbb, mkasmbb(fn->cfg->bb[i])); + + is->curbb = is->bb[0]; + prologue(is, fn, fn->stksz); + for (j = 0; j < fn->cfg->nbb - 1; j++) { + is->curbb = is->bb[j]; + if (!is->bb[j]) + continue; + bb = fn->cfg->bb[j]; + for (i = 0; i < bb->nnl; i++) { + /* put in a comment that says where this line comes from */ + n = bb->nl[i]; + bprintf(buf, sizeof buf, "bb = %ld, bbidx = %ld, %s:%d", + j, i, file->file.files[n->loc.file], n->loc.line); + g(is, Icomment, locstrlbl(buf), NULL); + isel(is, fn->cfg->bb[j]->nl[i]); + } + } + is->curbb = is->bb[is->nbb - 1]; + epilogue(is); + peep(is); + regalloc(is); + is->stksz->lit = align(is->stksz->lit, 16); } diff --git a/6/locs.c b/6/locs.c index ba5dbd0..f81c84e 100644 --- a/6/locs.c +++ b/6/locs.c @@ -23,44 +23,44 @@ Mode regmodes[] = { int isintmode(Mode m) { - return m == ModeB || m == ModeW || m == ModeL || m == ModeQ; + return m == ModeB || m == ModeW || m == ModeL || m == ModeQ; } int isfloatmode(Mode m) { - return m == ModeF || m == ModeD; + return m == ModeF || m == ModeD; } Loc *locstrlbl(char *lbl) { - Loc *l; + Loc *l; - l = zalloc(sizeof(Loc)); - l->type = Loclbl; - l->mode = ModeQ; - l->lbl = strdup(lbl); - return l; + l = zalloc(sizeof(Loc)); + l->type = Loclbl; + l->mode = ModeQ; + l->lbl = strdup(lbl); + return l; } Loc *loclitl(char *lbl) { - Loc *l; + Loc *l; - l = zalloc(sizeof(Loc)); - l->type = Loclitl; - l->mode = ModeQ; - l->lbl = strdup(lbl); - return l; + l = zalloc(sizeof(Loc)); + l->type = Loclitl; + l->mode = ModeQ; + l->lbl = strdup(lbl); + return l; } Loc *loclbl(Node *e) { - Node *lbl; - assert(e->type == Nexpr); - lbl = e->expr.args[0]; - assert(lbl->type == Nlit); - assert(lbl->lit.littype == Llbl); - return locstrlbl(lbl->lit.lblval); + Node *lbl; + assert(e->type == Nexpr); + lbl = e->expr.args[0]; + assert(lbl->type == Nlit); + assert(lbl->lit.littype == Llbl); + return locstrlbl(lbl->lit.lblval); } Loc **locmap = NULL; @@ -68,189 +68,189 @@ size_t maxregid = 0; static Loc *locregid(regid id, Mode m) { - Loc *l; - - l = zalloc(sizeof(Loc)); - l->type = Locreg; - l->mode = m; - l->reg.id = id; - locmap = xrealloc(locmap, maxregid * sizeof(Loc*)); - locmap[l->reg.id] = l; - return l; + Loc *l; + + l = zalloc(sizeof(Loc)); + l->type = Locreg; + l->mode = m; + l->reg.id = id; + locmap = xrealloc(locmap, maxregid * sizeof(Loc*)); + locmap[l->reg.id] = l; + return l; } Loc *locreg(Mode m) { - return locregid(maxregid++, m); + return locregid(maxregid++, m); } Loc *locphysreg(Reg r) { - static Loc *physregs[Nreg] = {0,}; + static Loc *physregs[Nreg] = {0,}; - if (physregs[r]) - return physregs[r]; - physregs[r] = locreg(regmodes[r]); - physregs[r]->reg.colour = r; - return physregs[r]; + if (physregs[r]) + return physregs[r]; + physregs[r] = locreg(regmodes[r]); + physregs[r]->reg.colour = r; + return physregs[r]; } Loc *locmem(long disp, Loc *base, Loc *idx, Mode mode) { - Loc *l; - - l = zalloc(sizeof(Loc)); - l->type = Locmem; - l->mode = mode; - l->mem.constdisp = disp; - l->mem.base = base; - l->mem.idx = idx; - l->mem.scale = 1; - return l; + Loc *l; + + l = zalloc(sizeof(Loc)); + l->type = Locmem; + l->mode = mode; + l->mem.constdisp = disp; + l->mem.base = base; + l->mem.idx = idx; + l->mem.scale = 1; + return l; } Loc *locmems(long disp, Loc *base, Loc *idx, int scale, Mode mode) { - Loc *l; + Loc *l; - l = locmem(disp, base, idx, mode); - l->mem.scale = scale; - return l; + l = locmem(disp, base, idx, mode); + l->mem.scale = scale; + return l; } Loc *locmeml(char *disp, Loc *base, Loc *idx, Mode mode) { - Loc *l; - - l = zalloc(sizeof(Loc)); - l->type = Locmeml; - l->mode = mode; - l->mem.lbldisp = strdup(disp); - l->mem.base = base; - l->mem.idx = idx; - l->mem.scale = 1; - return l; + Loc *l; + + l = zalloc(sizeof(Loc)); + l->type = Locmeml; + l->mode = mode; + l->mem.lbldisp = strdup(disp); + l->mem.base = base; + l->mem.idx = idx; + l->mem.scale = 1; + return l; } Loc *locmemls(char *disp, Loc *base, Loc *idx, int scale, Mode mode) { - Loc *l; + Loc *l; - l = locmeml(disp, base, idx, mode); - l->mem.scale = scale; - return l; + l = locmeml(disp, base, idx, mode); + l->mem.scale = scale; + return l; } Loc *loclit(long val, Mode m) { - Loc *l; + Loc *l; - l = zalloc(sizeof(Loc)); - l->type = Loclit; - l->mode = m; - l->lit = val; - return l; + l = zalloc(sizeof(Loc)); + l->type = Loclit; + l->mode = m; + l->lit = val; + return l; } Loc *coreg(Reg r, Mode m) { - Reg crtab[][Nmode + 1] = { - [Ral] = {Rnone, Ral, Rax, Reax, Rrax}, - [Rcl] = {Rnone, Rcl, Rcx, Recx, Rrcx}, - [Rdl] = {Rnone, Rdl, Rdx, Redx, Rrdx}, - [Rbl] = {Rnone, Rbl, Rbx, Rebx, Rrbx}, - [Rsil] = {Rnone, Rsil, Rsi, Resi, Rrsi}, - [Rdil] = {Rnone, Rdil, Rdi, Redi, Rrdi}, - [Rr8b] = {Rnone, Rr8b, Rr8w, Rr8d, Rr8}, - [Rr9b] = {Rnone, Rr9b, Rr9w, Rr9d, Rr9}, - [Rr10b] = {Rnone, Rr10b, Rr10w, Rr10d, Rr10}, - [Rr11b] = {Rnone, Rr11b, Rr11w, Rr11d, Rr11}, - [Rr12b] = {Rnone, Rr12b, Rr12w, Rr12d, Rr12}, - [Rr13b] = {Rnone, Rr13b, Rr13w, Rr13d, Rr13}, - [Rr14b] = {Rnone, Rr14b, Rr14w, Rr14d, Rr14}, - [Rr15b] = {Rnone, Rr15b, Rr15w, Rr15d, Rr15}, - - [Rax] = {Rnone, Ral, Rax, Reax, Rrax}, - [Rcx] = {Rnone, Rcl, Rcx, Recx, Rrcx}, - [Rdx] = {Rnone, Rdl, Rdx, Redx, Rrdx}, - [Rbx] = {Rnone, Rbl, Rbx, Rebx, Rrbx}, - [Rsi] = {Rnone, Rsil, Rsi, Resi, Rrsi}, - [Rdi] = {Rnone, Rsil, Rdi, Redi, Rrdi}, - [Rr8w] = {Rnone, Rr8b, Rr8w, Rr8d, Rr8}, - [Rr9w] = {Rnone, Rr9b, Rr9w, Rr9d, Rr9}, - [Rr10w] = {Rnone, Rr10b, Rr10w, Rr10d, Rr10}, - [Rr11w] = {Rnone, Rr11b, Rr11w, Rr11d, Rr11}, - [Rr12w] = {Rnone, Rr12b, Rr12w, Rr12d, Rr12}, - [Rr13w] = {Rnone, Rr13b, Rr13w, Rr13d, Rr13}, - [Rr14w] = {Rnone, Rr14b, Rr14w, Rr14d, Rr14}, - [Rr15w] = {Rnone, Rr15b, Rr15w, Rr15d, Rr15}, - - [Reax] = {Rnone, Ral, Rax, Reax, Rrax}, - [Recx] = {Rnone, Rcl, Rcx, Recx, Rrcx}, - [Redx] = {Rnone, Rdl, Rdx, Redx, Rrdx}, - [Rebx] = {Rnone, Rbl, Rbx, Rebx, Rrbx}, - [Resi] = {Rnone, Rsil, Rsi, Resi, Rrsi}, - [Redi] = {Rnone, Rsil, Rdi, Redi, Rrdi}, - [Rr8d] = {Rnone, Rr8b, Rr8w, Rr8d, Rr8}, - [Rr9d] = {Rnone, Rr9b, Rr9w, Rr9d, Rr9}, - [Rr10d] = {Rnone, Rr10b, Rr10w, Rr10d, Rr10}, - [Rr11d] = {Rnone, Rr11b, Rr11w, Rr11d, Rr11}, - [Rr12d] = {Rnone, Rr12b, Rr12w, Rr12d, Rr12}, - [Rr13d] = {Rnone, Rr13b, Rr13w, Rr13d, Rr13}, - [Rr14d] = {Rnone, Rr14b, Rr14w, Rr14d, Rr14}, - [Rr15d] = {Rnone, Rr15b, Rr15w, Rr15d, Rr15}, - - [Rrax] = {Rnone, Ral, Rax, Reax, Rrax}, - [Rrcx] = {Rnone, Rcl, Rcx, Recx, Rrcx}, - [Rrdx] = {Rnone, Rdl, Rdx, Redx, Rrdx}, - [Rrbx] = {Rnone, Rbl, Rbx, Rebx, Rrbx}, - [Rrsi] = {Rnone, Rsil, Rsi, Resi, Rrsi}, - [Rrdi] = {Rnone, Rsil, Rdi, Redi, Rrdi}, - [Rr8] = {Rnone, Rr8b, Rr8w, Rr8d, Rr8}, - [Rr9] = {Rnone, Rr9b, Rr9w, Rr9d, Rr9}, - [Rr10] = {Rnone, Rr10b, Rr10w, Rr10d, Rr10}, - [Rr11] = {Rnone, Rr11b, Rr11w, Rr11d, Rr11}, - [Rr12] = {Rnone, Rr12b, Rr12w, Rr12d, Rr12}, - [Rr13] = {Rnone, Rr13b, Rr13w, Rr13d, Rr13}, - [Rr14] = {Rnone, Rr14b, Rr14w, Rr14d, Rr14}, - [Rr15] = {Rnone, Rr15b, Rr15w, Rr15d, Rr15}, - - [Rxmm0f] = {[ModeF] = Rxmm0f, [ModeD] = Rxmm0d}, - [Rxmm1f] = {[ModeF] = Rxmm1f, [ModeD] = Rxmm1d}, - [Rxmm2f] = {[ModeF] = Rxmm2f, [ModeD] = Rxmm2d}, - [Rxmm3f] = {[ModeF] = Rxmm3f, [ModeD] = Rxmm3d}, - [Rxmm4f] = {[ModeF] = Rxmm4f, [ModeD] = Rxmm4d}, - [Rxmm5f] = {[ModeF] = Rxmm5f, [ModeD] = Rxmm5d}, - [Rxmm6f] = {[ModeF] = Rxmm6f, [ModeD] = Rxmm6d}, - [Rxmm7f] = {[ModeF] = Rxmm7f, [ModeD] = Rxmm7d}, - [Rxmm8f] = {[ModeF] = Rxmm8f, [ModeD] = Rxmm8d}, - [Rxmm9f] = {[ModeF] = Rxmm9f, [ModeD] = Rxmm9d}, - [Rxmm10f] = {[ModeF] = Rxmm0f, [ModeD] = Rxmm0d}, - [Rxmm11f] = {[ModeF] = Rxmm1f, [ModeD] = Rxmm1d}, - [Rxmm12f] = {[ModeF] = Rxmm2f, [ModeD] = Rxmm2d}, - [Rxmm13f] = {[ModeF] = Rxmm3f, [ModeD] = Rxmm3d}, - [Rxmm14f] = {[ModeF] = Rxmm4f, [ModeD] = Rxmm4d}, - [Rxmm15f] = {[ModeF] = Rxmm5f, [ModeD] = Rxmm5d}, - - [Rxmm0d] = {[ModeF] = Rxmm0f, [ModeD] = Rxmm0d}, - [Rxmm1d] = {[ModeF] = Rxmm1f, [ModeD] = Rxmm1d}, - [Rxmm2d] = {[ModeF] = Rxmm2f, [ModeD] = Rxmm2d}, - [Rxmm3d] = {[ModeF] = Rxmm3f, [ModeD] = Rxmm3d}, - [Rxmm4d] = {[ModeF] = Rxmm4f, [ModeD] = Rxmm4d}, - [Rxmm5d] = {[ModeF] = Rxmm5f, [ModeD] = Rxmm5d}, - [Rxmm6d] = {[ModeF] = Rxmm6f, [ModeD] = Rxmm6d}, - [Rxmm7d] = {[ModeF] = Rxmm7f, [ModeD] = Rxmm7d}, - [Rxmm8d] = {[ModeF] = Rxmm8f, [ModeD] = Rxmm8d}, - [Rxmm9d] = {[ModeF] = Rxmm9f, [ModeD] = Rxmm9d}, - [Rxmm10d] = {[ModeF] = Rxmm0f, [ModeD] = Rxmm0d}, - [Rxmm11d] = {[ModeF] = Rxmm1f, [ModeD] = Rxmm1d}, - [Rxmm12d] = {[ModeF] = Rxmm2f, [ModeD] = Rxmm2d}, - [Rxmm13d] = {[ModeF] = Rxmm3f, [ModeD] = Rxmm3d}, - [Rxmm14d] = {[ModeF] = Rxmm4f, [ModeD] = Rxmm4d}, - [Rxmm15d] = {[ModeF] = Rxmm5f, [ModeD] = Rxmm5d}, - }; - - assert(crtab[r][m] != Rnone); - return locphysreg(crtab[r][m]); + Reg crtab[][Nmode + 1] = { + [Ral] = {Rnone, Ral, Rax, Reax, Rrax}, + [Rcl] = {Rnone, Rcl, Rcx, Recx, Rrcx}, + [Rdl] = {Rnone, Rdl, Rdx, Redx, Rrdx}, + [Rbl] = {Rnone, Rbl, Rbx, Rebx, Rrbx}, + [Rsil] = {Rnone, Rsil, Rsi, Resi, Rrsi}, + [Rdil] = {Rnone, Rdil, Rdi, Redi, Rrdi}, + [Rr8b] = {Rnone, Rr8b, Rr8w, Rr8d, Rr8}, + [Rr9b] = {Rnone, Rr9b, Rr9w, Rr9d, Rr9}, + [Rr10b] = {Rnone, Rr10b, Rr10w, Rr10d, Rr10}, + [Rr11b] = {Rnone, Rr11b, Rr11w, Rr11d, Rr11}, + [Rr12b] = {Rnone, Rr12b, Rr12w, Rr12d, Rr12}, + [Rr13b] = {Rnone, Rr13b, Rr13w, Rr13d, Rr13}, + [Rr14b] = {Rnone, Rr14b, Rr14w, Rr14d, Rr14}, + [Rr15b] = {Rnone, Rr15b, Rr15w, Rr15d, Rr15}, + + [Rax] = {Rnone, Ral, Rax, Reax, Rrax}, + [Rcx] = {Rnone, Rcl, Rcx, Recx, Rrcx}, + [Rdx] = {Rnone, Rdl, Rdx, Redx, Rrdx}, + [Rbx] = {Rnone, Rbl, Rbx, Rebx, Rrbx}, + [Rsi] = {Rnone, Rsil, Rsi, Resi, Rrsi}, + [Rdi] = {Rnone, Rsil, Rdi, Redi, Rrdi}, + [Rr8w] = {Rnone, Rr8b, Rr8w, Rr8d, Rr8}, + [Rr9w] = {Rnone, Rr9b, Rr9w, Rr9d, Rr9}, + [Rr10w] = {Rnone, Rr10b, Rr10w, Rr10d, Rr10}, + [Rr11w] = {Rnone, Rr11b, Rr11w, Rr11d, Rr11}, + [Rr12w] = {Rnone, Rr12b, Rr12w, Rr12d, Rr12}, + [Rr13w] = {Rnone, Rr13b, Rr13w, Rr13d, Rr13}, + [Rr14w] = {Rnone, Rr14b, Rr14w, Rr14d, Rr14}, + [Rr15w] = {Rnone, Rr15b, Rr15w, Rr15d, Rr15}, + + [Reax] = {Rnone, Ral, Rax, Reax, Rrax}, + [Recx] = {Rnone, Rcl, Rcx, Recx, Rrcx}, + [Redx] = {Rnone, Rdl, Rdx, Redx, Rrdx}, + [Rebx] = {Rnone, Rbl, Rbx, Rebx, Rrbx}, + [Resi] = {Rnone, Rsil, Rsi, Resi, Rrsi}, + [Redi] = {Rnone, Rsil, Rdi, Redi, Rrdi}, + [Rr8d] = {Rnone, Rr8b, Rr8w, Rr8d, Rr8}, + [Rr9d] = {Rnone, Rr9b, Rr9w, Rr9d, Rr9}, + [Rr10d] = {Rnone, Rr10b, Rr10w, Rr10d, Rr10}, + [Rr11d] = {Rnone, Rr11b, Rr11w, Rr11d, Rr11}, + [Rr12d] = {Rnone, Rr12b, Rr12w, Rr12d, Rr12}, + [Rr13d] = {Rnone, Rr13b, Rr13w, Rr13d, Rr13}, + [Rr14d] = {Rnone, Rr14b, Rr14w, Rr14d, Rr14}, + [Rr15d] = {Rnone, Rr15b, Rr15w, Rr15d, Rr15}, + + [Rrax] = {Rnone, Ral, Rax, Reax, Rrax}, + [Rrcx] = {Rnone, Rcl, Rcx, Recx, Rrcx}, + [Rrdx] = {Rnone, Rdl, Rdx, Redx, Rrdx}, + [Rrbx] = {Rnone, Rbl, Rbx, Rebx, Rrbx}, + [Rrsi] = {Rnone, Rsil, Rsi, Resi, Rrsi}, + [Rrdi] = {Rnone, Rsil, Rdi, Redi, Rrdi}, + [Rr8] = {Rnone, Rr8b, Rr8w, Rr8d, Rr8}, + [Rr9] = {Rnone, Rr9b, Rr9w, Rr9d, Rr9}, + [Rr10] = {Rnone, Rr10b, Rr10w, Rr10d, Rr10}, + [Rr11] = {Rnone, Rr11b, Rr11w, Rr11d, Rr11}, + [Rr12] = {Rnone, Rr12b, Rr12w, Rr12d, Rr12}, + [Rr13] = {Rnone, Rr13b, Rr13w, Rr13d, Rr13}, + [Rr14] = {Rnone, Rr14b, Rr14w, Rr14d, Rr14}, + [Rr15] = {Rnone, Rr15b, Rr15w, Rr15d, Rr15}, + + [Rxmm0f] = {[ModeF] = Rxmm0f, [ModeD] = Rxmm0d}, + [Rxmm1f] = {[ModeF] = Rxmm1f, [ModeD] = Rxmm1d}, + [Rxmm2f] = {[ModeF] = Rxmm2f, [ModeD] = Rxmm2d}, + [Rxmm3f] = {[ModeF] = Rxmm3f, [ModeD] = Rxmm3d}, + [Rxmm4f] = {[ModeF] = Rxmm4f, [ModeD] = Rxmm4d}, + [Rxmm5f] = {[ModeF] = Rxmm5f, [ModeD] = Rxmm5d}, + [Rxmm6f] = {[ModeF] = Rxmm6f, [ModeD] = Rxmm6d}, + [Rxmm7f] = {[ModeF] = Rxmm7f, [ModeD] = Rxmm7d}, + [Rxmm8f] = {[ModeF] = Rxmm8f, [ModeD] = Rxmm8d}, + [Rxmm9f] = {[ModeF] = Rxmm9f, [ModeD] = Rxmm9d}, + [Rxmm10f] = {[ModeF] = Rxmm0f, [ModeD] = Rxmm0d}, + [Rxmm11f] = {[ModeF] = Rxmm1f, [ModeD] = Rxmm1d}, + [Rxmm12f] = {[ModeF] = Rxmm2f, [ModeD] = Rxmm2d}, + [Rxmm13f] = {[ModeF] = Rxmm3f, [ModeD] = Rxmm3d}, + [Rxmm14f] = {[ModeF] = Rxmm4f, [ModeD] = Rxmm4d}, + [Rxmm15f] = {[ModeF] = Rxmm5f, [ModeD] = Rxmm5d}, + + [Rxmm0d] = {[ModeF] = Rxmm0f, [ModeD] = Rxmm0d}, + [Rxmm1d] = {[ModeF] = Rxmm1f, [ModeD] = Rxmm1d}, + [Rxmm2d] = {[ModeF] = Rxmm2f, [ModeD] = Rxmm2d}, + [Rxmm3d] = {[ModeF] = Rxmm3f, [ModeD] = Rxmm3d}, + [Rxmm4d] = {[ModeF] = Rxmm4f, [ModeD] = Rxmm4d}, + [Rxmm5d] = {[ModeF] = Rxmm5f, [ModeD] = Rxmm5d}, + [Rxmm6d] = {[ModeF] = Rxmm6f, [ModeD] = Rxmm6d}, + [Rxmm7d] = {[ModeF] = Rxmm7f, [ModeD] = Rxmm7d}, + [Rxmm8d] = {[ModeF] = Rxmm8f, [ModeD] = Rxmm8d}, + [Rxmm9d] = {[ModeF] = Rxmm9f, [ModeD] = Rxmm9d}, + [Rxmm10d] = {[ModeF] = Rxmm0f, [ModeD] = Rxmm0d}, + [Rxmm11d] = {[ModeF] = Rxmm1f, [ModeD] = Rxmm1d}, + [Rxmm12d] = {[ModeF] = Rxmm2f, [ModeD] = Rxmm2d}, + [Rxmm13d] = {[ModeF] = Rxmm3f, [ModeD] = Rxmm3d}, + [Rxmm14d] = {[ModeF] = Rxmm4f, [ModeD] = Rxmm4d}, + [Rxmm15d] = {[ModeF] = Rxmm5f, [ModeD] = Rxmm5d}, + }; + + assert(crtab[r][m] != Rnone); + return locphysreg(crtab[r][m]); } diff --git a/6/main.c b/6/main.c index 4d884e6..5d66e38 100644 --- a/6/main.c +++ b/6/main.c @@ -32,215 +32,215 @@ Asmsyntax asmsyntax; static void usage(char *prog) { - printf("%s [-?] [-o outfile] [-d[dbgopts]] inputs\n", prog); - printf("\t-?\tPrint this help\n"); - printf("\t-o\tOutput to outfile\n"); - printf("\t-S\tGenerate assembly source alongside object code\n"); - printf("\t-c\tEnable additional (possibly flaky) checking\n"); - printf("\t-I path\tAdd 'path' to use search path\n"); - printf("\t-d\tPrint debug dumps. Recognized options: f r p i\n"); - printf("\t-G\tGenerate asm in gas syntax\n"); - printf("\t-8\tGenerate asm in plan 9 syntax\n"); - printf("\t-d opts: additional debug logging. Options are listed below:\n"); - printf("\t\tf: log folded trees\n"); - printf("\t\tl: log lowered pre-cfg trees\n"); - printf("\t\tT: log tree immediately\n"); - printf("\t\tr: log register allocation activity\n"); - printf("\t\ti: log instruction selection activity\n"); - printf("\t\tu: log type unifications\n"); + printf("%s [-?] [-o outfile] [-d[dbgopts]] inputs\n", prog); + printf("\t-?\tPrint this help\n"); + printf("\t-o\tOutput to outfile\n"); + printf("\t-S\tGenerate assembly source alongside object code\n"); + printf("\t-c\tEnable additional (possibly flaky) checking\n"); + printf("\t-I path\tAdd 'path' to use search path\n"); + printf("\t-d\tPrint debug dumps. Recognized options: f r p i\n"); + printf("\t-G\tGenerate asm in gas syntax\n"); + printf("\t-8\tGenerate asm in plan 9 syntax\n"); + printf("\t-d opts: additional debug logging. Options are listed below:\n"); + printf("\t\tf: log folded trees\n"); + printf("\t\tl: log lowered pre-cfg trees\n"); + printf("\t\tT: log tree immediately\n"); + printf("\t\tr: log register allocation activity\n"); + printf("\t\ti: log instruction selection activity\n"); + printf("\t\tu: log type unifications\n"); } static void swapout(char* buf, size_t sz, char* suf) { - char* psuffix; - psuffix = strrchr(outfile, '.'); - if (psuffix != NULL) - swapsuffix(buf, sz, outfile, psuffix, suf); - else - bprintf(buf, sz, "%s%s", outfile, suf); + char* psuffix; + psuffix = strrchr(outfile, '.'); + if (psuffix != NULL) + swapsuffix(buf, sz, outfile, psuffix, suf); + else + bprintf(buf, sz, "%s%s", outfile, suf); } static void assemble(char *asmsrc, char *path) { - char *asmcmd[] = Asmcmd; - char objfile[1024]; - char *psuffix; - char **p, **cmd; - size_t ncmd; - int pid, status; - - if (outfile != NULL) - strncpy(objfile, outfile, 1024); - else { - psuffix = strrchr(path, '+'); - if (psuffix != NULL) - swapsuffix(objfile, 1024, path, psuffix, Objsuffix); - else - swapsuffix(objfile, 1024, path, ".myr", Objsuffix); - } - cmd = NULL; - ncmd = 0; - for (p = asmcmd; *p != NULL; p++) - lappend(&cmd, &ncmd, *p); - lappend(&cmd, &ncmd, objfile); - lappend(&cmd, &ncmd, asmsrc); - lappend(&cmd, &ncmd, NULL); - - pid = fork(); - if (pid == -1) { - die("couldn't fork"); - } else if (pid == 0) { - if (execvp(cmd[0], cmd) == -1) - die("Couldn't exec assembler\n"); - } else { - waitpid(pid, &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - die("Couldn't run assembler"); - } + char *asmcmd[] = Asmcmd; + char objfile[1024]; + char *psuffix; + char **p, **cmd; + size_t ncmd; + int pid, status; + + if (outfile != NULL) + strncpy(objfile, outfile, 1024); + else { + psuffix = strrchr(path, '+'); + if (psuffix != NULL) + swapsuffix(objfile, 1024, path, psuffix, Objsuffix); + else + swapsuffix(objfile, 1024, path, ".myr", Objsuffix); + } + cmd = NULL; + ncmd = 0; + for (p = asmcmd; *p != NULL; p++) + lappend(&cmd, &ncmd, *p); + lappend(&cmd, &ncmd, objfile); + lappend(&cmd, &ncmd, asmsrc); + lappend(&cmd, &ncmd, NULL); + + pid = fork(); + if (pid == -1) { + die("couldn't fork"); + } else if (pid == 0) { + if (execvp(cmd[0], cmd) == -1) + die("Couldn't exec assembler\n"); + } else { + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + die("Couldn't run assembler"); + } } static char *gentempfile(char *buf, size_t bufsz, char *path, char *suffix) { - char *tmpdir; - char *base; - struct timeval tv; - - tmpdir = getenv("TMPDIR"); - if (!tmpdir) - tmpdir = "/tmp"; - base = strrchr(path, '/'); - if (base) - base++; - else - base = path; - gettimeofday(&tv, NULL); - bprintf(buf, bufsz, "%s/tmp%lx%lx-%s%s", tmpdir, (long)tv.tv_sec, (long)tv.tv_usec, base, suffix); - return buf; + char *tmpdir; + char *base; + struct timeval tv; + + tmpdir = getenv("TMPDIR"); + if (!tmpdir) + tmpdir = "/tmp"; + base = strrchr(path, '/'); + if (base) + base++; + else + base = path; + gettimeofday(&tv, NULL); + bprintf(buf, bufsz, "%s/tmp%lx%lx-%s%s", tmpdir, (long)tv.tv_sec, (long)tv.tv_usec, base, suffix); + return buf; } static int hasmain(Node *file) { - Node *n, *name; - - name = mknsname(Zloc, "", "main"); - n = getdcl(file->file.globls, name); - if (!n) - return 0; - n = n->decl.name; - if (n->name.ns) - return 0; - return 1; + Node *n, *name; + + name = mknsname(Zloc, "", "main"); + n = getdcl(file->file.globls, name); + if (!n) + return 0; + n = n->decl.name; + if (n->name.ns) + return 0; + return 1; } static void genuse(char *path) { - FILE *f; - char buf[1024]; - char *psuffix; - - if (outfile != NULL) - swapout(buf, 1024, ".use"); - else { - psuffix = strrchr(path, '+'); - if (psuffix != NULL) - swapsuffix(buf, 1024, path, psuffix, ".use"); - else - swapsuffix(buf, 1024, path, ".myr", ".use"); - } - f = fopen(buf, "w"); - if (!f) { - fprintf(stderr, "Could not open path %s\n", buf); - exit(1); - } - writeuse(f, file); - fclose(f); + FILE *f; + char buf[1024]; + char *psuffix; + + if (outfile != NULL) + swapout(buf, 1024, ".use"); + else { + psuffix = strrchr(path, '+'); + if (psuffix != NULL) + swapsuffix(buf, 1024, path, psuffix, ".use"); + else + swapsuffix(buf, 1024, path, ".myr", ".use"); + } + f = fopen(buf, "w"); + if (!f) { + fprintf(stderr, "Could not open path %s\n", buf); + exit(1); + } + writeuse(f, file); + fclose(f); } int main(int argc, char **argv) { - char buf[1024]; - Stab *globls; - Optctx ctx; - size_t i; - - outfile = NULL; - - optinit(&ctx, "d:hSo:I:9G", argv, argc); - asmsyntax = Defaultasm; - while (!optdone(&ctx)) { - switch (optnext(&ctx)) { - case 'o': - outfile = ctx.optarg; - break; - case 'S': - writeasm = 1; - break; - case '?': - case 'h': - usage(argv[0]); - exit(0); - break; - case 'c': - extracheck = 1; - case 'd': - while (ctx.optarg && *ctx.optarg) - debugopt[*ctx.optarg++ & 0x7f]++; - break; - case '9': - asmsyntax = Plan9; - break; - case 'G': - asmsyntax = Gnugas; - break; - case 'I': - lappend(&incpaths, &nincpaths, ctx.optarg); - break; - default: - usage(argv[0]); - exit(0); - break; - } - } - - lappend(&incpaths, &nincpaths, Instroot "/lib/myr"); - - if (ctx.nargs == 0) { - fprintf(stderr, "No input files given\n"); - exit(1); - } - else if (ctx.nargs > 1) - outfile = NULL; - - for (i = 0; i < ctx.nargs; i++) { - globls = mkstab(0); - tyinit(globls); - tokinit(ctx.args[i]); - file = mkfile(ctx.args[i]); - file->file.globls = globls; - yyparse(); - - /* before we do anything to the parse */ - if (debugopt['T']) - dump(file, stdout); - infer(file); - if (hasmain(file)) - geninit(file); - tagexports(file, 0); - /* after all type inference */ - if (debugopt['t']) - dump(file, stdout); - - if (writeasm) { - if (outfile != NULL) - swapout(buf, sizeof buf, ".s"); - else - swapsuffix(buf, sizeof buf, ctx.args[i], ".myr", ".s"); - } else { - gentempfile(buf, sizeof buf, ctx.args[i], ".s"); - } - genuse(ctx.args[i]); - gen(file, buf); - assemble(buf, ctx.args[i]); - } - - return 0; + char buf[1024]; + Stab *globls; + Optctx ctx; + size_t i; + + outfile = NULL; + + optinit(&ctx, "d:hSo:I:9G", argv, argc); + asmsyntax = Defaultasm; + while (!optdone(&ctx)) { + switch (optnext(&ctx)) { + case 'o': + outfile = ctx.optarg; + break; + case 'S': + writeasm = 1; + break; + case '?': + case 'h': + usage(argv[0]); + exit(0); + break; + case 'c': + extracheck = 1; + case 'd': + while (ctx.optarg && *ctx.optarg) + debugopt[*ctx.optarg++ & 0x7f]++; + break; + case '9': + asmsyntax = Plan9; + break; + case 'G': + asmsyntax = Gnugas; + break; + case 'I': + lappend(&incpaths, &nincpaths, ctx.optarg); + break; + default: + usage(argv[0]); + exit(0); + break; + } + } + + lappend(&incpaths, &nincpaths, Instroot "/lib/myr"); + + if (ctx.nargs == 0) { + fprintf(stderr, "No input files given\n"); + exit(1); + } + else if (ctx.nargs > 1) + outfile = NULL; + + for (i = 0; i < ctx.nargs; i++) { + globls = mkstab(0); + tyinit(globls); + tokinit(ctx.args[i]); + file = mkfile(ctx.args[i]); + file->file.globls = globls; + yyparse(); + + /* before we do anything to the parse */ + if (debugopt['T']) + dump(file, stdout); + infer(file); + if (hasmain(file)) + geninit(file); + tagexports(file, 0); + /* after all type inference */ + if (debugopt['t']) + dump(file, stdout); + + if (writeasm) { + if (outfile != NULL) + swapout(buf, sizeof buf, ".s"); + else + swapsuffix(buf, sizeof buf, ctx.args[i], ".myr", ".s"); + } else { + gentempfile(buf, sizeof buf, ctx.args[i], ".s"); + } + genuse(ctx.args[i]); + gen(file, buf); + assemble(buf, ctx.args[i]); + } + + return 0; } diff --git a/6/peep.c b/6/peep.c index f36cdff..cb31911 100644 --- a/6/peep.c +++ b/6/peep.c @@ -21,17 +21,17 @@ * at that point */ static void deadcode(Isel *s, Asmbb *bb) { - size_t i; + size_t i; - if (!bb) - return; - for (i = 0; i < bb->ni; i++) { - if (bb->il[i]->op == Ijmp) { - i++; - break; - } - } - bb->ni = i; + if (!bb) + return; + for (i = 0; i < bb->ni; i++) { + if (bb->il[i]->op == Ijmp) { + i++; + break; + } + } + bb->ni = i; } /* checks for of dumb jump code. @@ -42,48 +42,48 @@ static void deadcode(Isel *s, Asmbb *bb) */ static void nopjmp(Isel *s, Asmbb *bb, size_t idx) { - Insn *jmp; - Loc *targ; - Asmbb *nextbb; - size_t i; + Insn *jmp; + Loc *targ; + Asmbb *nextbb; + size_t i; - /* skip empty bbs */ - if (!bb || !bb->ni) - return; - /* find the target of the last unconditional - * jump in the bb */ - targ = NULL; - if (bb->il[bb->ni - 1]->op == Ijmp) { - jmp = bb->il[bb->ni - 1]; - if (jmp->args[0]->type == Loclbl) - targ = jmp->args[0]; - } - if (!targ) - return; - - /* figure out if it's somewhere in the head of the next bb */ - nextbb = NULL; - for (i = idx + 1; i < s->nbb; i++) { - nextbb = s->bb[i]; - if (nextbb) - break; - } - if (!nextbb) - return; - for (i = 0; i < nextbb->nlbls; i++) { - if (!strcmp(nextbb->lbls[i], targ->lbl)) { - bb->ni--; - break; - } - } + /* skip empty bbs */ + if (!bb || !bb->ni) + return; + /* find the target of the last unconditional + * jump in the bb */ + targ = NULL; + if (bb->il[bb->ni - 1]->op == Ijmp) { + jmp = bb->il[bb->ni - 1]; + if (jmp->args[0]->type == Loclbl) + targ = jmp->args[0]; + } + if (!targ) + return; + + /* figure out if it's somewhere in the head of the next bb */ + nextbb = NULL; + for (i = idx + 1; i < s->nbb; i++) { + nextbb = s->bb[i]; + if (nextbb) + break; + } + if (!nextbb) + return; + for (i = 0; i < nextbb->nlbls; i++) { + if (!strcmp(nextbb->lbls[i], targ->lbl)) { + bb->ni--; + break; + } + } } void peep(Isel *s) { - size_t i; + size_t i; - for (i = 0; i < s->nbb; i++) { - deadcode(s, s->bb[i]); - nopjmp(s, s->bb[i], i); - } + for (i = 0; i < s->nbb; i++) { + deadcode(s, s->bb[i]); + nopjmp(s, s->bb[i], i); + } } diff --git a/6/ra.c b/6/ra.c index 7e8fe83..5c7452b 100644 --- a/6/ra.c +++ b/6/ra.c @@ -15,8 +15,8 @@ typedef struct Usemap Usemap; struct Usemap { - int l[Nreg + 1]; /* location of arg used in instruction's arg list */ - int r[Nreg + 1]; /* list of registers used implicitly by instruction */ + int l[Nreg + 1]; /* location of arg used in instruction's arg list */ + int r[Nreg + 1]; /* list of registers used implicitly by instruction */ }; void wlprint(FILE *fd, char *name, Loc **wl, size_t nwl); @@ -47,297 +47,296 @@ Usemap deftab[] = { /* A map of which registers interfere */ #define Northogonal 32 Reg regmap[Northogonal][Nmode] = { - /* None, ModeB, ModeW, ModeL, ModeQ, ModeF, ModeD */ - [0] = {Rnone, Ral, Rax, Reax, Rrax, Rnone, Rnone}, - [1] = {Rnone, Rcl, Rcx, Recx, Rrcx, Rnone, Rnone}, - [2] = {Rnone, Rdl, Rdx, Redx, Rrdx, Rnone, Rnone}, - [3] = {Rnone, Rbl, Rbx, Rebx, Rrbx, Rnone, Rnone}, - [4] = {Rnone, Rsil, Rsi, Resi, Rrsi, Rnone, Rnone}, - [5] = {Rnone, Rdil, Rdi, Redi, Rrdi, Rnone, Rnone}, - [6] = {Rnone, Rr8b, Rr8w, Rr8d, Rr8, Rnone, Rnone}, - [7] = {Rnone, Rr9b, Rr9w, Rr9d, Rr9, Rnone, Rnone}, - [8] = {Rnone, Rr10b, Rr10w, Rr10d, Rr10, Rnone, Rnone}, - [9] = {Rnone, Rr11b, Rr11w, Rr11d, Rr11, Rnone, Rnone}, - [10] = {Rnone, Rr12b, Rr12w, Rr12d, Rr12, Rnone, Rnone}, - [11] = {Rnone, Rr13b, Rr13w, Rr13d, Rr13, Rnone, Rnone}, - [12] = {Rnone, Rr14b, Rr14w, Rr14d, Rr14, Rnone, Rnone}, - [13] = {Rnone, Rr15b, Rr15w, Rr15d, Rr15, Rnone, Rnone}, - [14] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rnone, Rnone}, - [15] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rnone, Rnone}, - [16] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm0f, Rxmm0d}, - [17] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm1f, Rxmm1d}, - [18] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm2f, Rxmm2d}, - [19] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm3f, Rxmm3d}, - [20] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm4f, Rxmm4d}, - [21] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm5f, Rxmm5d}, - [22] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm6f, Rxmm6d}, - [23] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm7f, Rxmm7d}, - [24] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm8f, Rxmm8d}, - [25] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm9f, Rxmm9d}, - [26] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm10f, Rxmm10d}, - [27] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm11f, Rxmm11d}, - [28] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm12f, Rxmm12d}, - [29] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm13f, Rxmm13d}, - [30] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm14f, Rxmm14d}, - [31] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm15f, Rxmm15d}, + /* None, ModeB, ModeW, ModeL, ModeQ, ModeF, ModeD */ + [0] = {Rnone, Ral, Rax, Reax, Rrax, Rnone, Rnone}, + [1] = {Rnone, Rcl, Rcx, Recx, Rrcx, Rnone, Rnone}, + [2] = {Rnone, Rdl, Rdx, Redx, Rrdx, Rnone, Rnone}, + [3] = {Rnone, Rbl, Rbx, Rebx, Rrbx, Rnone, Rnone}, + [4] = {Rnone, Rsil, Rsi, Resi, Rrsi, Rnone, Rnone}, + [5] = {Rnone, Rdil, Rdi, Redi, Rrdi, Rnone, Rnone}, + [6] = {Rnone, Rr8b, Rr8w, Rr8d, Rr8, Rnone, Rnone}, + [7] = {Rnone, Rr9b, Rr9w, Rr9d, Rr9, Rnone, Rnone}, + [8] = {Rnone, Rr10b, Rr10w, Rr10d, Rr10, Rnone, Rnone}, + [9] = {Rnone, Rr11b, Rr11w, Rr11d, Rr11, Rnone, Rnone}, + [10] = {Rnone, Rr12b, Rr12w, Rr12d, Rr12, Rnone, Rnone}, + [11] = {Rnone, Rr13b, Rr13w, Rr13d, Rr13, Rnone, Rnone}, + [12] = {Rnone, Rr14b, Rr14w, Rr14d, Rr14, Rnone, Rnone}, + [13] = {Rnone, Rr15b, Rr15w, Rr15d, Rr15, Rnone, Rnone}, + [14] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rnone, Rnone}, + [15] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rnone, Rnone}, + [16] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm0f, Rxmm0d}, + [17] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm1f, Rxmm1d}, + [18] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm2f, Rxmm2d}, + [19] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm3f, Rxmm3d}, + [20] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm4f, Rxmm4d}, + [21] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm5f, Rxmm5d}, + [22] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm6f, Rxmm6d}, + [23] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm7f, Rxmm7d}, + [24] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm8f, Rxmm8d}, + [25] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm9f, Rxmm9d}, + [26] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm10f, Rxmm10d}, + [27] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm11f, Rxmm11d}, + [28] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm12f, Rxmm12d}, + [29] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm13f, Rxmm13d}, + [30] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm14f, Rxmm14d}, + [31] = {Rnone, Rnone, Rnone, Rnone, Rnone, Rxmm15f, Rxmm15d}, }; /* Which regmap entry a register maps to */ int colourmap[Nreg] = { - /* byte */ - [Ral] = 0, [Rax] = 0, [Reax] = 0, [Rrax] = 0, - [Rcl] = 1, [Rcx] = 1, [Recx] = 1, [Rrcx] = 1, - [Rdl] = 2, [Rdx] = 2, [Redx] = 2, [Rrdx] = 2, - [Rbl] = 3, [Rbx] = 3, [Rebx] = 3, [Rrbx] = 3, - [Rsil] = 4, [Rsi] = 4, [Resi] = 4, [Rrsi] = 4, - [Rdil] = 5, [Rdi] = 5, [Redi] = 5, [Rrdi] = 5, - [Rr8b] = 6, [Rr8w] = 6, [Rr8d] = 6, [Rr8] = 6, - [Rr9b] = 7, [Rr9w] = 7, [Rr9d] = 7, [Rr9] = 7, - [Rr10b] = 8, [Rr10w] = 8, [Rr10d] = 8, [Rr10] = 8, - [Rr11b] = 9, [Rr11w] = 9, [Rr11d] = 9, [Rr11] = 9, - [Rr12b] = 10, [Rr12w] = 10, [Rr12d] = 10, [Rr12] = 10, - [Rr13b] = 11, [Rr13w] = 11, [Rr13d] = 11, [Rr13] = 11, - [Rr14b] = 12, [Rr14w] = 12, [Rr14d] = 12, [Rr14] = 12, - [Rr15b] = 13, [Rr15w] = 13, [Rr15d] = 13, [Rr15] = 13, - - /* float */ - [Rxmm0f] = 16, [Rxmm0d] = 16, - [Rxmm1f] = 17, [Rxmm1d] = 17, - [Rxmm2f] = 18, [Rxmm2d] = 18, - [Rxmm3f] = 19, [Rxmm3d] = 19, - [Rxmm4f] = 20, [Rxmm4d] = 20, - [Rxmm5f] = 21, [Rxmm5d] = 21, - [Rxmm6f] = 22, [Rxmm6d] = 22, - [Rxmm7f] = 23, [Rxmm7d] = 23, - [Rxmm8f] = 24, [Rxmm8d] = 24, - [Rxmm9f] = 25, [Rxmm9d] = 25, - [Rxmm10f] = 26, [Rxmm10d] = 26, - [Rxmm11f] = 27, [Rxmm11d] = 27, - [Rxmm12f] = 28, [Rxmm12d] = 28, - [Rxmm13f] = 29, [Rxmm13d] = 29, - [Rxmm14f] = 30, [Rxmm14d] = 30, - [Rxmm15f] = 31, [Rxmm15d] = 31, + /* byte */ + [Ral] = 0, [Rax] = 0, [Reax] = 0, [Rrax] = 0, + [Rcl] = 1, [Rcx] = 1, [Recx] = 1, [Rrcx] = 1, + [Rdl] = 2, [Rdx] = 2, [Redx] = 2, [Rrdx] = 2, + [Rbl] = 3, [Rbx] = 3, [Rebx] = 3, [Rrbx] = 3, + [Rsil] = 4, [Rsi] = 4, [Resi] = 4, [Rrsi] = 4, + [Rdil] = 5, [Rdi] = 5, [Redi] = 5, [Rrdi] = 5, + [Rr8b] = 6, [Rr8w] = 6, [Rr8d] = 6, [Rr8] = 6, + [Rr9b] = 7, [Rr9w] = 7, [Rr9d] = 7, [Rr9] = 7, + [Rr10b] = 8, [Rr10w] = 8, [Rr10d] = 8, [Rr10] = 8, + [Rr11b] = 9, [Rr11w] = 9, [Rr11d] = 9, [Rr11] = 9, + [Rr12b] = 10, [Rr12w] = 10, [Rr12d] = 10, [Rr12] = 10, + [Rr13b] = 11, [Rr13w] = 11, [Rr13d] = 11, [Rr13] = 11, + [Rr14b] = 12, [Rr14w] = 12, [Rr14d] = 12, [Rr14] = 12, + [Rr15b] = 13, [Rr15w] = 13, [Rr15d] = 13, [Rr15] = 13, + + /* float */ + [Rxmm0f] = 16, [Rxmm0d] = 16, + [Rxmm1f] = 17, [Rxmm1d] = 17, + [Rxmm2f] = 18, [Rxmm2d] = 18, + [Rxmm3f] = 19, [Rxmm3d] = 19, + [Rxmm4f] = 20, [Rxmm4d] = 20, + [Rxmm5f] = 21, [Rxmm5d] = 21, + [Rxmm6f] = 22, [Rxmm6d] = 22, + [Rxmm7f] = 23, [Rxmm7d] = 23, + [Rxmm8f] = 24, [Rxmm8d] = 24, + [Rxmm9f] = 25, [Rxmm9d] = 25, + [Rxmm10f] = 26, [Rxmm10d] = 26, + [Rxmm11f] = 27, [Rxmm11d] = 27, + [Rxmm12f] = 28, [Rxmm12d] = 28, + [Rxmm13f] = 29, [Rxmm13d] = 29, + [Rxmm14f] = 30, [Rxmm14d] = 30, + [Rxmm15f] = 31, [Rxmm15d] = 31, }; size_t modesize[Nmode] = { - [ModeNone] = 0, - [ModeB] = 1, - [ModeW] = 2, - [ModeL] = 4, - [ModeQ] = 8, - [ModeF] = 4, - [ModeD] = 8, + [ModeNone] = 0, + [ModeB] = 1, + [ModeW] = 2, + [ModeL] = 4, + [ModeQ] = 8, + [ModeF] = 4, + [ModeD] = 8, }; - static int _K[Nclass] = { - [Classbad] = 0, - [Classint] = 14, - [Classflt] = 16, + [Classbad] = 0, + [Classint] = 14, + [Classflt] = 16, }; Rclass rclass(Loc *l) { - switch (l->mode) { - case ModeNone: return Classbad; - case Nmode: return Classbad; - case ModeB: return Classint; - case ModeW: return Classint; - case ModeL: return Classint; - case ModeQ: return Classint; - - case ModeF: return Classflt; - case ModeD: return Classflt; - } - return Classbad; + switch (l->mode) { + case ModeNone: return Classbad; + case Nmode: return Classbad; + case ModeB: return Classint; + case ModeW: return Classint; + case ModeL: return Classint; + case ModeQ: return Classint; + + case ModeF: return Classflt; + case ModeD: return Classflt; + } + return Classbad; } /* %esp, %ebp are not in the allocatable pool */ static int isfixreg(Loc *l) { - if (l->reg.colour == Resp) - return 1; - if (l->reg.colour == Rebp) - return 1; - return 0; + if (l->reg.colour == Resp) + return 1; + if (l->reg.colour == Rebp) + return 1; + return 0; } static size_t uses(Insn *insn, regid *u) { - size_t i, j; - int k; - Loc *m; - - j = 0; - /* Add all the registers used and defined. Duplicates - * in this list are fine, since they're being added to - * a set anyways */ - for (i = 0; i < Maxarg; i++) { - if (!usetab[insn->op].l[i]) - break; - k = usetab[insn->op].l[i] - 1; - /* non-registers are handled later */ - if (insn->args[k]->type == Locreg) - if (!isfixreg(insn->args[k])) - u[j++] = insn->args[k]->reg.id; - } - /* some insns don't reflect their defs in the args. - * These are explictly listed in the insn description */ - for (i = 0; i < Nreg; i++) { - if (!usetab[insn->op].r[i]) - break; - /* not a leak; physical registers get memoized */ - u[j++] = locphysreg(usetab[insn->op].r[i])->reg.id; - } - /* If the registers are in an address calculation, - * they're used no matter what. */ - for (i = 0; i < insn->nargs; i++) { - m = insn->args[i]; - if (m->type != Locmem && m->type != Locmeml) - continue; - if (m->mem.base) - if (!isfixreg(m->mem.base)) - u[j++] = m->mem.base->reg.id; - if (m->mem.idx) - if (!isfixreg(m->mem.base)) - u[j++] = m->mem.idx->reg.id; - } - return j; + size_t i, j; + int k; + Loc *m; + + j = 0; + /* Add all the registers used and defined. Duplicates + * in this list are fine, since they're being added to + * a set anyways */ + for (i = 0; i < Maxarg; i++) { + if (!usetab[insn->op].l[i]) + break; + k = usetab[insn->op].l[i] - 1; + /* non-registers are handled later */ + if (insn->args[k]->type == Locreg) + if (!isfixreg(insn->args[k])) + u[j++] = insn->args[k]->reg.id; + } + /* some insns don't reflect their defs in the args. + * These are explictly listed in the insn description */ + for (i = 0; i < Nreg; i++) { + if (!usetab[insn->op].r[i]) + break; + /* not a leak; physical registers get memoized */ + u[j++] = locphysreg(usetab[insn->op].r[i])->reg.id; + } + /* If the registers are in an address calculation, + * they're used no matter what. */ + for (i = 0; i < insn->nargs; i++) { + m = insn->args[i]; + if (m->type != Locmem && m->type != Locmeml) + continue; + if (m->mem.base) + if (!isfixreg(m->mem.base)) + u[j++] = m->mem.base->reg.id; + if (m->mem.idx) + if (!isfixreg(m->mem.base)) + u[j++] = m->mem.idx->reg.id; + } + return j; } static size_t defs(Insn *insn, regid *d) { - size_t i, j; - int k; - - j = 0; - /* Add all the registers dsed and defined. Duplicates - * in this list are fine, since they're being added to - * a set anyways */ - for (i = 0; i < Maxarg; i++) { - if (!deftab[insn->op].l[i]) - break; - k = deftab[insn->op].l[i] - 1; - if (insn->args[k]->type == Locreg) - if (!isfixreg(insn->args[k])) - d[j++] = insn->args[k]->reg.id; - } - /* some insns don't reflect their defs in the args. - * These are explictly listed in the insn description */ - for (i = 0; i < Nreg; i++) { - if (!deftab[insn->op].r[i]) - break; - /* not a leak; physical registers get memoized */ - d[j++] = locphysreg(deftab[insn->op].r[i])->reg.id; - } - return j; + size_t i, j; + int k; + + j = 0; + /* Add all the registers dsed and defined. Duplicates + * in this list are fine, since they're being added to + * a set anyways */ + for (i = 0; i < Maxarg; i++) { + if (!deftab[insn->op].l[i]) + break; + k = deftab[insn->op].l[i] - 1; + if (insn->args[k]->type == Locreg) + if (!isfixreg(insn->args[k])) + d[j++] = insn->args[k]->reg.id; + } + /* some insns don't reflect their defs in the args. + * These are explictly listed in the insn description */ + for (i = 0; i < Nreg; i++) { + if (!deftab[insn->op].r[i]) + break; + /* not a leak; physical registers get memoized */ + d[j++] = locphysreg(deftab[insn->op].r[i])->reg.id; + } + return j; } /* The uses and defs for an entire BB. */ static void udcalc(Asmbb *bb) { - regid u[Nreg], d[Nreg]; - size_t nu, nd; - size_t i, j; - - bb->use = bsclear(bb->use); - bb->def = bsclear(bb->def); - for (i = 0; i < bb->ni; i++) { - nu = uses(bb->il[i], u); - nd = defs(bb->il[i], d); - for (j = 0; j < nu; j++) - if (!bshas(bb->def, u[j])) - bsput(bb->use, u[j]); - for (j = 0; j < nd; j++) - bsput(bb->def, d[j]); - } + regid u[Nreg], d[Nreg]; + size_t nu, nd; + size_t i, j; + + bb->use = bsclear(bb->use); + bb->def = bsclear(bb->def); + for (i = 0; i < bb->ni; i++) { + nu = uses(bb->il[i], u); + nd = defs(bb->il[i], d); + for (j = 0; j < nu; j++) + if (!bshas(bb->def, u[j])) + bsput(bb->use, u[j]); + for (j = 0; j < nd; j++) + bsput(bb->def, d[j]); + } } static int istrivial(Isel *s, regid r) { - return s->degree[r] < _K[rclass(locmap[r])]; + return s->degree[r] < _K[rclass(locmap[r])]; } static void liveness(Isel *s) { - Bitset *old; - Asmbb **bb; - ssize_t nbb; - ssize_t i; - size_t j; - int changed; - - bb = s->bb; - nbb = s->nbb; - for (i = 0; i < nbb; i++) { - if (!bb[i]) - continue; - udcalc(s->bb[i]); - bb[i]->livein = bsclear(bb[i]->livein); - bb[i]->liveout = bsclear(bb[i]->liveout); - } - - changed = 1; - while (changed) { - changed = 0; - old = NULL; - for (i = nbb - 1; i >= 0; i--) { - if (!bb[i]) - continue; - old = bsdup(bb[i]->liveout); - /* liveout[b] = U(s in succ) livein[s] */ - for (j = 0; bsiter(bb[i]->succ, &j); j++) - bsunion(bb[i]->liveout, bb[j]->livein); - /* livein[b] = use[b] U (out[b] \ def[b]) */ - bb[i]->livein = bsclear(bb[i]->livein); - bsunion(bb[i]->livein, bb[i]->liveout); - bsdiff(bb[i]->livein, bb[i]->def); - bsunion(bb[i]->livein, bb[i]->use); - if (!changed) - changed = !bseq(old, bb[i]->liveout); - bsfree(old); - } - } + Bitset *old; + Asmbb **bb; + ssize_t nbb; + ssize_t i; + size_t j; + int changed; + + bb = s->bb; + nbb = s->nbb; + for (i = 0; i < nbb; i++) { + if (!bb[i]) + continue; + udcalc(s->bb[i]); + bb[i]->livein = bsclear(bb[i]->livein); + bb[i]->liveout = bsclear(bb[i]->liveout); + } + + changed = 1; + while (changed) { + changed = 0; + old = NULL; + for (i = nbb - 1; i >= 0; i--) { + if (!bb[i]) + continue; + old = bsdup(bb[i]->liveout); + /* liveout[b] = U(s in succ) livein[s] */ + for (j = 0; bsiter(bb[i]->succ, &j); j++) + bsunion(bb[i]->liveout, bb[j]->livein); + /* livein[b] = use[b] U (out[b] \ def[b]) */ + bb[i]->livein = bsclear(bb[i]->livein); + bsunion(bb[i]->livein, bb[i]->liveout); + bsdiff(bb[i]->livein, bb[i]->def); + bsunion(bb[i]->livein, bb[i]->use); + if (!changed) + changed = !bseq(old, bb[i]->liveout); + bsfree(old); + } + } } /* we're only interested in register->register moves */ static int ismove(Insn *i) { - if (i->op != Imov && i->op != Imovs) - return 0; - return i->args[0]->type == Locreg && i->args[1]->type == Locreg; + if (i->op != Imov && i->op != Imovs) + return 0; + return i->args[0]->type == Locreg && i->args[1]->type == Locreg; } static int gbhasedge(Isel *s, size_t u, size_t v) { - size_t i; - i = (s->nreg * v) + u; - return (s->gbits[i/Sizetbits] & (1ULL <<(i % Sizetbits))) != 0; + size_t i; + i = (s->nreg * v) + u; + return (s->gbits[i/Sizetbits] & (1ULL <<(i % Sizetbits))) != 0; } static void gbputedge(Isel *s, size_t u, size_t v) { - size_t i, j; + size_t i, j; - i = (s->nreg * u) + v; - j = (s->nreg * v) + u; - s->gbits[i/Sizetbits] |= 1ULL << (i % Sizetbits); - s->gbits[j/Sizetbits] |= 1ULL << (j % Sizetbits); - assert(gbhasedge(s, u, v) && gbhasedge(s, v, u)); + i = (s->nreg * u) + v; + j = (s->nreg * v) + u; + s->gbits[i/Sizetbits] |= 1ULL << (i % Sizetbits); + s->gbits[j/Sizetbits] |= 1ULL << (j % Sizetbits); + assert(gbhasedge(s, u, v) && gbhasedge(s, v, u)); } static int wlfind(Loc **wl, size_t nwl, regid v, size_t *idx) { - size_t i; - - for (i = 0; i < nwl; i++) { - if (wl[i]->reg.id == v) { - *idx = i; - return 1; - } - } - *idx = -1; - return 0; + size_t i; + + for (i = 0; i < nwl; i++) { + if (wl[i]->reg.id == v) { + *idx = i; + return 1; + } + } + *idx = -1; + return 0; } /* @@ -347,609 +346,609 @@ static int wlfind(Loc **wl, size_t nwl, regid v, size_t *idx) */ static int degreechange(Isel *s, regid u, regid v) { - regid phys, virt, r; - size_t i; - - if (bshas(s->prepainted, u)) { - phys = u; - virt = v; - } else if (bshas(s->prepainted, v)) { - phys = v; - virt = u; - } else { - return 1; - } - - for (i = 0; i < Nmode; i++) { - r = regmap[colourmap[phys]][i]; - if (r != phys && gbhasedge(s, virt, regmap[colourmap[phys]][i])) { - return 0; - } - } - return 1; + regid phys, virt, r; + size_t i; + + if (bshas(s->prepainted, u)) { + phys = u; + virt = v; + } else if (bshas(s->prepainted, v)) { + phys = v; + virt = u; + } else { + return 1; + } + + for (i = 0; i < Nmode; i++) { + r = regmap[colourmap[phys]][i]; + if (r != phys && gbhasedge(s, virt, regmap[colourmap[phys]][i])) { + return 0; + } + } + return 1; } static void alputedge(Isel *s, regid u, regid v) { - s->ngadj[u]++; - s->gadj[u] = xrealloc(s->gadj[u], s->ngadj[u]*sizeof(regid)); - s->gadj[u][s->ngadj[u] - 1] = v; + s->ngadj[u]++; + s->gadj[u] = xrealloc(s->gadj[u], s->ngadj[u]*sizeof(regid)); + s->gadj[u][s->ngadj[u] - 1] = v; } static void wlput(Loc ***wl, size_t *nwl, Loc *l) { - lappend(wl, nwl, l); - l->list = wl; + lappend(wl, nwl, l); + l->list = wl; } static void wldel(Isel *s, Loc ***wl, size_t *nwl, size_t idx) { - (*wl)[idx]->list = NULL; - ldel(wl, nwl, idx); + (*wl)[idx]->list = NULL; + ldel(wl, nwl, idx); } static void wlputset(Bitset *bs, regid r) { - bsput(bs, r); - locmap[r]->list = bs; + bsput(bs, r); + locmap[r]->list = bs; } static void addedge(Isel *s, regid u, regid v) { - if (u == v || gbhasedge(s, u, v)) - return; - if (u == Rrbp || u == Rrsp || u == Rrip) - return; - if (v == Rrbp || v == Rrsp || v == Rrip) - return; - if (rclass(locmap[u]) != rclass(locmap[v])) - return; - if (bshas(s->prepainted, u) && bshas(s->prepainted, v)) - return; - - gbputedge(s, u, v); - gbputedge(s, v, u); - if (!bshas(s->prepainted, u)) { - alputedge(s, u, v); - s->degree[u] += degreechange(s, v, u); - } - if (!bshas(s->prepainted, v)) { - alputedge(s, v, u); - s->degree[v] += degreechange(s, u, v); - } + if (u == v || gbhasedge(s, u, v)) + return; + if (u == Rrbp || u == Rrsp || u == Rrip) + return; + if (v == Rrbp || v == Rrsp || v == Rrip) + return; + if (rclass(locmap[u]) != rclass(locmap[v])) + return; + if (bshas(s->prepainted, u) && bshas(s->prepainted, v)) + return; + + gbputedge(s, u, v); + gbputedge(s, v, u); + if (!bshas(s->prepainted, u)) { + alputedge(s, u, v); + s->degree[u] += degreechange(s, v, u); + } + if (!bshas(s->prepainted, v)) { + alputedge(s, v, u); + s->degree[v] += degreechange(s, u, v); + } } static void gfree(Isel *s) { - size_t i; + size_t i; - for (i = 0; i < s->nreg; i++) - free(s->gadj[i]); - free(s->gbits); - free(s->gadj); - free(s->ngadj); + for (i = 0; i < s->nreg; i++) + free(s->gadj[i]); + free(s->gbits); + free(s->gadj); + free(s->ngadj); } static void setup(Isel *s) { - size_t gchunks; - size_t i; - - gfree(s); - s->nreg = maxregid; - gchunks = (s->nreg*s->nreg)/Sizetbits + 1; - s->gbits = zalloc(gchunks*sizeof(size_t)); - /* fresh adj list repr. */ - s->gadj = zalloc(s->nreg * sizeof(regid*)); - s->ngadj = zalloc(s->nreg * sizeof(size_t)); - - s->mactiveset = bsclear(s->mactiveset); - s->wlmoveset = bsclear(s->wlmoveset); - s->spilled = bsclear(s->spilled); - s->coalesced = bsclear(s->coalesced); - lfree(&s->wlspill, &s->nwlspill); - lfree(&s->wlfreeze, &s->nwlfreeze); - lfree(&s->wlsimp, &s->nwlsimp); - - free(s->aliasmap); - free(s->degree); - free(s->rmoves); - free(s->nrmoves); - - s->aliasmap = zalloc(s->nreg * sizeof(Loc*)); - s->degree = zalloc(s->nreg * sizeof(int)); - s->nuses = zalloc(s->nreg * sizeof(int)); - s->rmoves = zalloc(s->nreg * sizeof(Insn**)); - s->nrmoves = zalloc(s->nreg * sizeof(size_t)); - - for (i = 0; bsiter(s->prepainted, &i); i++) - s->degree[i] = 1<<16; + size_t gchunks; + size_t i; + + gfree(s); + s->nreg = maxregid; + gchunks = (s->nreg*s->nreg)/Sizetbits + 1; + s->gbits = zalloc(gchunks*sizeof(size_t)); + /* fresh adj list repr. */ + s->gadj = zalloc(s->nreg * sizeof(regid*)); + s->ngadj = zalloc(s->nreg * sizeof(size_t)); + + s->mactiveset = bsclear(s->mactiveset); + s->wlmoveset = bsclear(s->wlmoveset); + s->spilled = bsclear(s->spilled); + s->coalesced = bsclear(s->coalesced); + lfree(&s->wlspill, &s->nwlspill); + lfree(&s->wlfreeze, &s->nwlfreeze); + lfree(&s->wlsimp, &s->nwlsimp); + + free(s->aliasmap); + free(s->degree); + free(s->rmoves); + free(s->nrmoves); + + s->aliasmap = zalloc(s->nreg * sizeof(Loc*)); + s->degree = zalloc(s->nreg * sizeof(int)); + s->nuses = zalloc(s->nreg * sizeof(int)); + s->rmoves = zalloc(s->nreg * sizeof(Insn**)); + s->nrmoves = zalloc(s->nreg * sizeof(size_t)); + + for (i = 0; bsiter(s->prepainted, &i); i++) + s->degree[i] = 1<<16; } static void build(Isel *s) { - regid u[Nreg], d[Nreg]; - size_t nu, nd; - size_t i, k, a; - ssize_t j; - Bitset *live; - Asmbb **bb; - size_t nbb; - Insn *insn; - size_t l; - - /* set up convenience vars */ - bb = s->bb; - nbb = s->nbb; - - for (i = 0; i < nbb; i++) { - if (!bb[i]) - continue; - live = bsdup(bb[i]->liveout); - for (j = bb[i]->ni - 1; j >= 0; j--) { - insn = bb[i]->il[j]; - nu = uses(insn, u); - nd = defs(insn, d); - - /* add these to the initial set */ - for (k = 0; k < nu; k++) { - if (!bshas(s->prepainted, u[k])) { - wlputset(s->initial, u[k]); - s->nuses[u[k]]++; - } - } - for (k = 0; k < nd; k++) { - if (!bshas(s->prepainted, d[k])) - wlputset(s->initial, d[k]); - } - - /* moves get special treatment, since we don't want spurious - * edges between the src and dest */ - //iprintf(stdout, insn); - if (ismove(insn)) { - /* live \= uses(i) */ - for (k = 0; k < nu; k++) { - /* remove all physical register aliases */ - if (bshas(s->prepainted, u[k])) { - for (a = 0; a < Nmode; a++) - bsdel(live, regmap[colourmap[u[k]]][a]); - } else { - bsdel(live, u[k]); - } - } - - for (k = 0; k < nu; k++) - lappend(&s->rmoves[u[k]], &s->nrmoves[u[k]], insn); - for (k = 0; k < nd; k++) - lappend(&s->rmoves[d[k]], &s->nrmoves[d[k]], insn); - lappend(&s->wlmove, &s->nwlmove, insn); - bsput(s->wlmoveset, insn->uid); - } - /* live = live U def(i) */ - for (k = 0; k < nd; k++) - bsput(live, d[k]); - - for (k = 0; k < nd; k++) - for (l = 0; bsiter(live, &l); l++) - addedge(s, d[k], l); - /* live = use(i) U (live \ def(i)) */ - for (k = 0; k < nd; k++) - bsdel(live, d[k]); - for (k = 0; k < nu; k++) - bsput(live, u[k]); - } - bsfree(live); - } + regid u[Nreg], d[Nreg]; + size_t nu, nd; + size_t i, k, a; + ssize_t j; + Bitset *live; + Asmbb **bb; + size_t nbb; + Insn *insn; + size_t l; + + /* set up convenience vars */ + bb = s->bb; + nbb = s->nbb; + + for (i = 0; i < nbb; i++) { + if (!bb[i]) + continue; + live = bsdup(bb[i]->liveout); + for (j = bb[i]->ni - 1; j >= 0; j--) { + insn = bb[i]->il[j]; + nu = uses(insn, u); + nd = defs(insn, d); + + /* add these to the initial set */ + for (k = 0; k < nu; k++) { + if (!bshas(s->prepainted, u[k])) { + wlputset(s->initial, u[k]); + s->nuses[u[k]]++; + } + } + for (k = 0; k < nd; k++) { + if (!bshas(s->prepainted, d[k])) + wlputset(s->initial, d[k]); + } + + /* moves get special treatment, since we don't want spurious + * edges between the src and dest */ + //iprintf(stdout, insn); + if (ismove(insn)) { + /* live \= uses(i) */ + for (k = 0; k < nu; k++) { + /* remove all physical register aliases */ + if (bshas(s->prepainted, u[k])) { + for (a = 0; a < Nmode; a++) + bsdel(live, regmap[colourmap[u[k]]][a]); + } else { + bsdel(live, u[k]); + } + } + + for (k = 0; k < nu; k++) + lappend(&s->rmoves[u[k]], &s->nrmoves[u[k]], insn); + for (k = 0; k < nd; k++) + lappend(&s->rmoves[d[k]], &s->nrmoves[d[k]], insn); + lappend(&s->wlmove, &s->nwlmove, insn); + bsput(s->wlmoveset, insn->uid); + } + /* live = live U def(i) */ + for (k = 0; k < nd; k++) + bsput(live, d[k]); + + for (k = 0; k < nd; k++) + for (l = 0; bsiter(live, &l); l++) + addedge(s, d[k], l); + /* live = use(i) U (live \ def(i)) */ + for (k = 0; k < nd; k++) + bsdel(live, d[k]); + for (k = 0; k < nu; k++) + bsput(live, u[k]); + } + bsfree(live); + } } static int adjavail(Isel *s, regid r) { - if (bshas(s->coalesced, r)) - return 0; - if (locmap[r]->list == &s->selstk) - return 0; - return 1; + if (bshas(s->coalesced, r)) + return 0; + if (locmap[r]->list == &s->selstk) + return 0; + return 1; } static size_t nodemoves(Isel *s, regid n, Insn ***pil) { - size_t i; - size_t count; - - /* FIXME: inefficient. Do I care? */ - count = 0; - if (pil) - *pil = NULL; - for (i = 0; i < s->nrmoves[n]; i++) { - if (bshas(s->mactiveset, s->rmoves[n][i]->uid)) - lappend(pil, &count, s->rmoves[n][i]); - if (bshas(s->wlmoveset, s->rmoves[n][i]->uid)) - lappend(pil, &count, s->rmoves[n][i]); - } - return count; + size_t i; + size_t count; + + /* FIXME: inefficient. Do I care? */ + count = 0; + if (pil) + *pil = NULL; + for (i = 0; i < s->nrmoves[n]; i++) { + if (bshas(s->mactiveset, s->rmoves[n][i]->uid)) + lappend(pil, &count, s->rmoves[n][i]); + if (bshas(s->wlmoveset, s->rmoves[n][i]->uid)) + lappend(pil, &count, s->rmoves[n][i]); + } + return count; } static int moverelated(Isel *s, regid n) { - size_t i; - - for (i = 0; i < s->nrmoves[n]; i++) { - if (bshas(s->mactiveset, s->rmoves[n][i]->uid)) - return 1; - if (bshas(s->wlmoveset, s->rmoves[n][i]->uid)) - return 1; - } - return 0; + size_t i; + + for (i = 0; i < s->nrmoves[n]; i++) { + if (bshas(s->mactiveset, s->rmoves[n][i]->uid)) + return 1; + if (bshas(s->wlmoveset, s->rmoves[n][i]->uid)) + return 1; + } + return 0; } static void mkworklist(Isel *s) { - size_t i; - - for (i = 0; bsiter(s->initial, &i); i++) { - if (bshas(s->prepainted, i)) - continue; - else if (!istrivial(s, i)) - wlput(&s->wlspill, &s->nwlspill, locmap[i]); - else if (moverelated(s, i)) { - wlput(&s->wlfreeze, &s->nwlfreeze, locmap[i]); - } - else - wlput(&s->wlsimp, &s->nwlsimp, locmap[i]); - locmap[i]->reg.colour = 0; - } + size_t i; + + for (i = 0; bsiter(s->initial, &i); i++) { + if (bshas(s->prepainted, i)) + continue; + else if (!istrivial(s, i)) + wlput(&s->wlspill, &s->nwlspill, locmap[i]); + else if (moverelated(s, i)) { + wlput(&s->wlfreeze, &s->nwlfreeze, locmap[i]); + } + else + wlput(&s->wlsimp, &s->nwlsimp, locmap[i]); + locmap[i]->reg.colour = 0; + } } static void enablemove(Isel *s, regid n) { - size_t i, j; - Insn **il; - size_t ni; - - ni = nodemoves(s, n, &il); - for (i = 0; i < ni; i++) { - if (!bshas(s->mactiveset, il[i]->uid)) - continue; - for (j = 0; j < s->nmactive; j++) { - if (il[i] == s->mactive[j]) { - ldel(&s->mactive, &s->nmactive, j); - lappend(&s->wlmove, &s->nwlmove, il[i]); - bsdel(s->mactiveset, il[i]->uid); - bsput(s->wlmoveset, il[i]->uid); - } - } - } + size_t i, j; + Insn **il; + size_t ni; + + ni = nodemoves(s, n, &il); + for (i = 0; i < ni; i++) { + if (!bshas(s->mactiveset, il[i]->uid)) + continue; + for (j = 0; j < s->nmactive; j++) { + if (il[i] == s->mactive[j]) { + ldel(&s->mactive, &s->nmactive, j); + lappend(&s->wlmove, &s->nwlmove, il[i]); + bsdel(s->mactiveset, il[i]->uid); + bsput(s->wlmoveset, il[i]->uid); + } + } + } } static void decdegree(Isel *s, regid m) { - int before, after; - int found; - size_t idx, i; - regid n; - - assert(m < s->nreg); - before = istrivial(s, m); - s->degree[m]--; - after = istrivial(s, m); - - if (before != after) { - enablemove(s, m); - for (i = 0; i < s->ngadj[m]; i++) { - n = s->gadj[m][i]; - if (adjavail(s, n)) - enablemove(s, n); - } - - /* Subtle: - * - * If this code is being called from coalesce(), - * then the degree could have been bumped up only - * temporarily. This means that the node can already - * be on wlfreeze or wlsimp. - * - * Therefore, if we don't find it on wlspill, we assert - * that the node is already on the list that we'd be - * moving it to. - */ - found = wlfind(s->wlspill, s->nwlspill, m, &idx); - if (found) - wldel(s, &s->wlspill, &s->nwlspill, idx); - if (moverelated(s, m)) { - if (!found) { - assert(wlfind(s->wlfreeze, s->nwlfreeze, m, &idx) != 0); - } else { - wlput(&s->wlfreeze, &s->nwlfreeze, locmap[m]); - } - } else { - if (!found) { - assert(wlfind(s->wlsimp, s->nwlsimp, m, &idx)); - } else { - wlput(&s->wlsimp, &s->nwlsimp, locmap[m]); - } - } - } + int before, after; + int found; + size_t idx, i; + regid n; + + assert(m < s->nreg); + before = istrivial(s, m); + s->degree[m]--; + after = istrivial(s, m); + + if (before != after) { + enablemove(s, m); + for (i = 0; i < s->ngadj[m]; i++) { + n = s->gadj[m][i]; + if (adjavail(s, n)) + enablemove(s, n); + } + + /* Subtle: + * + * If this code is being called from coalesce(), + * then the degree could have been bumped up only + * temporarily. This means that the node can already + * be on wlfreeze or wlsimp. + * + * Therefore, if we don't find it on wlspill, we assert + * that the node is already on the list that we'd be + * moving it to. + */ + found = wlfind(s->wlspill, s->nwlspill, m, &idx); + if (found) + wldel(s, &s->wlspill, &s->nwlspill, idx); + if (moverelated(s, m)) { + if (!found) { + assert(wlfind(s->wlfreeze, s->nwlfreeze, m, &idx) != 0); + } else { + wlput(&s->wlfreeze, &s->nwlfreeze, locmap[m]); + } + } else { + if (!found) { + assert(wlfind(s->wlsimp, s->nwlsimp, m, &idx)); + } else { + wlput(&s->wlsimp, &s->nwlsimp, locmap[m]); + } + } + } } static void simp(Isel *s) { - Loc *l; - regid m; - size_t i; - - l = lpop(&s->wlsimp, &s->nwlsimp); - wlput(&s->selstk, &s->nselstk, l); - for (i = 0; i < s->ngadj[l->reg.id]; i++) { - m = s->gadj[l->reg.id][i]; - if (adjavail(s, m)) - decdegree(s, m); - } + Loc *l; + regid m; + size_t i; + + l = lpop(&s->wlsimp, &s->nwlsimp); + wlput(&s->selstk, &s->nselstk, l); + for (i = 0; i < s->ngadj[l->reg.id]; i++) { + m = s->gadj[l->reg.id][i]; + if (adjavail(s, m)) + decdegree(s, m); + } } static regid getmappedalias(Loc **aliasmap, size_t nreg, regid id) { - /* - * if we get called from rewrite(), we can get a register that - * we just created, with an id bigger than the number of entries - * in the alias map. We should just return its id in that case. - */ - while (id < nreg) { - if (!aliasmap[id]) - break; - id = aliasmap[id]->reg.id; - }; - return id; + /* + * if we get called from rewrite(), we can get a register that + * we just created, with an id bigger than the number of entries + * in the alias map. We should just return its id in that case. + */ + while (id < nreg) { + if (!aliasmap[id]) + break; + id = aliasmap[id]->reg.id; + }; + return id; } static regid getalias(Isel *s, regid id) { - return getmappedalias(s->aliasmap, s->nreg, id); + return getmappedalias(s->aliasmap, s->nreg, id); } static void wladd(Isel *s, regid u) { - size_t i; - - if (bshas(s->prepainted, u)) - return; - if (moverelated(s, u)) - return; - if (!istrivial(s, u)) - return; - - assert(locmap[u]->list == &s->wlfreeze || locmap[u]->list == &s->wlsimp); - if (wlfind(s->wlfreeze, s->nwlfreeze, u, &i)) - wldel(s, &s->wlfreeze, &s->nwlfreeze, i); - wlput(&s->wlsimp, &s->nwlsimp, locmap[u]); + size_t i; + + if (bshas(s->prepainted, u)) + return; + if (moverelated(s, u)) + return; + if (!istrivial(s, u)) + return; + + assert(locmap[u]->list == &s->wlfreeze || locmap[u]->list == &s->wlsimp); + if (wlfind(s->wlfreeze, s->nwlfreeze, u, &i)) + wldel(s, &s->wlfreeze, &s->nwlfreeze, i); + wlput(&s->wlsimp, &s->nwlsimp, locmap[u]); } static int conservative(Isel *s, regid u, regid v) { - int k; - size_t i; - regid n; - - k = 0; - for (i = 0; i < s->ngadj[u]; i++) { - n = s->gadj[u][i]; - if (adjavail(s, n) && !istrivial(s, n)) - k++; - } - for (i = 0; i < s->ngadj[v]; i++) { - n = s->gadj[v][i]; - if (adjavail(s, n) && !istrivial(s, n)) - k++; - } - return k < _K[rclass(locmap[u])]; + int k; + size_t i; + regid n; + + k = 0; + for (i = 0; i < s->ngadj[u]; i++) { + n = s->gadj[u][i]; + if (adjavail(s, n) && !istrivial(s, n)) + k++; + } + for (i = 0; i < s->ngadj[v]; i++) { + n = s->gadj[v][i]; + if (adjavail(s, n) && !istrivial(s, n)) + k++; + } + return k < _K[rclass(locmap[u])]; } /* FIXME: is this actually correct? */ static int ok(Isel *s, regid t, regid r) { - return istrivial(s, t) || bshas(s->prepainted, t) || gbhasedge(s, t, r); + return istrivial(s, t) || bshas(s->prepainted, t) || gbhasedge(s, t, r); } static int combinable(Isel *s, regid u, regid v) { - regid t; - size_t i; - - /* Regs of different modes can't be combined as things stand. - * In principle they should be combinable, but it confused the - * whole mode dance. */ - if (locmap[u]->mode != locmap[v]->mode) - return 0; - /* if u isn't prepainted, can we conservatively coalesce? */ - if (!bshas(s->prepainted, u) && conservative(s, u, v)) - return 1; - - /* if it is, are the adjacent nodes ok to combine with this? */ - for (i = 0; i < s->ngadj[v]; i++) { - t = s->gadj[v][i]; - if (adjavail(s, t) && !ok(s, t, u)) - return 0; - } - return 1; + regid t; + size_t i; + + /* Regs of different modes can't be combined as things stand. + * In principle they should be combinable, but it confused the + * whole mode dance. */ + if (locmap[u]->mode != locmap[v]->mode) + return 0; + /* if u isn't prepainted, can we conservatively coalesce? */ + if (!bshas(s->prepainted, u) && conservative(s, u, v)) + return 1; + + /* if it is, are the adjacent nodes ok to combine with this? */ + for (i = 0; i < s->ngadj[v]; i++) { + t = s->gadj[v][i]; + if (adjavail(s, t) && !ok(s, t, u)) + return 0; + } + return 1; } static void combine(Isel *s, regid u, regid v) { - regid t; - size_t idx; - size_t i, j; - int has; - - if (debugopt['r'] > 2) - printedge(stdout, "combining:", u, v); - if (wlfind(s->wlfreeze, s->nwlfreeze, v, &idx)) - wldel(s, &s->wlfreeze, &s->nwlfreeze, idx); - else if (wlfind(s->wlspill, s->nwlspill, v, &idx)) { - wldel(s, &s->wlspill, &s->nwlspill, idx); - } - wlputset(s->coalesced, v); - s->aliasmap[v] = locmap[u]; - s->nuses[u] += s->nuses[v]; - - /* nodemoves[u] = nodemoves[u] U nodemoves[v] */ - for (i = 0; i < s->nrmoves[v]; i++) { - has = 0; - for (j = 0; j < s->nrmoves[u]; j++) { - if (s->rmoves[v][i] == s->rmoves[u][j]) { - has = 1; - break; - } - } - if (!has) - lappend(&s->rmoves[u], &s->nrmoves[u], s->rmoves[v][i]); - } - - for (i = 0; i < s->ngadj[v]; i++) { - t = s->gadj[v][i]; - if (!adjavail(s, t)) - continue; - if (debugopt['r'] > 2) - printedge(stdout, "combine-putedge:", t, u); - addedge(s, t, u); - decdegree(s, t); - } - if (!istrivial(s, u) && wlfind(s->wlfreeze, s->nwlfreeze, u, &idx)) { - wldel(s, &s->wlfreeze, &s->nwlfreeze, idx); - wlput(&s->wlspill, &s->nwlspill, locmap[u]); - } + regid t; + size_t idx; + size_t i, j; + int has; + + if (debugopt['r'] > 2) + printedge(stdout, "combining:", u, v); + if (wlfind(s->wlfreeze, s->nwlfreeze, v, &idx)) + wldel(s, &s->wlfreeze, &s->nwlfreeze, idx); + else if (wlfind(s->wlspill, s->nwlspill, v, &idx)) { + wldel(s, &s->wlspill, &s->nwlspill, idx); + } + wlputset(s->coalesced, v); + s->aliasmap[v] = locmap[u]; + s->nuses[u] += s->nuses[v]; + + /* nodemoves[u] = nodemoves[u] U nodemoves[v] */ + for (i = 0; i < s->nrmoves[v]; i++) { + has = 0; + for (j = 0; j < s->nrmoves[u]; j++) { + if (s->rmoves[v][i] == s->rmoves[u][j]) { + has = 1; + break; + } + } + if (!has) + lappend(&s->rmoves[u], &s->nrmoves[u], s->rmoves[v][i]); + } + + for (i = 0; i < s->ngadj[v]; i++) { + t = s->gadj[v][i]; + if (!adjavail(s, t)) + continue; + if (debugopt['r'] > 2) + printedge(stdout, "combine-putedge:", t, u); + addedge(s, t, u); + decdegree(s, t); + } + if (!istrivial(s, u) && wlfind(s->wlfreeze, s->nwlfreeze, u, &idx)) { + wldel(s, &s->wlfreeze, &s->nwlfreeze, idx); + wlput(&s->wlspill, &s->nwlspill, locmap[u]); + } } static int constrained(Isel *s, regid u, regid v) { - size_t i; - - if (bshas(s->prepainted, v)) - return 1; - if (bshas(s->prepainted, u)) - for (i = 0; i < Nmode; i++) - if (regmap[colourmap[u]][i] && gbhasedge(s, regmap[colourmap[u]][i], v)) - return 1; - return gbhasedge(s, u, v); + size_t i; + + if (bshas(s->prepainted, v)) + return 1; + if (bshas(s->prepainted, u)) + for (i = 0; i < Nmode; i++) + if (regmap[colourmap[u]][i] && gbhasedge(s, regmap[colourmap[u]][i], v)) + return 1; + return gbhasedge(s, u, v); } static void coalesce(Isel *s) { - Insn *m; - regid u, v, tmp; - - m = lpop(&s->wlmove, &s->nwlmove); - bsdel(s->wlmoveset, m->uid); - u = getalias(s, m->args[0]->reg.id); - v = getalias(s, m->args[1]->reg.id); - - if (bshas(s->prepainted, v)) { - tmp = u; - u = v; - v = tmp; - } - - if (u == v) { - lappend(&s->mcoalesced, &s->nmcoalesced, m); - wladd(s, u); - wladd(s, v); - } else if (constrained(s, u, v)) { - lappend(&s->mconstrained, &s->nmconstrained, m); - wladd(s, u); - wladd(s, v); - } else if (combinable(s, u, v)) { - lappend(&s->mcoalesced, &s->nmcoalesced, m); - combine(s, u, v); - wladd(s, u); - } else { - lappend(&s->mactive, &s->nmactive, m); - bsput(s->mactiveset, m->uid); - } + Insn *m; + regid u, v, tmp; + + m = lpop(&s->wlmove, &s->nwlmove); + bsdel(s->wlmoveset, m->uid); + u = getalias(s, m->args[0]->reg.id); + v = getalias(s, m->args[1]->reg.id); + + if (bshas(s->prepainted, v)) { + tmp = u; + u = v; + v = tmp; + } + + if (u == v) { + lappend(&s->mcoalesced, &s->nmcoalesced, m); + wladd(s, u); + wladd(s, v); + } else if (constrained(s, u, v)) { + lappend(&s->mconstrained, &s->nmconstrained, m); + wladd(s, u); + wladd(s, v); + } else if (combinable(s, u, v)) { + lappend(&s->mcoalesced, &s->nmcoalesced, m); + combine(s, u, v); + wladd(s, u); + } else { + lappend(&s->mactive, &s->nmactive, m); + bsput(s->mactiveset, m->uid); + } } static int mldel(Insn ***ml, size_t *nml, Bitset *bs, Insn *m) { - size_t i; - if (bshas(bs, m->uid)) { - bsdel(bs, m->uid); - for (i = 0; i < *nml; i++) { - if (m == (*ml)[i]) { - ldel(ml, nml, i); - return 1; - } - } - } - return 0; + size_t i; + if (bshas(bs, m->uid)) { + bsdel(bs, m->uid); + for (i = 0; i < *nml; i++) { + if (m == (*ml)[i]) { + ldel(ml, nml, i); + return 1; + } + } + } + return 0; } static void freezemoves(Isel *s, Loc *u) { - size_t i; - Insn **ml; - Insn *m; - size_t nml; - size_t idx; - Loc *v; - - nml = nodemoves(s, u->reg.id, &ml); - for (i = 0; i < nml; i++) { - m = ml[i]; - if (getalias(s, m->args[0]->reg.id) == getalias(s, u->reg.id)) - v = locmap[getalias(s, m->args[1]->reg.id)]; - else - v = locmap[getalias(s, m->args[0]->reg.id)]; - - if (!mldel(&s->mactive, &s->nmactive, s->mactiveset, m)) - mldel(&s->wlmove, &s->nwlmove, s->wlmoveset, m); - - lappend(&s->mfrozen, &s->nmfrozen, m); - if (!moverelated(s, v->reg.id) && istrivial(s, v->reg.id)) { - if (!wlfind(s->wlfreeze, s->nwlfreeze, v->reg.id, &idx)) - die("Reg %zd not in freeze wl\n", v->reg.id); - wldel(s, &s->wlfreeze, &s->nwlfreeze, idx); - wlput(&s->wlsimp, &s->nwlsimp, v); - } - - } - lfree(&ml, &nml); + size_t i; + Insn **ml; + Insn *m; + size_t nml; + size_t idx; + Loc *v; + + nml = nodemoves(s, u->reg.id, &ml); + for (i = 0; i < nml; i++) { + m = ml[i]; + if (getalias(s, m->args[0]->reg.id) == getalias(s, u->reg.id)) + v = locmap[getalias(s, m->args[1]->reg.id)]; + else + v = locmap[getalias(s, m->args[0]->reg.id)]; + + if (!mldel(&s->mactive, &s->nmactive, s->mactiveset, m)) + mldel(&s->wlmove, &s->nwlmove, s->wlmoveset, m); + + lappend(&s->mfrozen, &s->nmfrozen, m); + if (!moverelated(s, v->reg.id) && istrivial(s, v->reg.id)) { + if (!wlfind(s->wlfreeze, s->nwlfreeze, v->reg.id, &idx)) + die("Reg %zd not in freeze wl\n", v->reg.id); + wldel(s, &s->wlfreeze, &s->nwlfreeze, idx); + wlput(&s->wlsimp, &s->nwlsimp, v); + } + + } + lfree(&ml, &nml); } static void freeze(Isel *s) { - Loc *l; + Loc *l; - l = lpop(&s->wlfreeze, &s->nwlfreeze); - wlput(&s->wlsimp, &s->nwlsimp, l); - freezemoves(s, l); + l = lpop(&s->wlfreeze, &s->nwlfreeze); + wlput(&s->wlsimp, &s->nwlsimp, l); + freezemoves(s, l); } /* Select the spill candidates */ static void selspill(Isel *s) { - size_t i; - Loc *m; - - /* FIXME: pick a better heuristic for spilling */ - m = NULL; - for (i = 0; i < s->nwlspill; i++) { - if (!bshas(s->shouldspill, s->wlspill[i]->reg.id)) - continue; - m = s->wlspill[i]; - wldel(s, &s->wlspill, &s->nwlspill, i); - break; - } - if (!m) { - for (i = 0; i < s->nwlspill; i++) { - if (bshas(s->neverspill, s->wlspill[i]->reg.id)) { - continue; - } - m = s->wlspill[i]; - wldel(s, &s->wlspill, &s->nwlspill, i); - break; - } - } - assert(m != NULL); - wlput(&s->wlsimp, &s->nwlsimp, m); - freezemoves(s, m); + size_t i; + Loc *m; + + /* FIXME: pick a better heuristic for spilling */ + m = NULL; + for (i = 0; i < s->nwlspill; i++) { + if (!bshas(s->shouldspill, s->wlspill[i]->reg.id)) + continue; + m = s->wlspill[i]; + wldel(s, &s->wlspill, &s->nwlspill, i); + break; + } + if (!m) { + for (i = 0; i < s->nwlspill; i++) { + if (bshas(s->neverspill, s->wlspill[i]->reg.id)) { + continue; + } + m = s->wlspill[i]; + wldel(s, &s->wlspill, &s->nwlspill, i); + break; + } + } + assert(m != NULL); + wlput(&s->wlsimp, &s->nwlsimp, m); + freezemoves(s, m); } /* @@ -958,98 +957,98 @@ static void selspill(Isel *s) */ static int paint(Isel *s) { - int taken[Nreg]; - Loc *n, *w; - regid l; - size_t i, j; - int spilled; - int found; - - spilled = 0; - while (s->nselstk) { - memset(taken, 0, Nreg*sizeof(int)); - n = lpop(&s->selstk, &s->nselstk); - - for (j = 0; j < s->ngadj[n->reg.id];j++) { - l = s->gadj[n->reg.id][j]; - if (debugopt['r'] > 1) - printedge(stdout, "paint-edge:", n->reg.id, l); - w = locmap[getalias(s, l)]; - if (w->reg.colour) - taken[colourmap[w->reg.colour]] = 1; - } - - found = 0; - for (i = 0; i < Northogonal; i++) { - if (regmap[i][n->mode] && !taken[i]) { - n->reg.colour = regmap[i][n->mode]; - found = 1; - break; - } - } - if (!found) { - spilled = 1; - wlputset(s->spilled, n->reg.id); - } - } - for (l = 0; bsiter(s->coalesced, &l); l++) { - n = locmap[getalias(s, l)]; - locmap[l]->reg.colour = n->reg.colour; - } - return spilled; + int taken[Nreg]; + Loc *n, *w; + regid l; + size_t i, j; + int spilled; + int found; + + spilled = 0; + while (s->nselstk) { + memset(taken, 0, Nreg*sizeof(int)); + n = lpop(&s->selstk, &s->nselstk); + + for (j = 0; j < s->ngadj[n->reg.id];j++) { + l = s->gadj[n->reg.id][j]; + if (debugopt['r'] > 1) + printedge(stdout, "paint-edge:", n->reg.id, l); + w = locmap[getalias(s, l)]; + if (w->reg.colour) + taken[colourmap[w->reg.colour]] = 1; + } + + found = 0; + for (i = 0; i < Northogonal; i++) { + if (regmap[i][n->mode] && !taken[i]) { + n->reg.colour = regmap[i][n->mode]; + found = 1; + break; + } + } + if (!found) { + spilled = 1; + wlputset(s->spilled, n->reg.id); + } + } + for (l = 0; bsiter(s->coalesced, &l); l++) { + n = locmap[getalias(s, l)]; + locmap[l]->reg.colour = n->reg.colour; + } + return spilled; } static Loc *mapfind(Isel *s, Htab *map, Loc *old) { - Loc *new; - Loc *base; - Loc *idx; - regid id; - - if (!old) - return NULL; - - new = NULL; - if (old->type == Locreg) { - id = getalias(s, old->reg.id); - new = htget(map, locmap[id]); - } else if (old->type == Locmem || old->type == Locmeml) { - base = old->mem.base; - idx = old->mem.idx; - if (base) - base = locmap[getalias(s, base->reg.id)]; - if (idx) - idx = locmap[getalias(s, idx->reg.id)]; - base = mapfind(s, map, base); - idx = mapfind(s, map, idx); - if (base != old->mem.base || idx != old->mem.idx) { - if (old->type == Locmem) - new = locmems(old->mem.constdisp, base, idx, old->mem.scale, old->mode); - else - new = locmemls(old->mem.lbldisp, base, idx, old->mem.scale, old->mode); - } - } - if (new) - return new; - return old; + Loc *new; + Loc *base; + Loc *idx; + regid id; + + if (!old) + return NULL; + + new = NULL; + if (old->type == Locreg) { + id = getalias(s, old->reg.id); + new = htget(map, locmap[id]); + } else if (old->type == Locmem || old->type == Locmeml) { + base = old->mem.base; + idx = old->mem.idx; + if (base) + base = locmap[getalias(s, base->reg.id)]; + if (idx) + idx = locmap[getalias(s, idx->reg.id)]; + base = mapfind(s, map, base); + idx = mapfind(s, map, idx); + if (base != old->mem.base || idx != old->mem.idx) { + if (old->type == Locmem) + new = locmems(old->mem.constdisp, base, idx, old->mem.scale, old->mode); + else + new = locmemls(old->mem.lbldisp, base, idx, old->mem.scale, old->mode); + } + } + if (new) + return new; + return old; } static Loc *spillslot(Isel *s, regid reg) { - size_t stkoff; + size_t stkoff; - stkoff = ptoi(htget(s->spillslots, itop(reg))); - return locmem(-stkoff, locphysreg(Rrbp), NULL, locmap[reg]->mode); + stkoff = ptoi(htget(s->spillslots, itop(reg))); + return locmem(-stkoff, locphysreg(Rrbp), NULL, locmap[reg]->mode); } static void updatelocs(Isel *s, Htab *map, Insn *insn) { - size_t i; + size_t i; - for (i = 0; i < insn->nargs; i++) { - insn->args[i] = mapfind(s, map, insn->args[i]); - insn->args[i] = mapfind(s, map, insn->args[i]); - } + for (i = 0; i < insn->nargs; i++) { + insn->args[i] = mapfind(s, map, insn->args[i]); + insn->args[i] = mapfind(s, map, insn->args[i]); + } } /* @@ -1059,82 +1058,82 @@ static void updatelocs(Isel *s, Htab *map, Insn *insn) */ static int remap(Isel *s, Htab *map, Insn *insn, regid *use, size_t nuse, regid *def, size_t ndef) { - regid ruse, rdef; - int remapped; - Loc *tmp; - size_t i; - - remapped = 0; - for (i = 0; i < nuse; i++) { - ruse = getalias(s, use[i]); - if (!bshas(s->spilled, ruse)) - continue; - tmp = locreg(locmap[ruse]->mode); - htput(map, locmap[ruse], tmp); - bsput(s->neverspill, tmp->reg.id); - remapped = 1; - } - - for (i = 0; i < ndef; i++) { - rdef = getalias(s, def[i]); - if (!bshas(s->spilled, rdef)) - continue; - if (hthas(map, locmap[rdef])) - continue; - tmp = locreg(locmap[rdef]->mode); - htput(map, locmap[rdef], tmp); - bsput(s->neverspill, tmp->reg.id); - remapped = 1; - } - - return remapped; + regid ruse, rdef; + int remapped; + Loc *tmp; + size_t i; + + remapped = 0; + for (i = 0; i < nuse; i++) { + ruse = getalias(s, use[i]); + if (!bshas(s->spilled, ruse)) + continue; + tmp = locreg(locmap[ruse]->mode); + htput(map, locmap[ruse], tmp); + bsput(s->neverspill, tmp->reg.id); + remapped = 1; + } + + for (i = 0; i < ndef; i++) { + rdef = getalias(s, def[i]); + if (!bshas(s->spilled, rdef)) + continue; + if (hthas(map, locmap[rdef])) + continue; + tmp = locreg(locmap[rdef]->mode); + htput(map, locmap[rdef], tmp); + bsput(s->neverspill, tmp->reg.id); + remapped = 1; + } + + return remapped; } static int nopmov(Insn *insn) { - if (insn->op != Imov && insn->op != Imovs) - return 0; - if (insn->args[0]->type != Locreg || insn->args[1]->type != Locreg) - return 0; - return insn->args[0]->reg.id == insn->args[1]->reg.id; + if (insn->op != Imov && insn->op != Imovs) + return 0; + if (insn->args[0]->type != Locreg || insn->args[1]->type != Locreg) + return 0; + return insn->args[0]->reg.id == insn->args[1]->reg.id; } void replacealias(Isel *s, Loc **map, size_t nreg, Insn *insn) { - size_t i; - Loc *l; - - if (!map) - return; - for (i = 0; i < insn->nargs; i++) { - l = insn->args[i]; - if (l->type == Locreg) { - insn->args[i] = locmap[getalias(s, l->reg.id)]; - } else if (l->type == Locmem || l->type == Locmeml) { - if (l->mem.base) - l->mem.base = locmap[getalias(s, l->mem.base->reg.id)]; - if (l->mem.idx) - l->mem.idx = locmap[getalias(s, l->mem.idx->reg.id)]; - } - } + size_t i; + Loc *l; + + if (!map) + return; + for (i = 0; i < insn->nargs; i++) { + l = insn->args[i]; + if (l->type == Locreg) { + insn->args[i] = locmap[getalias(s, l->reg.id)]; + } else if (l->type == Locmem || l->type == Locmeml) { + if (l->mem.base) + l->mem.base = locmap[getalias(s, l->mem.base->reg.id)]; + if (l->mem.idx) + l->mem.idx = locmap[getalias(s, l->mem.idx->reg.id)]; + } + } } static ulong reglochash(void *p) { - Loc *l; - - l = p; - return inthash(l->reg.id); + Loc *l; + + l = p; + return inthash(l->reg.id); } static int regloceq(void *pa, void *pb) { - Loc *a, *b; - - a = pa; - b = pb; - return a->reg.id == b->reg.id; + Loc *a, *b; + + a = pa; + b = pb; + return a->reg.id == b->reg.id; } /* * Rewrite instructions using spilled registers, inserting @@ -1142,74 +1141,74 @@ static int regloceq(void *pa, void *pb) */ static void rewritebb(Isel *s, Asmbb *bb, Loc **aliasmap) { - regid use[Nreg], def[Nreg]; - size_t nuse, ndef; - Insn *insn, *mov; - size_t i, j; - Insn **new; - size_t nnew; - Htab *map; - Loc *tmp; - - new = NULL; - nnew = 0; - if (!bb) - return; - map = mkht(reglochash, regloceq); - for (j = 0; j < bb->ni; j++) { - insn = bb->il[j]; - replacealias(s, aliasmap, s->nreg, insn); - if (nopmov(insn)) - continue; - nuse = uses(insn, use); - ndef = defs(insn, def); - /* if there is a remapping, insert the loads and stores as needed */ - if (remap(s, map, insn, use, nuse, def, ndef)) { - for (i = 0; i < nuse; i++) { - tmp = htget(map, locmap[use[i]]); - if (!tmp) - continue; - if (isfloatmode(tmp->mode)) - mov = mkinsn(Imovs, spillslot(s, use[i]), tmp, NULL); - else - mov = mkinsn(Imov, spillslot(s, use[i]), tmp, NULL); - lappend(&new, &nnew, mov); - } - updatelocs(s, map, insn); - lappend(&new, &nnew, insn); - for (i = 0; i < ndef; i++) { - tmp = htget(map, locmap[def[i]]); - if (!tmp) - continue; - if (isfloatmode(tmp->mode)) - mov = mkinsn(Imovs, tmp, spillslot(s, def[i]), NULL); - else - mov = mkinsn(Imov, tmp, spillslot(s, def[i]), NULL); - lappend(&new, &nnew, mov); - } - for (i = 0; i < nuse; i++) - htdel(map, locmap[use[i]]); - for (i = 0; i < ndef; i++) - htdel(map, locmap[def[i]]); - } else { - lappend(&new, &nnew, insn); - } - } - lfree(&bb->il, &bb->ni); - bb->il = new; - bb->ni = nnew; + regid use[Nreg], def[Nreg]; + size_t nuse, ndef; + Insn *insn, *mov; + size_t i, j; + Insn **new; + size_t nnew; + Htab *map; + Loc *tmp; + + new = NULL; + nnew = 0; + if (!bb) + return; + map = mkht(reglochash, regloceq); + for (j = 0; j < bb->ni; j++) { + insn = bb->il[j]; + replacealias(s, aliasmap, s->nreg, insn); + if (nopmov(insn)) + continue; + nuse = uses(insn, use); + ndef = defs(insn, def); + /* if there is a remapping, insert the loads and stores as needed */ + if (remap(s, map, insn, use, nuse, def, ndef)) { + for (i = 0; i < nuse; i++) { + tmp = htget(map, locmap[use[i]]); + if (!tmp) + continue; + if (isfloatmode(tmp->mode)) + mov = mkinsn(Imovs, spillslot(s, use[i]), tmp, NULL); + else + mov = mkinsn(Imov, spillslot(s, use[i]), tmp, NULL); + lappend(&new, &nnew, mov); + } + updatelocs(s, map, insn); + lappend(&new, &nnew, insn); + for (i = 0; i < ndef; i++) { + tmp = htget(map, locmap[def[i]]); + if (!tmp) + continue; + if (isfloatmode(tmp->mode)) + mov = mkinsn(Imovs, tmp, spillslot(s, def[i]), NULL); + else + mov = mkinsn(Imov, tmp, spillslot(s, def[i]), NULL); + lappend(&new, &nnew, mov); + } + for (i = 0; i < nuse; i++) + htdel(map, locmap[use[i]]); + for (i = 0; i < ndef; i++) + htdel(map, locmap[def[i]]); + } else { + lappend(&new, &nnew, insn); + } + } + lfree(&bb->il, &bb->ni); + bb->il = new; + bb->ni = nnew; } static void addspill(Isel *s, Loc *l) { - s->stksz->lit += modesize[l->mode]; - s->stksz->lit = align(s->stksz->lit, modesize[l->mode]); - if (debugopt['r']) { - printf("spill "); - dbglocprint(stdout, l, 'x'); - printf(" to %zd(%%rbp)\n", s->stksz->lit); - } - htput(s->spillslots, itop(l->reg.id), itop(s->stksz->lit)); + s->stksz->lit += modesize[l->mode]; + s->stksz->lit = align(s->stksz->lit, modesize[l->mode]); + if (debugopt['r']) { + printf("spill "); + dbglocprint(stdout, l, 'x'); + printf(" to %zd(%%rbp)\n", s->stksz->lit); + } + htput(s->spillslots, itop(l->reg.id), itop(s->stksz->lit)); } /* @@ -1226,18 +1225,18 @@ static void addspill(Isel *s, Loc *l) */ static void rewrite(Isel *s, Loc **aliasmap) { - size_t i; - - s->spillslots = mkht(ptrhash, ptreq); - /* set up stack locations for all spilled registers. */ - for (i = 0; bsiter(s->spilled, &i); i++) - addspill(s, locmap[i]); - - /* rewrite instructions using them */ - for (i = 0; i < s->nbb; i++) - rewritebb(s, s->bb[i], aliasmap); - htfree(s->spillslots); - bsclear(s->spilled); + size_t i; + + s->spillslots = mkht(ptrhash, ptreq); + /* set up stack locations for all spilled registers. */ + for (i = 0; bsiter(s->spilled, &i); i++) + addspill(s, locmap[i]); + + /* rewrite instructions using them */ + for (i = 0; i < s->nbb; i++) + rewritebb(s, s->bb[i], aliasmap); + htfree(s->spillslots); + bsclear(s->spilled); } /* @@ -1250,187 +1249,187 @@ static void rewrite(Isel *s, Loc **aliasmap) */ static void delnops(Isel *s) { - Insn *insn; - Asmbb *bb; - Insn **new; - size_t nnew; - size_t i, j; - - for (i = 0; i < s->nbb; i++) { - if (!s->bb[i]) - continue; - new = NULL; - nnew = 0; - bb = s->bb[i]; - for (j = 0; j < bb->ni; j++) { - insn = bb->il[j]; - if (ismove(insn) && insn->args[0]->reg.colour == insn->args[1]->reg.colour) - continue; - lappend(&new, &nnew, insn); - } - lfree(&bb->il, &bb->ni); - bb->il = new; - bb->ni = nnew; - } - if (debugopt['r']) - dumpasm(s, stdout); + Insn *insn; + Asmbb *bb; + Insn **new; + size_t nnew; + size_t i, j; + + for (i = 0; i < s->nbb; i++) { + if (!s->bb[i]) + continue; + new = NULL; + nnew = 0; + bb = s->bb[i]; + for (j = 0; j < bb->ni; j++) { + insn = bb->il[j]; + if (ismove(insn) && insn->args[0]->reg.colour == insn->args[1]->reg.colour) + continue; + lappend(&new, &nnew, insn); + } + lfree(&bb->il, &bb->ni); + bb->il = new; + bb->ni = nnew; + } + if (debugopt['r']) + dumpasm(s, stdout); } void regalloc(Isel *s) { - int spilled; - size_t i; - Loc **aliasmap; - - /* Initialize the list of prepainted registers */ - s->prepainted = mkbs(); - bsput(s->prepainted, 0); - for (i = 0; i < Nreg; i++) - bsput(s->prepainted, i); - - s->shouldspill = mkbs(); - s->neverspill = mkbs(); - s->initial = mkbs(); - for (i = 0; i < s->nsaved; i++) - bsput(s->shouldspill, s->calleesave[i]->reg.id); - do { - aliasmap = NULL; - setup(s); - liveness(s); - build(s); - mkworklist(s); - if (debugopt['r']) - dumpasm(s, stdout); - do { - if (s->nwlsimp) - simp(s); - else if (s->nwlmove) - coalesce(s); - else if (s->nwlfreeze) - freeze(s); - else if (s->nwlspill) { - if (!aliasmap) - aliasmap = memdup(s->aliasmap, s->nreg * sizeof(Loc*)); - selspill(s); - } - } while (s->nwlsimp || s->nwlmove || s->nwlfreeze || s->nwlspill); - spilled = paint(s); - if (spilled) - rewrite(s, aliasmap); - } while (spilled); - delnops(s); - bsfree(s->prepainted); - bsfree(s->shouldspill); - bsfree(s->neverspill); - gfree(s); + int spilled; + size_t i; + Loc **aliasmap; + + /* Initialize the list of prepainted registers */ + s->prepainted = mkbs(); + bsput(s->prepainted, 0); + for (i = 0; i < Nreg; i++) + bsput(s->prepainted, i); + + s->shouldspill = mkbs(); + s->neverspill = mkbs(); + s->initial = mkbs(); + for (i = 0; i < s->nsaved; i++) + bsput(s->shouldspill, s->calleesave[i]->reg.id); + do { + aliasmap = NULL; + setup(s); + liveness(s); + build(s); + mkworklist(s); + if (debugopt['r']) + dumpasm(s, stdout); + do { + if (s->nwlsimp) + simp(s); + else if (s->nwlmove) + coalesce(s); + else if (s->nwlfreeze) + freeze(s); + else if (s->nwlspill) { + if (!aliasmap) + aliasmap = memdup(s->aliasmap, s->nreg * sizeof(Loc*)); + selspill(s); + } + } while (s->nwlsimp || s->nwlmove || s->nwlfreeze || s->nwlspill); + spilled = paint(s); + if (spilled) + rewrite(s, aliasmap); + } while (spilled); + delnops(s); + bsfree(s->prepainted); + bsfree(s->shouldspill); + bsfree(s->neverspill); + gfree(s); } void wlprint(FILE *fd, char *name, Loc **wl, size_t nwl) { - size_t i; - char *sep; - - sep = ""; - fprintf(fd, "%s = [", name); - for (i = 0; i < nwl; i++) { - fprintf(fd, "%s", sep); - dbglocprint(fd, wl[i], 'x'); - fprintf(fd, "(%zd)", wl[i]->reg.id); - sep = ","; - } - fprintf(fd, "]\n"); + size_t i; + char *sep; + + sep = ""; + fprintf(fd, "%s = [", name); + for (i = 0; i < nwl; i++) { + fprintf(fd, "%s", sep); + dbglocprint(fd, wl[i], 'x'); + fprintf(fd, "(%zd)", wl[i]->reg.id); + sep = ","; + } + fprintf(fd, "]\n"); } static void setprint(FILE *fd, Bitset *s) { - char *sep; - size_t i; - - sep = ""; - for (i = 0; i < bsmax(s); i++) { - if (bshas(s, i)) { - fprintf(fd, "%s%zd", sep, i); - sep = ","; - } - } - fprintf(fd, "\n"); + char *sep; + size_t i; + + sep = ""; + for (i = 0; i < bsmax(s); i++) { + if (bshas(s, i)) { + fprintf(fd, "%s%zd", sep, i); + sep = ","; + } + } + fprintf(fd, "\n"); } static void locsetprint(FILE *fd, Bitset *s) { - char *sep; - size_t i; - - sep = ""; - for (i = 0; i < bsmax(s); i++) { - if (bshas(s, i)) { - fprintf(fd, "%s", sep); - dbglocprint(fd, locmap[i], 'x'); - sep = ","; - } - } - fprintf(fd, "\n"); + char *sep; + size_t i; + + sep = ""; + for (i = 0; i < bsmax(s); i++) { + if (bshas(s, i)) { + fprintf(fd, "%s", sep); + dbglocprint(fd, locmap[i], 'x'); + sep = ","; + } + } + fprintf(fd, "\n"); } static void printedge(FILE *fd, char *msg, size_t a, size_t b) { - fprintf(fd, "\t%s ", msg); - dbglocprint(fd, locmap[a], 'x'); - fprintf(fd, " -- "); - dbglocprint(fd, locmap[b], 'x'); - fprintf(fd, "\n"); + fprintf(fd, "\t%s ", msg); + dbglocprint(fd, locmap[a], 'x'); + fprintf(fd, " -- "); + dbglocprint(fd, locmap[b], 'x'); + fprintf(fd, "\n"); } void dumpasm(Isel *s, FILE *fd) { - size_t i, j; - char *sep; - Asmbb *bb; - - fprintf(fd, "WORKLISTS -- \n"); - wlprint(stdout, "spill", s->wlspill, s->nwlspill); - wlprint(stdout, "simp", s->wlsimp, s->nwlsimp); - wlprint(stdout, "freeze", s->wlfreeze, s->nwlfreeze); - /* noisy to dump this all the time; only dump for higher debug levels */ - if (debugopt['r'] > 2) { - fprintf(fd, "IGRAPH ----- \n"); - for (i = 0; i < s->nreg; i++) { - for (j = i; j < s->nreg; j++) { - if (gbhasedge(s, i, j)) - printedge(stdout, "", i, j); - } - } - } - fprintf(fd, "ASM -------- \n"); - for (j = 0; j < s->nbb; j++) { - bb = s->bb[j]; - if (!bb) - continue; - fprintf(fd, "\n"); - fprintf(fd, "Bb: %d labels=(", bb->id); - sep = ""; - for (i = 0; i < bb->nlbls; i++) {; - fprintf(fd, "%s%s", bb->lbls[i], sep); - sep = ","; - } - fprintf(fd, ")\n"); - - fprintf(fd, "Pred: "); - setprint(fd, bb->pred); - fprintf(fd, "Succ: "); - setprint(fd, bb->succ); - - fprintf(fd, "Use: "); - locsetprint(fd, bb->use); - fprintf(fd, "Def: "); - locsetprint(fd, bb->def); - fprintf(fd, "Livein: "); - locsetprint(fd, bb->livein); - fprintf(fd, "Liveout: "); - locsetprint(fd, bb->liveout); - for (i = 0; i < bb->ni; i++) - dbgiprintf(fd, bb->il[i]); - } - fprintf(fd, "ENDASM -------- \n"); + size_t i, j; + char *sep; + Asmbb *bb; + + fprintf(fd, "WORKLISTS -- \n"); + wlprint(stdout, "spill", s->wlspill, s->nwlspill); + wlprint(stdout, "simp", s->wlsimp, s->nwlsimp); + wlprint(stdout, "freeze", s->wlfreeze, s->nwlfreeze); + /* noisy to dump this all the time; only dump for higher debug levels */ + if (debugopt['r'] > 2) { + fprintf(fd, "IGRAPH ----- \n"); + for (i = 0; i < s->nreg; i++) { + for (j = i; j < s->nreg; j++) { + if (gbhasedge(s, i, j)) + printedge(stdout, "", i, j); + } + } + } + fprintf(fd, "ASM -------- \n"); + for (j = 0; j < s->nbb; j++) { + bb = s->bb[j]; + if (!bb) + continue; + fprintf(fd, "\n"); + fprintf(fd, "Bb: %d labels=(", bb->id); + sep = ""; + for (i = 0; i < bb->nlbls; i++) {; + fprintf(fd, "%s%s", bb->lbls[i], sep); + sep = ","; + } + fprintf(fd, ")\n"); + + fprintf(fd, "Pred: "); + setprint(fd, bb->pred); + fprintf(fd, "Succ: "); + setprint(fd, bb->succ); + + fprintf(fd, "Use: "); + locsetprint(fd, bb->use); + fprintf(fd, "Def: "); + locsetprint(fd, bb->def); + fprintf(fd, "Livein: "); + locsetprint(fd, bb->livein); + fprintf(fd, "Liveout: "); + locsetprint(fd, bb->liveout); + for (i = 0; i < bb->ni; i++) + dbgiprintf(fd, bb->il[i]); + } + fprintf(fd, "ENDASM -------- \n"); } diff --git a/6/simp.c b/6/simp.c index dd06dff..59a12e9 100644 --- a/6/simp.c +++ b/6/simp.c @@ -24,42 +24,42 @@ */ typedef struct Simp Simp; struct Simp { - int isglobl; - - Node **stmts; - size_t nstmts; - - /* return handling */ - Node *endlbl; - Node *ret; - int hasenv; - int isbigret; - - /* the array we're indexing for context within [] */ - Node **idxctx; - size_t nidxctx; - - /* pre/postinc handling */ - Node **incqueue; - size_t nqueue; - - /* break/continue handling */ - Node **loopstep; - size_t nloopstep; - Node **loopexit; - size_t nloopexit; - - /* location handling */ - Node **blobs; - size_t nblobs; - Htab *globls; - - Htab *stkoff; - Htab *envoff; - size_t stksz; - - Node **args; - size_t nargs; + int isglobl; + + Node **stmts; + size_t nstmts; + + /* return handling */ + Node *endlbl; + Node *ret; + int hasenv; + int isbigret; + + /* the array we're indexing for context within [] */ + Node **idxctx; + size_t nidxctx; + + /* pre/postinc handling */ + Node **incqueue; + size_t nqueue; + + /* break/continue handling */ + Node **loopstep; + size_t nloopstep; + Node **loopexit; + size_t nloopexit; + + /* location handling */ + Node **blobs; + size_t nblobs; + Htab *globls; + + Htab *stkoff; + Htab *envoff; + size_t stksz; + + Node **args; + size_t nargs; }; static int envcmp(const void *pa, const void *pb); @@ -83,309 +83,309 @@ Node *abortoob; static void append(Simp *s, Node *n) { - lappend(&s->stmts, &s->nstmts, n); + lappend(&s->stmts, &s->nstmts, n); } static int ispure(Node *n) { - return opispure[exprop(n)]; + return opispure[exprop(n)]; } size_t alignto(size_t sz, Type *t) { - size_t a; - size_t i; - - t = tybase(t); - a = 0; - switch (t->type) { - case Tyarray: - a = alignto(1, t->sub[0]); - case Tytuple: - for (i = 0; i < t->nsub; i++) - a = max(alignto(1, t->sub[i]), a); - break; - case Tystruct: - for (i = 0; i < t->nmemb; i++) - a = max(alignto(1, decltype(t->sdecls[i])), a); - break; - default: - a = tysize(t); - break; - } - - return align(sz, min(a, Ptrsz)); + size_t a; + size_t i; + + t = tybase(t); + a = 0; + switch (t->type) { + case Tyarray: + a = alignto(1, t->sub[0]); + case Tytuple: + for (i = 0; i < t->nsub; i++) + a = max(alignto(1, t->sub[i]), a); + break; + case Tystruct: + for (i = 0; i < t->nmemb; i++) + a = max(alignto(1, decltype(t->sdecls[i])), a); + break; + default: + a = tysize(t); + break; + } + + return align(sz, min(a, Ptrsz)); } static Type *base(Type *t) { - assert(t->nsub == 1); - return t->sub[0]; + assert(t->nsub == 1); + return t->sub[0]; } static Node *add(Node *a, Node *b) { - Node *n; + Node *n; - assert(size(a) == size(b)); - n = mkexpr(a->loc, Oadd, a, b, NULL); - n->expr.type = a->expr.type; - return n; + assert(size(a) == size(b)); + n = mkexpr(a->loc, Oadd, a, b, NULL); + n->expr.type = a->expr.type; + return n; } static Node *addk(Node *n, uvlong v) { - Node *k; + Node *k; - k = mkintlit(n->loc, v); - k->expr.type = exprtype(n); - return add(n, k); + k = mkintlit(n->loc, v); + k->expr.type = exprtype(n); + return add(n, k); } static Node *sub(Node *a, Node *b) { - Node *n; + Node *n; - n = mkexpr(a->loc, Osub, a, b, NULL); - n->expr.type = a->expr.type; - return n; + n = mkexpr(a->loc, Osub, a, b, NULL); + n->expr.type = a->expr.type; + return n; } static Node *subk(Node *n, uvlong v) { - Node *k; + Node *k; - k = mkintlit(n->loc, v); - k->expr.type = exprtype(n); - return sub(n, k); + k = mkintlit(n->loc, v); + k->expr.type = exprtype(n); + return sub(n, k); } static Node *mul(Node *a, Node *b) { - Node *n; + Node *n; - n = mkexpr(a->loc, Omul, a, b, NULL); - n->expr.type = a->expr.type; - return n; + n = mkexpr(a->loc, Omul, a, b, NULL); + n->expr.type = a->expr.type; + return n; } static int addressable(Simp *s, Node *a) { - if (a->type == Ndecl || (a->type == Nexpr && exprop(a) == Ovar)) - return hthas(s->envoff, a) || hthas(s->stkoff, a) || hthas(s->globls, a); - else - return stacknode(a); + if (a->type == Ndecl || (a->type == Nexpr && exprop(a) == Ovar)) + return hthas(s->envoff, a) || hthas(s->stkoff, a) || hthas(s->globls, a); + else + return stacknode(a); } int stacknode(Node *n) { - if (n->type == Nexpr) - return isstacktype(n->expr.type); - else - return isstacktype(n->decl.type); + if (n->type == Nexpr) + return isstacktype(n->expr.type); + else + return isstacktype(n->decl.type); } int floatnode(Node *n) { - if (n->type == Nexpr) - return istyfloat(n->expr.type); - else - return istyfloat(n->decl.type); + if (n->type == Nexpr) + return istyfloat(n->expr.type); + else + return istyfloat(n->decl.type); } static void forcelocal(Simp *s, Node *n) { - assert(n->type == Ndecl || (n->type == Nexpr && exprop(n) == Ovar)); - s->stksz += size(n); - s->stksz = align(s->stksz, min(size(n), Ptrsz)); - if (debugopt['i']) { - dump(n, stdout); - printf("declared at %zd, size = %zd\n", s->stksz, size(n)); - } - htput(s->stkoff, n, itop(s->stksz)); + assert(n->type == Ndecl || (n->type == Nexpr && exprop(n) == Ovar)); + s->stksz += size(n); + s->stksz = align(s->stksz, min(size(n), Ptrsz)); + if (debugopt['i']) { + dump(n, stdout); + printf("declared at %zd, size = %zd\n", s->stksz, size(n)); + } + htput(s->stkoff, n, itop(s->stksz)); } static void declarelocal(Simp *s, Node *n) { - if (stacknode(n)) - forcelocal(s, n); + if (stacknode(n)) + forcelocal(s, n); } /* takes the address of a node, possibly converting it to * a pointer to the base type 'bt' */ static Node *addr(Simp *s, Node *a, Type *bt) { - Node *n; + Node *n; - n = mkexpr(a->loc, Oaddr, a, NULL); - if (!addressable(s, a)) - forcelocal(s, a); - if (!bt) - n->expr.type = mktyptr(a->loc, a->expr.type); - else - n->expr.type = mktyptr(a->loc, bt); - return n; + n = mkexpr(a->loc, Oaddr, a, NULL); + if (!addressable(s, a)) + forcelocal(s, a); + if (!bt) + n->expr.type = mktyptr(a->loc, a->expr.type); + else + n->expr.type = mktyptr(a->loc, bt); + return n; } static Node *load(Node *a) { - Node *n; + Node *n; - assert(a->expr.type->type == Typtr); - n = mkexpr(a->loc, Oderef, a, NULL); - n->expr.type = base(a->expr.type); - return n; + assert(a->expr.type->type == Typtr); + n = mkexpr(a->loc, Oderef, a, NULL); + n->expr.type = base(a->expr.type); + return n; } static Node *deref(Node *a, Type *t) { - Node *n; + Node *n; - assert(a->expr.type->type == Typtr); - n = mkexpr(a->loc, Oderef, a, NULL); - if (t) - n->expr.type = t; - else - n->expr.type = base(a->expr.type); - return n; + assert(a->expr.type->type == Typtr); + n = mkexpr(a->loc, Oderef, a, NULL); + if (t) + n->expr.type = t; + else + n->expr.type = base(a->expr.type); + return n; } static Node *set(Node *a, Node *b) { - Node *n; + Node *n; - assert(a != NULL && b != NULL); - assert(exprop(a) == Ovar || exprop(a) == Oderef); - n = mkexpr(a->loc, Oset, a, b, NULL); - n->expr.type = exprtype(a); - return n; + assert(a != NULL && b != NULL); + assert(exprop(a) == Ovar || exprop(a) == Oderef); + n = mkexpr(a->loc, Oset, a, b, NULL); + n->expr.type = exprtype(a); + return n; } static void def(Simp *s, Node *var) { - Node *d; + Node *d; - d = mkexpr(var->loc, Odef, var, NULL); - d->expr.type = mktype(var->loc, Tyvoid); - append(s, d); + d = mkexpr(var->loc, Odef, var, NULL); + d->expr.type = mktype(var->loc, Tyvoid); + append(s, d); } static Node *disp(Srcloc loc, uint v) { - Node *n; + Node *n; - n = mkintlit(loc, v); - n->expr.type = tyintptr; - return n; + n = mkintlit(loc, v); + n->expr.type = tyintptr; + return n; } static Node *word(Srcloc loc, uint v) { - Node *n; + Node *n; - n = mkintlit(loc, v); - n->expr.type = tyword; - return n; + n = mkintlit(loc, v); + n->expr.type = tyword; + return n; } static Node *temp(Simp *simp, Node *e) { - Node *t, *dcl; + Node *t, *dcl; - assert(e->type == Nexpr); - t = gentemp(e->loc, e->expr.type, &dcl); - if (stacknode(e)) - declarelocal(simp, dcl); - return t; + assert(e->type == Nexpr); + t = gentemp(e->loc, e->expr.type, &dcl); + if (stacknode(e)) + declarelocal(simp, dcl); + return t; } static void jmp(Simp *s, Node *lbl) { - append(s, mkexpr(lbl->loc, Ojmp, lbl, NULL)); + append(s, mkexpr(lbl->loc, Ojmp, lbl, NULL)); } static void cjmp(Simp *s, Node *cond, Node *iftrue, Node *iffalse) { - Node *jmp; + Node *jmp; - jmp = mkexpr(cond->loc, Ocjmp, cond, iftrue, iffalse, NULL); - append(s, jmp); + jmp = mkexpr(cond->loc, Ocjmp, cond, iftrue, iffalse, NULL); + append(s, jmp); } static Node *slicelen(Simp *s, Node *sl) { - /* *(&sl + sizeof(size_t)) */ - return load(addk(addr(s, sl, tyintptr), Ptrsz)); + /* *(&sl + sizeof(size_t)) */ + return load(addk(addr(s, sl, tyintptr), Ptrsz)); } Node *loadvar(Simp *s, Node *n, Node *dst) { - Node *p, *f, *r; + Node *p, *f, *r; - if (isconstfn(n)) { - if (dst) - r = dst; - else - r = temp(s, n); - f = getcode(s, n); - p = addr(s, r, exprtype(n)); - assignat(s, p, Ptrsz, f); - } else { - r = n; - } - return r; + if (isconstfn(n)) { + if (dst) + r = dst; + else + r = temp(s, n); + f = getcode(s, n); + p = addr(s, r, exprtype(n)); + assignat(s, p, Ptrsz, f); + } else { + r = n; + } + return r; } static Node *seqlen(Simp *s, Node *n, Type *ty) { - Node *t, *r; + Node *t, *r; - if (exprtype(n)->type == Tyslice) { - t = slicelen(s, n); - r = simpcast(s, t, ty); - } else if (exprtype(n)->type == Tyarray) { - t = exprtype(n)->asize; - r = simpcast(s, t, ty); - } else { - r = NULL; - } - return r; + if (exprtype(n)->type == Tyslice) { + t = slicelen(s, n); + r = simpcast(s, t, ty); + } else if (exprtype(n)->type == Tyarray) { + t = exprtype(n)->asize; + r = simpcast(s, t, ty); + } else { + r = NULL; + } + return r; } /* if foo; bar; else baz;; * => cjmp (foo) :bar :baz */ static void simpif(Simp *s, Node *n, Node *exit) { - Node *l1, *l2, *l3; - Node *iftrue, *iffalse; - - l1 = genlbl(n->loc); - l2 = genlbl(n->loc); - if (exit) - l3 = exit; - else - l3 = genlbl(n->loc); - - iftrue = n->ifstmt.iftrue; - iffalse = n->ifstmt.iffalse; - - simpcond(s, n->ifstmt.cond, l1, l2); - simp(s, l1); - simp(s, iftrue); - jmp(s, l3); - simp(s, l2); - /* because lots of bunched up end labels are ugly, - * coalesce them by handling 'elif'-like constructs - * separately */ - if (iffalse && iffalse->type == Nifstmt) { - simpif(s, iffalse, exit); - } else { - simp(s, iffalse); - jmp(s, l3); - } - - if (!exit) - simp(s, l3); + Node *l1, *l2, *l3; + Node *iftrue, *iffalse; + + l1 = genlbl(n->loc); + l2 = genlbl(n->loc); + if (exit) + l3 = exit; + else + l3 = genlbl(n->loc); + + iftrue = n->ifstmt.iftrue; + iffalse = n->ifstmt.iffalse; + + simpcond(s, n->ifstmt.cond, l1, l2); + simp(s, l1); + simp(s, iftrue); + jmp(s, l3); + simp(s, l2); + /* because lots of bunched up end labels are ugly, + * coalesce them by handling 'elif'-like constructs + * separately */ + if (iffalse && iffalse->type == Nifstmt) { + simpif(s, iffalse, exit); + } else { + simp(s, iffalse); + jmp(s, l3); + } + + if (!exit) + simp(s, l3); } /* init; while cond; body;; @@ -401,31 +401,31 @@ static void simpif(Simp *s, Node *n, Node *exit) */ static void simploop(Simp *s, Node *n) { - Node *lbody; - Node *lend; - Node *lcond; - Node *lstep; + Node *lbody; + Node *lend; + Node *lcond; + Node *lstep; - lbody = genlbl(n->loc); - lcond = genlbl(n->loc); - lstep = genlbl(n->loc); - lend = genlbl(n->loc); + lbody = genlbl(n->loc); + lcond = genlbl(n->loc); + lstep = genlbl(n->loc); + lend = genlbl(n->loc); - lappend(&s->loopstep, &s->nloopstep, lstep); - lappend(&s->loopexit, &s->nloopexit, lend); + lappend(&s->loopstep, &s->nloopstep, lstep); + lappend(&s->loopexit, &s->nloopexit, lend); - simp(s, n->loopstmt.init); /* init */ - jmp(s, lcond); /* goto test */ - simp(s, lbody); /* body lbl */ - simp(s, n->loopstmt.body); /* body */ - simp(s, lstep); /* test lbl */ - simp(s, n->loopstmt.step); /* step */ - simp(s, lcond); /* test lbl */ - simpcond(s, n->loopstmt.cond, lbody, lend); /* repeat? */ - simp(s, lend); /* exit */ + simp(s, n->loopstmt.init); /* init */ + jmp(s, lcond); /* goto test */ + simp(s, lbody); /* body lbl */ + simp(s, n->loopstmt.body); /* body */ + simp(s, lstep); /* test lbl */ + simp(s, n->loopstmt.step); /* step */ + simp(s, lcond); /* test lbl */ + simpcond(s, n->loopstmt.cond, lbody, lend); /* repeat? */ + simp(s, lend); /* exit */ - s->nloopstep--; - s->nloopexit--; + s->nloopstep--; + s->nloopexit--; } /* pat; seq; @@ -448,554 +448,554 @@ static void simploop(Simp *s, Node *n) */ static void simpiter(Simp *s, Node *n) { - Node *lbody, *lload, *lstep, *lcond, *lmatch, *lend; - Node *idx, *len, *dcl, *seq, *val, *done; - Node **cap, **out; - size_t i, ncap, nout; - Node *zero; - - lbody = genlbl(n->loc); - lload = genlbl(n->loc); - lstep = genlbl(n->loc); - lcond = genlbl(n->loc); - lmatch = genlbl(n->loc); - lend = genlbl(n->loc); - - lappend(&s->loopstep, &s->nloopstep, lstep); - lappend(&s->loopexit, &s->nloopexit, lend); - - zero = mkintlit(n->loc, 0); - zero->expr.type = tyintptr; - - seq = rval(s, n->iterstmt.seq, NULL); - idx = gentemp(n->loc, tyintptr, &dcl); - declarelocal(s, dcl); - - /* setup */ - append(s, assign(s, idx, zero)); - jmp(s, lcond); - simp(s, lbody); - - /* body */ - simp(s, n->iterstmt.body); - /* step */ - simp(s, lstep); - simp(s, assign(s, idx, addk(idx, 1))); - /* condition */ - simp(s, lcond); - len = seqlen(s, seq, tyintptr); - done = mkexpr(n->loc, Olt, idx, len, NULL); - cjmp(s, done, lmatch, lend); - simp(s, lmatch); - val = load(idxaddr(s, seq, idx)); - - /* pattern match */ - out = NULL; - nout = 0; - cap = NULL; - ncap = 0; - genonematch(n->iterstmt.elt, val, lload, lstep, &out, &nout, &cap, &ncap); - for (i = 0; i < nout; i++) - simp(s, out[i]); - simp(s, lload); - for (i = 0; i < ncap; i++) - simp(s, cap[i]); - jmp(s, lbody); - simp(s, lend); - - s->nloopstep--; - s->nloopexit--; + Node *lbody, *lload, *lstep, *lcond, *lmatch, *lend; + Node *idx, *len, *dcl, *seq, *val, *done; + Node **cap, **out; + size_t i, ncap, nout; + Node *zero; + + lbody = genlbl(n->loc); + lload = genlbl(n->loc); + lstep = genlbl(n->loc); + lcond = genlbl(n->loc); + lmatch = genlbl(n->loc); + lend = genlbl(n->loc); + + lappend(&s->loopstep, &s->nloopstep, lstep); + lappend(&s->loopexit, &s->nloopexit, lend); + + zero = mkintlit(n->loc, 0); + zero->expr.type = tyintptr; + + seq = rval(s, n->iterstmt.seq, NULL); + idx = gentemp(n->loc, tyintptr, &dcl); + declarelocal(s, dcl); + + /* setup */ + append(s, assign(s, idx, zero)); + jmp(s, lcond); + simp(s, lbody); + + /* body */ + simp(s, n->iterstmt.body); + /* step */ + simp(s, lstep); + simp(s, assign(s, idx, addk(idx, 1))); + /* condition */ + simp(s, lcond); + len = seqlen(s, seq, tyintptr); + done = mkexpr(n->loc, Olt, idx, len, NULL); + cjmp(s, done, lmatch, lend); + simp(s, lmatch); + val = load(idxaddr(s, seq, idx)); + + /* pattern match */ + out = NULL; + nout = 0; + cap = NULL; + ncap = 0; + genonematch(n->iterstmt.elt, val, lload, lstep, &out, &nout, &cap, &ncap); + for (i = 0; i < nout; i++) + simp(s, out[i]); + simp(s, lload); + for (i = 0; i < ncap; i++) + simp(s, cap[i]); + jmp(s, lbody); + simp(s, lend); + + s->nloopstep--; + s->nloopexit--; } static Node *uconid(Simp *s, Node *n) { - Ucon *uc; + Ucon *uc; - n = rval(s, n, NULL); - if (exprop(n) != Oucon) - return load(addr(s, n, mktype(n->loc, Tyuint))); + n = rval(s, n, NULL); + if (exprop(n) != Oucon) + return load(addr(s, n, mktype(n->loc, Tyuint))); - uc = finducon(exprtype(n), n->expr.args[0]); - return word(uc->loc, uc->id); + uc = finducon(exprtype(n), n->expr.args[0]); + return word(uc->loc, uc->id); } static void simpblk(Simp *s, Node *n) { - size_t i; + size_t i; - for (i = 0; i < n->block.nstmts; i++) { - n->block.stmts[i] = fold(n->block.stmts[i], 0); - simp(s, n->block.stmts[i]); - } + for (i = 0; i < n->block.nstmts; i++) { + n->block.stmts[i] = fold(n->block.stmts[i], 0); + simp(s, n->block.stmts[i]); + } } static Node *geninitdecl(Node *init, Type *ty, Node **dcl) { - Node *n, *d, *r; - char lbl[128]; + Node *n, *d, *r; + char lbl[128]; - n = mkname(init->loc, genlblstr(lbl, 128, "")); - d = mkdecl(init->loc, n, ty); - r = mkexpr(init->loc, Ovar, n, NULL); + n = mkname(init->loc, genlblstr(lbl, 128, "")); + d = mkdecl(init->loc, n, ty); + r = mkexpr(init->loc, Ovar, n, NULL); - d->decl.init = init; - d->decl.type = ty; - d->decl.isconst = 1; - d->decl.isglobl = 1; + d->decl.init = init; + d->decl.type = ty; + d->decl.isconst = 1; + d->decl.isglobl = 1; - r->expr.did = d->decl.did; - r->expr.type = ty; - r->expr.isconst = 1; - if (dcl) - *dcl = d; - return r; + r->expr.did = d->decl.did; + r->expr.type = ty; + r->expr.isconst = 1; + if (dcl) + *dcl = d; + return r; } static Node *simpcode(Simp *s, Node *fn) { - Node *r, *d; + Node *r, *d; - r = geninitdecl(fn, codetype(exprtype(fn)), &d); - htput(s->globls, d, asmname(d)); - lappend(&file->file.stmts, &file->file.nstmts, d); - return r; + r = geninitdecl(fn, codetype(exprtype(fn)), &d); + htput(s->globls, d, asmname(d)); + lappend(&file->file.stmts, &file->file.nstmts, d); + return r; } static Node *simpblob(Simp *s, Node *blob) { - Node *r, *d; + Node *r, *d; - r = geninitdecl(blob, exprtype(blob), &d); - htput(s->globls, d, asmname(d)); - lappend(&s->blobs, &s->nblobs, d); - return r; + r = geninitdecl(blob, exprtype(blob), &d); + htput(s->globls, d, asmname(d)); + lappend(&s->blobs, &s->nblobs, d); + return r; } static Node *ptrsized(Simp *s, Node *v) { - if (size(v) == Ptrsz) - return v; - else if (size(v) < Ptrsz) - v = mkexpr(v->loc, Ozwiden, v, NULL); - else if (size(v) > Ptrsz) - v = mkexpr(v->loc, Otrunc, v, NULL); - v->expr.type = tyintptr; - return v; + if (size(v) == Ptrsz) + return v; + else if (size(v) < Ptrsz) + v = mkexpr(v->loc, Ozwiden, v, NULL); + else if (size(v) > Ptrsz) + v = mkexpr(v->loc, Otrunc, v, NULL); + v->expr.type = tyintptr; + return v; } static Node *membaddr(Simp *s, Node *n) { - Node *t, *u, *r; - Node **args; - Type *ty; + Node *t, *u, *r; + Node **args; + Type *ty; - args = n->expr.args; - ty = tybase(exprtype(args[0])); - if (ty->type == Typtr) { - t = lval(s, args[0]); - } else { - t = addr(s, lval(s, args[0]), exprtype(n)); - } - u = disp(n->loc, offset(args[0], args[1])); - r = add(t, u); - r->expr.type = mktyptr(n->loc, n->expr.type); - return r; + args = n->expr.args; + ty = tybase(exprtype(args[0])); + if (ty->type == Typtr) { + t = lval(s, args[0]); + } else { + t = addr(s, lval(s, args[0]), exprtype(n)); + } + u = disp(n->loc, offset(args[0], args[1])); + r = add(t, u); + r->expr.type = mktyptr(n->loc, n->expr.type); + return r; } static void checkidx(Simp *s, Node *len, Node *idx) { - Node *cmp, *die; - Node *ok, *fail; + Node *cmp, *die; + Node *ok, *fail; - if (!len) - return; - /* create expressions */ - cmp = mkexpr(idx->loc, Olt, ptrsized(s, idx), ptrsized(s, len), NULL); - cmp->expr.type = mktype(len->loc, Tybool); - ok = genlbl(len->loc); - fail = genlbl(len->loc); - die = mkexpr(idx->loc, Ocall, abortoob, NULL); - die->expr.type = mktype(len->loc, Tyvoid); + if (!len) + return; + /* create expressions */ + cmp = mkexpr(idx->loc, Olt, ptrsized(s, idx), ptrsized(s, len), NULL); + cmp->expr.type = mktype(len->loc, Tybool); + ok = genlbl(len->loc); + fail = genlbl(len->loc); + die = mkexpr(idx->loc, Ocall, abortoob, NULL); + die->expr.type = mktype(len->loc, Tyvoid); - /* insert them */ - cjmp(s, cmp, ok, fail); - append(s, fail); - append(s, die); - append(s, ok); + /* insert them */ + cjmp(s, cmp, ok, fail); + append(s, fail); + append(s, die); + append(s, ok); } static Node *idxaddr(Simp *s, Node *seq, Node *idx) { - Node *a, *t, *u, *v, *w; /* temps */ - Node *r; /* result */ - Type *ty; - size_t sz; - - a = rval(s, seq, NULL); - ty = exprtype(seq)->sub[0]; - if (exprtype(seq)->type == Tyarray) { - t = addr(s, a, ty); - w = exprtype(a)->asize; - } else if (seq->expr.type->type == Tyslice) { - t = load(addr(s, a, mktyptr(seq->loc, ty))); - w = slicelen(s, a); - } else { - die("Can't index type %s\n", tystr(seq->expr.type)); - } - assert(t->expr.type->type == Typtr); - u = rval(s, idx, NULL); - u = ptrsized(s, u); - checkidx(s, w, u); - sz = tysize(ty); - v = mul(u, disp(seq->loc, sz)); - r = add(t, v); - return r; + Node *a, *t, *u, *v, *w; /* temps */ + Node *r; /* result */ + Type *ty; + size_t sz; + + a = rval(s, seq, NULL); + ty = exprtype(seq)->sub[0]; + if (exprtype(seq)->type == Tyarray) { + t = addr(s, a, ty); + w = exprtype(a)->asize; + } else if (seq->expr.type->type == Tyslice) { + t = load(addr(s, a, mktyptr(seq->loc, ty))); + w = slicelen(s, a); + } else { + die("Can't index type %s\n", tystr(seq->expr.type)); + } + assert(t->expr.type->type == Typtr); + u = rval(s, idx, NULL); + u = ptrsized(s, u); + checkidx(s, w, u); + sz = tysize(ty); + v = mul(u, disp(seq->loc, sz)); + r = add(t, v); + return r; } static Node *slicebase(Simp *s, Node *n, Node *off) { - Node *u, *v; - Type *ty; - int sz; - - u = NULL; - ty = tybase(exprtype(n)); - switch (ty->type) { - case Typtr: u = n; break; - case Tyarray: u = addr(s, n, base(exprtype(n))); break; - case Tyslice: u = load(addr(s, n, mktyptr(n->loc, base(exprtype(n))))); break; - default: die("Unslicable type %s", tystr(n->expr.type)); - } - /* safe: all types we allow here have a sub[0] that we want to grab */ - if (off) { - off = ptrsized(s, rval(s, off, NULL)); - sz = tysize(n->expr.type->sub[0]); - v = mul(off, disp(n->loc, sz)); - return add(u, v); - } else { - return u; - } + Node *u, *v; + Type *ty; + int sz; + + u = NULL; + ty = tybase(exprtype(n)); + switch (ty->type) { + case Typtr: u = n; break; + case Tyarray: u = addr(s, n, base(exprtype(n))); break; + case Tyslice: u = load(addr(s, n, mktyptr(n->loc, base(exprtype(n))))); break; + default: die("Unslicable type %s", tystr(n->expr.type)); + } + /* safe: all types we allow here have a sub[0] that we want to grab */ + if (off) { + off = ptrsized(s, rval(s, off, NULL)); + sz = tysize(n->expr.type->sub[0]); + v = mul(off, disp(n->loc, sz)); + return add(u, v); + } else { + return u; + } } static Node *loadidx(Simp *s, Node *arr, Node *idx) { - Node *v, *a; + Node *v, *a; - a = rval(s, arr, NULL); - lappend(&s->idxctx, &s->nidxctx, a); - v = deref(idxaddr(s, a, idx), NULL); - lpop(&s->idxctx, &s->nidxctx); - return v; + a = rval(s, arr, NULL); + lappend(&s->idxctx, &s->nidxctx, a); + v = deref(idxaddr(s, a, idx), NULL); + lpop(&s->idxctx, &s->nidxctx); + return v; } static Node *lval(Simp *s, Node *n) { - Node *r; - Node **args; - - args = n->expr.args; - switch (exprop(n)) { - case Ovar: r = loadvar(s, n, NULL); break; - case Oidx: r = loadidx(s, args[0], args[1]); break; - case Oderef: r = deref(rval(s, args[0], NULL), NULL); break; - case Omemb: r = rval(s, n, NULL); break; - case Ostruct: r = rval(s, n, NULL); break; - case Oucon: r = rval(s, n, NULL); break; - case Oarr: r = rval(s, n, NULL); break; - case Ogap: r = temp(s, n); break; - - /* not actually expressible as lvalues in syntax, but we generate them */ - case Oudata: r = rval(s, n, NULL); break; - case Outag: r = rval(s, n, NULL); break; - case Otupget: r = rval(s, n, NULL); break; - default: - fatal(n, "%s cannot be an lvalue", opstr[exprop(n)]); - break; - } - return r; + Node *r; + Node **args; + + args = n->expr.args; + switch (exprop(n)) { + case Ovar: r = loadvar(s, n, NULL); break; + case Oidx: r = loadidx(s, args[0], args[1]); break; + case Oderef: r = deref(rval(s, args[0], NULL), NULL); break; + case Omemb: r = rval(s, n, NULL); break; + case Ostruct: r = rval(s, n, NULL); break; + case Oucon: r = rval(s, n, NULL); break; + case Oarr: r = rval(s, n, NULL); break; + case Ogap: r = temp(s, n); break; + + /* not actually expressible as lvalues in syntax, but we generate them */ + case Oudata: r = rval(s, n, NULL); break; + case Outag: r = rval(s, n, NULL); break; + case Otupget: r = rval(s, n, NULL); break; + default: + fatal(n, "%s cannot be an lvalue", opstr[exprop(n)]); + break; + } + return r; } static void simpcond(Simp *s, Node *n, Node *ltrue, Node *lfalse) { - Node **args; - Node *v, *lnext; - - args = n->expr.args; - switch (exprop(n)) { - case Oland: - lnext = genlbl(n->loc); - simpcond(s, args[0], lnext, lfalse); - append(s, lnext); - simpcond(s, args[1], ltrue, lfalse); - break; - case Olor: - lnext = genlbl(n->loc); - simpcond(s, args[0], ltrue, lnext); - append(s, lnext); - simpcond(s, args[1], ltrue, lfalse); - break; - case Olnot: - simpcond(s, args[0], lfalse, ltrue); - break; - default: - v = rval(s, n, NULL); - cjmp(s, v, ltrue, lfalse); - break; - } + Node **args; + Node *v, *lnext; + + args = n->expr.args; + switch (exprop(n)) { + case Oland: + lnext = genlbl(n->loc); + simpcond(s, args[0], lnext, lfalse); + append(s, lnext); + simpcond(s, args[1], ltrue, lfalse); + break; + case Olor: + lnext = genlbl(n->loc); + simpcond(s, args[0], ltrue, lnext); + append(s, lnext); + simpcond(s, args[1], ltrue, lfalse); + break; + case Olnot: + simpcond(s, args[0], lfalse, ltrue); + break; + default: + v = rval(s, n, NULL); + cjmp(s, v, ltrue, lfalse); + break; + } } static Node *intconvert(Simp *s, Node *from, Type *to, int issigned) { - Node *r; - size_t fromsz, tosz; + Node *r; + size_t fromsz, tosz; - fromsz = size(from); - tosz = tysize(to); - r = rval(s, from, NULL); - if (fromsz > tosz) { - r = mkexpr(from->loc, Otrunc, r, NULL); - } else if (tosz > fromsz) { - if (issigned) - r = mkexpr(from->loc, Oswiden, r, NULL); - else - r = mkexpr(from->loc, Ozwiden, r, NULL); - } - r->expr.type = to; - return r; + fromsz = size(from); + tosz = tysize(to); + r = rval(s, from, NULL); + if (fromsz > tosz) { + r = mkexpr(from->loc, Otrunc, r, NULL); + } else if (tosz > fromsz) { + if (issigned) + r = mkexpr(from->loc, Oswiden, r, NULL); + else + r = mkexpr(from->loc, Ozwiden, r, NULL); + } + r->expr.type = to; + return r; } static Node *simpcast(Simp *s, Node *val, Type *to) { - Node *r; - Type *t; - - r = NULL; - /* do the type conversion */ - switch (tybase(to)->type) { - case Tybool: - case Tyint8: case Tyint16: case Tyint32: case Tyint64: - case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64: - case Tyint: case Tyuint: case Tychar: case Tybyte: - case Typtr: - t = tybase(exprtype(val)); - switch (t->type) { - /* ptr -> slice conversion is disallowed */ - case Tyslice: - /* FIXME: we should only allow casting to pointers. */ - if (tysize(to) != Ptrsz) - fatal(val, "bad cast from %s to %s", tystr(exprtype(val)), tystr(to)); - val = rval(s, val, NULL); - r = slicebase(s, val, NULL); - break; - case Tyfunc: - if (to->type != Typtr) - fatal(val, "bad cast from %s to %s", tystr(exprtype(val)), tystr(to)); - r = getcode(s, val); - break; - /* signed conversions */ - case Tyint8: case Tyint16: case Tyint32: case Tyint64: - case Tyint: - r = intconvert(s, val, to, 1); - break; - /* unsigned conversions */ - case Tybool: - case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64: - case Tyuint: case Tychar: case Tybyte: - case Typtr: - r = intconvert(s, val, to, 0); - break; - case Tyflt32: case Tyflt64: - if (tybase(to)->type == Typtr) - fatal(val, "bad cast from %s to %s", - tystr(exprtype(val)), tystr(to)); - r = mkexpr(val->loc, Oflt2int, rval(s, val, NULL), NULL); - r->expr.type = to; - break; - default: - fatal(val, "bad cast from %s to %s", - tystr(exprtype(val)), tystr(to)); - } - break; - case Tyflt32: case Tyflt64: - t = tybase(exprtype(val)); - switch (t->type) { - case Tyint8: case Tyint16: case Tyint32: case Tyint64: - case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64: - case Tyint: case Tyuint: case Tychar: case Tybyte: - r = mkexpr(val->loc, Oint2flt, rval(s, val, NULL), NULL); - r->expr.type = to; - break; - case Tyflt32: case Tyflt64: - r = mkexpr(val->loc, Oflt2flt, rval(s, val, NULL), NULL); - r->expr.type = to; - break; - default: - fatal(val, "bad cast from %s to %s", - tystr(exprtype(val)), tystr(to)); - break; - } - break; - /* no other destination types are handled as things stand */ - default: - fatal(val, "bad cast from %s to %s", - tystr(exprtype(val)), tystr(to)); - } - return r; + Node *r; + Type *t; + + r = NULL; + /* do the type conversion */ + switch (tybase(to)->type) { + case Tybool: + case Tyint8: case Tyint16: case Tyint32: case Tyint64: + case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64: + case Tyint: case Tyuint: case Tychar: case Tybyte: + case Typtr: + t = tybase(exprtype(val)); + switch (t->type) { + /* ptr -> slice conversion is disallowed */ + case Tyslice: + /* FIXME: we should only allow casting to pointers. */ + if (tysize(to) != Ptrsz) + fatal(val, "bad cast from %s to %s", tystr(exprtype(val)), tystr(to)); + val = rval(s, val, NULL); + r = slicebase(s, val, NULL); + break; + case Tyfunc: + if (to->type != Typtr) + fatal(val, "bad cast from %s to %s", tystr(exprtype(val)), tystr(to)); + r = getcode(s, val); + break; + /* signed conversions */ + case Tyint8: case Tyint16: case Tyint32: case Tyint64: + case Tyint: + r = intconvert(s, val, to, 1); + break; + /* unsigned conversions */ + case Tybool: + case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64: + case Tyuint: case Tychar: case Tybyte: + case Typtr: + r = intconvert(s, val, to, 0); + break; + case Tyflt32: case Tyflt64: + if (tybase(to)->type == Typtr) + fatal(val, "bad cast from %s to %s", + tystr(exprtype(val)), tystr(to)); + r = mkexpr(val->loc, Oflt2int, rval(s, val, NULL), NULL); + r->expr.type = to; + break; + default: + fatal(val, "bad cast from %s to %s", + tystr(exprtype(val)), tystr(to)); + } + break; + case Tyflt32: case Tyflt64: + t = tybase(exprtype(val)); + switch (t->type) { + case Tyint8: case Tyint16: case Tyint32: case Tyint64: + case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64: + case Tyint: case Tyuint: case Tychar: case Tybyte: + r = mkexpr(val->loc, Oint2flt, rval(s, val, NULL), NULL); + r->expr.type = to; + break; + case Tyflt32: case Tyflt64: + r = mkexpr(val->loc, Oflt2flt, rval(s, val, NULL), NULL); + r->expr.type = to; + break; + default: + fatal(val, "bad cast from %s to %s", + tystr(exprtype(val)), tystr(to)); + break; + } + break; + /* no other destination types are handled as things stand */ + default: + fatal(val, "bad cast from %s to %s", + tystr(exprtype(val)), tystr(to)); + } + return r; } /* Simplifies taking a slice of an array, pointer, * or other slice down to primitive pointer operations */ static Node *simpslice(Simp *s, Node *n, Node *dst) { - Node *t; - Node *start, *end; - Node *seq, *base, *sz, *len; - Node *stbase, *stlen; - - if (dst) - t = dst; - else - t = temp(s, n); - seq = rval(s, n->expr.args[0], NULL); - if (tybase(exprtype(seq))->type != Typtr) - lappend(&s->idxctx, &s->nidxctx, seq); - /* *(&slice) = (void*)base + off*sz */ - base = slicebase(s, seq, n->expr.args[1]); - start = ptrsized(s, rval(s, n->expr.args[1], NULL)); - end = ptrsized(s, rval(s, n->expr.args[2], NULL)); - len = sub(end, start); - /* we can be storing through a pointer, in the case - * of '*foo = bar'. */ - if (tybase(exprtype(t))->type == Typtr) { - stbase = set(simpcast(s, t, mktyptr(t->loc, tyintptr)), base); - sz = addk(simpcast(s, t, mktyptr(t->loc, tyintptr)), Ptrsz); - } else { - stbase = set(deref(addr(s, t, tyintptr), NULL), base); - sz = addk(addr(s, t, tyintptr), Ptrsz); - } - if (tybase(exprtype(seq))->type != Typtr) - lpop(&s->idxctx, &s->nidxctx); - /* *(&slice + ptrsz) = len */ - stlen = set(deref(sz, NULL), len); - append(s, stbase); - append(s, stlen); - return t; + Node *t; + Node *start, *end; + Node *seq, *base, *sz, *len; + Node *stbase, *stlen; + + if (dst) + t = dst; + else + t = temp(s, n); + seq = rval(s, n->expr.args[0], NULL); + if (tybase(exprtype(seq))->type != Typtr) + lappend(&s->idxctx, &s->nidxctx, seq); + /* *(&slice) = (void*)base + off*sz */ + base = slicebase(s, seq, n->expr.args[1]); + start = ptrsized(s, rval(s, n->expr.args[1], NULL)); + end = ptrsized(s, rval(s, n->expr.args[2], NULL)); + len = sub(end, start); + /* we can be storing through a pointer, in the case + * of '*foo = bar'. */ + if (tybase(exprtype(t))->type == Typtr) { + stbase = set(simpcast(s, t, mktyptr(t->loc, tyintptr)), base); + sz = addk(simpcast(s, t, mktyptr(t->loc, tyintptr)), Ptrsz); + } else { + stbase = set(deref(addr(s, t, tyintptr), NULL), base); + sz = addk(addr(s, t, tyintptr), Ptrsz); + } + if (tybase(exprtype(seq))->type != Typtr) + lpop(&s->idxctx, &s->nidxctx); + /* *(&slice + ptrsz) = len */ + stlen = set(deref(sz, NULL), len); + append(s, stbase); + append(s, stlen); + return t; } static Node *visit(Simp *s, Node *n) { - size_t i; - Node *r; - - for (i = 0; i < n->expr.nargs; i++) - n->expr.args[i] = rval(s, n->expr.args[i], NULL); - if (ispure(n)) { - r = n; - } else { - if (exprtype(n)->type == Tyvoid) { - r = NULL; - append(s, n); - } else { - r = temp(s, n); - append(s, set(r, n)); - } - } - return r; + size_t i; + Node *r; + + for (i = 0; i < n->expr.nargs; i++) + n->expr.args[i] = rval(s, n->expr.args[i], NULL); + if (ispure(n)) { + r = n; + } else { + if (exprtype(n)->type == Tyvoid) { + r = NULL; + append(s, n); + } else { + r = temp(s, n); + append(s, set(r, n)); + } + } + return r; } static Node *tupget(Simp *s, Node *tup, size_t idx, Node *dst) { - Node *plv, *prv, *sz, *stor, *dcl; - size_t off, i; - Type *ty; - - off = 0; - ty = exprtype(tup); - for (i = 0; i < ty->nsub; i++) { - off = alignto(off, ty->sub[i]); - if (i == idx) - break; - off += tysize(ty->sub[i]); - } - - if (!dst) { - dst = gentemp(tup->loc, ty->sub[idx], &dcl); - if (isstacktype(ty->sub[idx])) - declarelocal(s, dcl); - } - prv = add(addr(s, tup, ty->sub[i]), disp(tup->loc, off)); - if (stacknode(dst)) { - sz = disp(dst->loc, size(dst)); - plv = addr(s, dst, exprtype(dst)); - stor = mkexpr(dst->loc, Oblit, plv, prv, sz, NULL); - } else { - stor = set(dst, load(prv)); - } - append(s, stor); - return dst; + Node *plv, *prv, *sz, *stor, *dcl; + size_t off, i; + Type *ty; + + off = 0; + ty = exprtype(tup); + for (i = 0; i < ty->nsub; i++) { + off = alignto(off, ty->sub[i]); + if (i == idx) + break; + off += tysize(ty->sub[i]); + } + + if (!dst) { + dst = gentemp(tup->loc, ty->sub[idx], &dcl); + if (isstacktype(ty->sub[idx])) + declarelocal(s, dcl); + } + prv = add(addr(s, tup, ty->sub[i]), disp(tup->loc, off)); + if (stacknode(dst)) { + sz = disp(dst->loc, size(dst)); + plv = addr(s, dst, exprtype(dst)); + stor = mkexpr(dst->loc, Oblit, plv, prv, sz, NULL); + } else { + stor = set(dst, load(prv)); + } + append(s, stor); + return dst; } /* Takes a tuple and binds the i'th element of it to the * i'th name on the rhs of the assignment. */ static Node *destructure(Simp *s, Node *lhs, Node *rhs) { - Node *lv, *rv, **args; - size_t i; + Node *lv, *rv, **args; + size_t i; - args = lhs->expr.args; - rhs = rval(s, rhs, NULL); - for (i = 0; i < lhs->expr.nargs; i++) { - lv = lval(s, args[i]); - rv = tupget(s, rhs, i, lv); - assert(rv == lv); - } + args = lhs->expr.args; + rhs = rval(s, rhs, NULL); + for (i = 0; i < lhs->expr.nargs; i++) { + lv = lval(s, args[i]); + rv = tupget(s, rhs, i, lv); + assert(rv == lv); + } - return NULL; + return NULL; } static Node *assign(Simp *s, Node *lhs, Node *rhs) { - Node *t, *u, *v, *r; - - if (exprop(lhs) == Otup) { - r = destructure(s, lhs, rhs); - } else { - t = lval(s, lhs); - u = rval(s, rhs, t); - - /* if we stored the result into t, rval() should return that, - * so we know our work is done. */ - if (u == t) { - r = t; - } else if (stacknode(lhs)) { - t = addr(s, t, exprtype(lhs)); - u = addr(s, u, exprtype(lhs)); - v = disp(lhs->loc, size(lhs)); - r = mkexpr(lhs->loc, Oblit, t, u, v, NULL); - } else { - r = set(t, u); - } - } - return r; + Node *t, *u, *v, *r; + + if (exprop(lhs) == Otup) { + r = destructure(s, lhs, rhs); + } else { + t = lval(s, lhs); + u = rval(s, rhs, t); + + /* if we stored the result into t, rval() should return that, + * so we know our work is done. */ + if (u == t) { + r = t; + } else if (stacknode(lhs)) { + t = addr(s, t, exprtype(lhs)); + u = addr(s, u, exprtype(lhs)); + v = disp(lhs->loc, size(lhs)); + r = mkexpr(lhs->loc, Oblit, t, u, v, NULL); + } else { + r = set(t, u); + } + } + return r; } static Node *assignat(Simp *s, Node *r, size_t off, Node *val) { - Node *pval, *pdst; - Node *sz; - Node *st; + Node *pval, *pdst; + Node *sz; + Node *st; - pdst = add(r, disp(val->loc, off)); + pdst = add(r, disp(val->loc, off)); - if (stacknode(val)) { - sz = disp(val->loc, size(val)); - pval = addr(s, val, exprtype(val)); - st = mkexpr(val->loc, Oblit, pdst, pval, sz, NULL); - } else { - st = set(deref(pdst, val->expr.type), val); - } - append(s, st); - return r; + if (stacknode(val)) { + sz = disp(val->loc, size(val)); + pval = addr(s, val, exprtype(val)); + st = mkexpr(val->loc, Oblit, pdst, pval, sz, NULL); + } else { + st = set(deref(pdst, val->expr.type), val); + } + append(s, st); + return r; } /* Simplify tuple construction to a stack allocated @@ -1004,83 +1004,83 @@ static Node *assignat(Simp *s, Node *r, size_t off, Node *val) * head of the tuple. */ static Node *simptup(Simp *s, Node *n, Node *dst) { - Node **args; - Node *r; - size_t i, off; + Node **args; + Node *r; + size_t i, off; - args = n->expr.args; - if (!dst) - dst = temp(s, n); - r = addr(s, dst, exprtype(dst)); + args = n->expr.args; + if (!dst) + dst = temp(s, n); + r = addr(s, dst, exprtype(dst)); - off = 0; - for (i = 0; i < n->expr.nargs; i++) { - off = alignto(off, exprtype(args[i])); - assignat(s, r, off, rval(s, args[i], NULL)); - off += size(args[i]); - } - return dst; + off = 0; + for (i = 0; i < n->expr.nargs; i++) { + off = alignto(off, exprtype(args[i])); + assignat(s, r, off, rval(s, args[i], NULL)); + off += size(args[i]); + } + return dst; } static Node *simpucon(Simp *s, Node *n, Node *dst) { - Node *tmp, *u, *tag, *elt, *sz; - Node *r; - Type *ty; - Ucon *uc; - size_t i; - - /* find the ucon we're constructing here */ - ty = tybase(n->expr.type); - uc = NULL; - for (i = 0; i < ty->nmemb; i++) { - if (!strcmp(namestr(n->expr.args[0]), namestr(ty->udecls[i]->name))) { - uc = ty->udecls[i]; - break; - } - } - if (!uc) - die("Couldn't find union constructor"); - - if (dst) - tmp = dst; - else - tmp = temp(s, n); - - /* Set the tag on the ucon */ - u = addr(s, tmp, mktype(n->loc, Tyuint)); - tag = mkintlit(n->loc, uc->id); - tag->expr.type = mktype(n->loc, Tyuint); - append(s, set(deref(u, tyword), tag)); - - - /* fill the value, if needed */ - if (!uc->etype) - return tmp; - elt = rval(s, n->expr.args[1], NULL); - u = addk(u, Wordsz); - if (isstacktype(uc->etype)) { - elt = addr(s, elt, uc->etype); - sz = disp(n->loc, tysize(uc->etype)); - r = mkexpr(n->loc, Oblit, u, elt, sz, NULL); - } else { - r = set(deref(u, uc->etype), elt); - } - append(s, r); - return tmp; + Node *tmp, *u, *tag, *elt, *sz; + Node *r; + Type *ty; + Ucon *uc; + size_t i; + + /* find the ucon we're constructing here */ + ty = tybase(n->expr.type); + uc = NULL; + for (i = 0; i < ty->nmemb; i++) { + if (!strcmp(namestr(n->expr.args[0]), namestr(ty->udecls[i]->name))) { + uc = ty->udecls[i]; + break; + } + } + if (!uc) + die("Couldn't find union constructor"); + + if (dst) + tmp = dst; + else + tmp = temp(s, n); + + /* Set the tag on the ucon */ + u = addr(s, tmp, mktype(n->loc, Tyuint)); + tag = mkintlit(n->loc, uc->id); + tag->expr.type = mktype(n->loc, Tyuint); + append(s, set(deref(u, tyword), tag)); + + + /* fill the value, if needed */ + if (!uc->etype) + return tmp; + elt = rval(s, n->expr.args[1], NULL); + u = addk(u, Wordsz); + if (isstacktype(uc->etype)) { + elt = addr(s, elt, uc->etype); + sz = disp(n->loc, tysize(uc->etype)); + r = mkexpr(n->loc, Oblit, u, elt, sz, NULL); + } else { + r = set(deref(u, uc->etype), elt); + } + append(s, r); + return tmp; } static Node *simpuget(Simp *s, Node *n, Node *dst) { - Node *u, *p, *l; + Node *u, *p, *l; - if (!dst) - dst = temp(s, n); - u = rval(s, n->expr.args[0], NULL); - p = addk(addr(s, u, exprtype(n)), Wordsz); - l = assign(s, dst, load(p)); - append(s, l); - return dst; + if (!dst) + dst = temp(s, n); + u = rval(s, n->expr.args[0], NULL); + p = addk(addr(s, u, exprtype(n)), Wordsz); + l = assign(s, dst, load(p)); + append(s, l); + return dst; } /* simplifies @@ -1094,583 +1094,583 @@ static Node *simpuget(Simp *s, Node *n, Node *dst) */ static Node *simplazy(Simp *s, Node *n) { - Node *r, *t, *u; - Node *ltrue, *lfalse, *ldone; + Node *r, *t, *u; + Node *ltrue, *lfalse, *ldone; - /* set up temps and labels */ - r = temp(s, n); - ltrue = genlbl(n->loc); - lfalse = genlbl(n->loc); - ldone = genlbl(n->loc); + /* set up temps and labels */ + r = temp(s, n); + ltrue = genlbl(n->loc); + lfalse = genlbl(n->loc); + ldone = genlbl(n->loc); - /* simp the conditional */ - simpcond(s, n, ltrue, lfalse); + /* simp the conditional */ + simpcond(s, n, ltrue, lfalse); - /* if true */ - append(s, ltrue); - u = mkexpr(n->loc, Olit, mkbool(n->loc, 1), NULL); - u->expr.type = mktype(n->loc, Tybool); - t = set(r, u); - append(s, t); - jmp(s, ldone); + /* if true */ + append(s, ltrue); + u = mkexpr(n->loc, Olit, mkbool(n->loc, 1), NULL); + u->expr.type = mktype(n->loc, Tybool); + t = set(r, u); + append(s, t); + jmp(s, ldone); - /* if false */ - append(s, lfalse); - u = mkexpr(n->loc, Olit, mkbool(n->loc, 0), NULL); - u->expr.type = mktype(n->loc, Tybool); - t = set(r, u); - append(s, t); - jmp(s, ldone); + /* if false */ + append(s, lfalse); + u = mkexpr(n->loc, Olit, mkbool(n->loc, 0), NULL); + u->expr.type = mktype(n->loc, Tybool); + t = set(r, u); + append(s, t); + jmp(s, ldone); - /* finish */ - append(s, ldone); - return r; + /* finish */ + append(s, ldone); + return r; } static Node *comparecomplex(Simp *s, Node *n, Op op) { - fatal(n, "Complex comparisons not yet supported\n"); - return NULL; + fatal(n, "Complex comparisons not yet supported\n"); + return NULL; } static Node *compare(Simp *s, Node *n, int fields) { - const Op cmpmap[Numops][3] = { - [Oeq] = {Oeq, Oueq, Ofeq}, - [One] = {One, Oune, Ofne}, - [Ogt] = {Ogt, Ougt, Ofgt}, - [Oge] = {Oge, Ouge, Ofge}, - [Olt] = {Olt, Oult, Oflt}, - [Ole] = {Ole, Oule, Ofle} - }; - Node *r; - Op newop; - - newop = Obad; - if (istysigned(tybase(exprtype(n->expr.args[0])))) - newop = cmpmap[n->expr.op][0]; - else if (istyunsigned(tybase(exprtype(n->expr.args[0])))) - newop = cmpmap[n->expr.op][1]; - else if (istyfloat(tybase(exprtype(n->expr.args[0])))) - newop = cmpmap[n->expr.op][2]; - - if (newop != Obad) { - n->expr.op = newop; - r = visit(s, n); - } else if (fields) { - r = comparecomplex(s, n, exprop(n)); - } else { - fatal(n, "unsupported comparison on values"); - } - return r; + const Op cmpmap[Numops][3] = { + [Oeq] = {Oeq, Oueq, Ofeq}, + [One] = {One, Oune, Ofne}, + [Ogt] = {Ogt, Ougt, Ofgt}, + [Oge] = {Oge, Ouge, Ofge}, + [Olt] = {Olt, Oult, Oflt}, + [Ole] = {Ole, Oule, Ofle} + }; + Node *r; + Op newop; + + newop = Obad; + if (istysigned(tybase(exprtype(n->expr.args[0])))) + newop = cmpmap[n->expr.op][0]; + else if (istyunsigned(tybase(exprtype(n->expr.args[0])))) + newop = cmpmap[n->expr.op][1]; + else if (istyfloat(tybase(exprtype(n->expr.args[0])))) + newop = cmpmap[n->expr.op][2]; + + if (newop != Obad) { + n->expr.op = newop; + r = visit(s, n); + } else if (fields) { + r = comparecomplex(s, n, exprop(n)); + } else { + fatal(n, "unsupported comparison on values"); + } + return r; } static Node *vatypeinfo(Simp *s, Node *n) { - Node *ti, *tp, *td, *tn; - Type *ft, *vt, **st; - size_t nst, i; - char buf[1024]; - - st = NULL; - nst = 0; - ft = exprtype(n->expr.args[0]); - /* The structure of ft->sub: - * [return, normal, args, ...] - * - * The structure of n->expr.sub: - * [fn, normal, args, , variadic, args] - * - * We want to start at variadic, so we want - * to count from ft->nsub - 1, up to n->expr.nsub. - */ - for (i = ft->nsub - 1; i < n->expr.nargs; i++) - lappend(&st, &nst, exprtype(n->expr.args[i])); - vt = mktytuple(n->loc, st, nst); - vt->isreflect = 1; - - /* make the decl */ - tn = mkname(Zloc, tydescid(buf, sizeof buf, vt)); - td = mkdecl(Zloc, tn, mktype(n->loc, Tybyte)); - td->decl.isglobl = 1; - td->decl.isconst = 1; - td->decl.ishidden = 1; - - /* and the var */ - ti = mkexpr(Zloc, Ovar, tn, NULL); - ti->expr.type = td->decl.type; - ti->expr.did = td->decl.did; - - /* and the pointer */ - tp = mkexpr(Zloc, Oaddr, ti, NULL); - tp->expr.type = mktyptr(n->loc, td->decl.type); - - htput(s->globls, td, asmname(td)); - return tp; + Node *ti, *tp, *td, *tn; + Type *ft, *vt, **st; + size_t nst, i; + char buf[1024]; + + st = NULL; + nst = 0; + ft = exprtype(n->expr.args[0]); + /* The structure of ft->sub: + * [return, normal, args, ...] + * + * The structure of n->expr.sub: + * [fn, normal, args, , variadic, args] + * + * We want to start at variadic, so we want + * to count from ft->nsub - 1, up to n->expr.nsub. + */ + for (i = ft->nsub - 1; i < n->expr.nargs; i++) + lappend(&st, &nst, exprtype(n->expr.args[i])); + vt = mktytuple(n->loc, st, nst); + vt->isreflect = 1; + + /* make the decl */ + tn = mkname(Zloc, tydescid(buf, sizeof buf, vt)); + td = mkdecl(Zloc, tn, mktype(n->loc, Tybyte)); + td->decl.isglobl = 1; + td->decl.isconst = 1; + td->decl.ishidden = 1; + + /* and the var */ + ti = mkexpr(Zloc, Ovar, tn, NULL); + ti->expr.type = td->decl.type; + ti->expr.did = td->decl.did; + + /* and the pointer */ + tp = mkexpr(Zloc, Oaddr, ti, NULL); + tp->expr.type = mktyptr(n->loc, td->decl.type); + + htput(s->globls, td, asmname(td)); + return tp; } static Node *capture(Simp *s, Node *n, Node *dst) { - Node *fn, *t, *f, *e, *val, *dcl, *fp, *envsz; - size_t nenv, nenvt, off, i; - Type **envt; - Node **env; - - f = simpcode(s, n); - fn = n->expr.args[0]; - fn = fn->lit.fnval; - if (!dst) { - dst = gentemp(n->loc, closuretype(exprtype(f)), &dcl); - forcelocal(s, dcl); - } - fp = addr(s, dst, exprtype(dst)); - - env = getclosure(fn->func.scope, &nenv); - if (env) { - /* we need these in a deterministic order so that we can - put them in the right place both when we use them and - when we capture them. */ - qsort(env, nenv, sizeof(Node*), envcmp); - - /* make the tuple that will hold the environment */ - envt = NULL; - nenvt = 0; - /* reserve space for size */ - lappend(&envt, &nenvt, tyintptr); - for (i = 0; i < nenv; i++) - lappend(&envt, &nenvt, decltype(env[i])); - - t = gentemp(n->loc, mktytuple(n->loc, envt, nenvt), &dcl); - forcelocal(s, dcl); - e = addr(s, t, exprtype(t)); - - off = Ptrsz; /* we start with the size of the env */ - for (i = 0; i < nenv; i++) { - off = alignto(off, decltype(env[i])); - val = mkexpr(n->loc, Ovar, env[i]->decl.name, NULL); - val->expr.type = env[i]->decl.type; - val->expr.did = env[i]->decl.did; - assignat(s, e, off, rval(s, val, NULL)); - off += size(env[i]); - } - free(env); - envsz = mkintlit(n->loc, off); - envsz->expr.type = tyintptr; - assignat(s, e, 0, envsz); - assignat(s, fp, 0, e); - } - assignat(s, fp, Ptrsz, f); - return dst; + Node *fn, *t, *f, *e, *val, *dcl, *fp, *envsz; + size_t nenv, nenvt, off, i; + Type **envt; + Node **env; + + f = simpcode(s, n); + fn = n->expr.args[0]; + fn = fn->lit.fnval; + if (!dst) { + dst = gentemp(n->loc, closuretype(exprtype(f)), &dcl); + forcelocal(s, dcl); + } + fp = addr(s, dst, exprtype(dst)); + + env = getclosure(fn->func.scope, &nenv); + if (env) { + /* we need these in a deterministic order so that we can + put them in the right place both when we use them and + when we capture them. */ + qsort(env, nenv, sizeof(Node*), envcmp); + + /* make the tuple that will hold the environment */ + envt = NULL; + nenvt = 0; + /* reserve space for size */ + lappend(&envt, &nenvt, tyintptr); + for (i = 0; i < nenv; i++) + lappend(&envt, &nenvt, decltype(env[i])); + + t = gentemp(n->loc, mktytuple(n->loc, envt, nenvt), &dcl); + forcelocal(s, dcl); + e = addr(s, t, exprtype(t)); + + off = Ptrsz; /* we start with the size of the env */ + for (i = 0; i < nenv; i++) { + off = alignto(off, decltype(env[i])); + val = mkexpr(n->loc, Ovar, env[i]->decl.name, NULL); + val->expr.type = env[i]->decl.type; + val->expr.did = env[i]->decl.did; + assignat(s, e, off, rval(s, val, NULL)); + off += size(env[i]); + } + free(env); + envsz = mkintlit(n->loc, off); + envsz->expr.type = tyintptr; + assignat(s, e, 0, envsz); + assignat(s, fp, 0, e); + } + assignat(s, fp, Ptrsz, f); + return dst; } static Node *getenvptr(Simp *s, Node *n) { - assert(tybase(exprtype(n))->type == Tyfunc); - return load(addr(s, n, tyintptr)); + assert(tybase(exprtype(n))->type == Tyfunc); + return load(addr(s, n, tyintptr)); } static Node *getcode(Simp *s, Node *n) { - Node *r, *p, *d; - Type *ty; + Node *r, *p, *d; + Type *ty; - if (isconstfn(n)) { - d = decls[n->expr.did]; - r = mkexpr(n->loc, Ovar, n->expr.args[0], NULL); - r->expr.did = d->decl.did; - r->expr.type = codetype(exprtype(n)); - } else { - ty = tybase(exprtype(n)); - assert(ty->type == Tyfunc); - p = addr(s, rval(s, n, NULL), codetype(ty)); - r = load(addk(p, Ptrsz)); - } - return r; + if (isconstfn(n)) { + d = decls[n->expr.did]; + r = mkexpr(n->loc, Ovar, n->expr.args[0], NULL); + r->expr.did = d->decl.did; + r->expr.type = codetype(exprtype(n)); + } else { + ty = tybase(exprtype(n)); + assert(ty->type == Tyfunc); + p = addr(s, rval(s, n, NULL), codetype(ty)); + r = load(addk(p, Ptrsz)); + } + return r; } static Node *simpcall(Simp *s, Node *n, Node *dst) { - Node *r, *call, *fn; - size_t i, nargs; - Node **args; - Type *ft; - Op op; - - /* NB: If we called rval() on a const function, , we would end up with - a stack allocated closure. We don't want to do this. */ - fn = n->expr.args[0]; - if (!isconstfn(fn)) - fn = rval(s, fn, NULL); - ft = tybase(exprtype(fn)); - if (exprtype(n)->type == Tyvoid) - r = NULL; - else if (isstacktype(exprtype(n)) && dst) - r = dst; - else - r = temp(s, n); - - args = NULL; - nargs = 0; - op = Ocall; - lappend(&args, &nargs, getcode(s, fn)); - if (!isconstfn(fn)) { - op = Ocallind; - lappend(&args, &nargs, getenvptr(s, fn)); - } - - if (exprtype(n)->type != Tyvoid && isstacktype(exprtype(n))) - lappend(&args, &nargs, addr(s, r, exprtype(n))); - - for (i = 1; i < n->expr.nargs; i++) { - if (i < ft->nsub && tybase(ft->sub[i])->type == Tyvalist) - lappend(&args, &nargs, vatypeinfo(s, n)); - lappend(&args, &nargs, rval(s, n->expr.args[i], NULL)); - if (exprop(n->expr.args[i]) == Oaddr) - if (exprop(n->expr.args[i]->expr.args[0]) == Ovar) - def(s, n->expr.args[i]->expr.args[0]); - } - if (i < ft->nsub && tybase(ft->sub[i])->type == Tyvalist) - lappend(&args, &nargs, vatypeinfo(s, n)); - - if (r) - def(s, r); - - call = mkexprl(n->loc, op, args, nargs); - call->expr.type = exprtype(n); - if (r && !isstacktype(exprtype(n))) { - append(s, set(r, call)); - } else { - append(s, call); - } - return r; + Node *r, *call, *fn; + size_t i, nargs; + Node **args; + Type *ft; + Op op; + + /* NB: If we called rval() on a const function, , we would end up with + a stack allocated closure. We don't want to do this. */ + fn = n->expr.args[0]; + if (!isconstfn(fn)) + fn = rval(s, fn, NULL); + ft = tybase(exprtype(fn)); + if (exprtype(n)->type == Tyvoid) + r = NULL; + else if (isstacktype(exprtype(n)) && dst) + r = dst; + else + r = temp(s, n); + + args = NULL; + nargs = 0; + op = Ocall; + lappend(&args, &nargs, getcode(s, fn)); + if (!isconstfn(fn)) { + op = Ocallind; + lappend(&args, &nargs, getenvptr(s, fn)); + } + + if (exprtype(n)->type != Tyvoid && isstacktype(exprtype(n))) + lappend(&args, &nargs, addr(s, r, exprtype(n))); + + for (i = 1; i < n->expr.nargs; i++) { + if (i < ft->nsub && tybase(ft->sub[i])->type == Tyvalist) + lappend(&args, &nargs, vatypeinfo(s, n)); + lappend(&args, &nargs, rval(s, n->expr.args[i], NULL)); + if (exprop(n->expr.args[i]) == Oaddr) + if (exprop(n->expr.args[i]->expr.args[0]) == Ovar) + def(s, n->expr.args[i]->expr.args[0]); + } + if (i < ft->nsub && tybase(ft->sub[i])->type == Tyvalist) + lappend(&args, &nargs, vatypeinfo(s, n)); + + if (r) + def(s, r); + + call = mkexprl(n->loc, op, args, nargs); + call->expr.type = exprtype(n); + if (r && !isstacktype(exprtype(n))) { + append(s, set(r, call)); + } else { + append(s, call); + } + return r; } static Node *rval(Simp *s, Node *n, Node *dst) { - Node *t, *u, *v; /* temporary nodes */ - Node *r; /* expression result */ - Node **args; - size_t i; - Type *ty; - - const Op fusedmap[Numops] = { - [Oaddeq] = Oadd, - [Osubeq] = Osub, - [Omuleq] = Omul, - [Odiveq] = Odiv, - [Omodeq] = Omod, - [Oboreq] = Obor, - [Obandeq] = Oband, - [Obxoreq] = Obxor, - [Obsleq] = Obsl, - [Obsreq] = Obsr, - }; - - r = NULL; - args = n->expr.args; - switch (exprop(n)) { - case Olor: case Oland: - r = simplazy(s, n); - break; - case Osize: - r = mkintlit(n->loc, size(args[0])); - r->expr.type = exprtype(n); - break; - case Oslice: - r = simpslice(s, n, dst); - break; - case Oidx: - t = rval(s, n->expr.args[0], NULL); - lappend(&s->idxctx, &s->nidxctx, t); - u = idxaddr(s, t, n->expr.args[1]); - lpop(&s->idxctx, &s->nidxctx); - r = load(u); - break; - /* array.len slice.len are magic 'virtual' members. - * they need to be special cased. */ - case Omemb: - if (exprtype(args[0])->type == Tyslice || exprtype(args[0])->type == Tyarray) { - r = seqlen(s, args[0], exprtype(n)); - } else { - t = membaddr(s, n); - r = load(t); - } - break; - case Oucon: - r = simpucon(s, n, dst); - break; - case Outag: - r = uconid(s, args[0]); - break; - case Oudata: - r = simpuget(s, n, dst); - break; - case Otup: - r = simptup(s, n, dst); - break; - case Oarr: - if (!dst) - dst = temp(s, n); - t = addr(s, dst, exprtype(dst)); - for (i = 0; i < n->expr.nargs; i++) - assignat(s, t, size(n->expr.args[i])*i, rval(s, n->expr.args[i], NULL)); - r = dst; - break; - case Ostruct: - if (!dst) - dst = temp(s, n); - u = mkexpr(dst->loc, Odef, dst, NULL); - u->expr.type = mktype(u->loc, Tyvoid); - append(s, u); - t = addr(s, dst, exprtype(dst)); - ty = exprtype(n); - /* we only need to clear if we don't have things fully initialized */ - if (tybase(ty)->nmemb != n->expr.nargs) - append(s, mkexpr(n->loc, Oclear, t, mkintlit(n->loc, size(n)), NULL)); - for (i = 0; i < n->expr.nargs; i++) - assignat(s, t, offset(n, n->expr.args[i]->expr.idx), rval(s, n->expr.args[i], NULL)); - r = dst; - break; - case Ocast: - r = simpcast(s, args[0], exprtype(n)); - break; - - /* fused ops: - * foo ?= blah - * => - * foo = foo ? blah*/ - case Oaddeq: case Osubeq: case Omuleq: case Odiveq: case Omodeq: - case Oboreq: case Obandeq: case Obxoreq: case Obsleq: case Obsreq: - assert(fusedmap[exprop(n)] != Obad); - u = lval(s, args[0]); - v = rval(s, args[1], NULL); - v = mkexpr(n->loc, fusedmap[exprop(n)], u, v, NULL); - v->expr.type = u->expr.type; - r = set(u, v); - break; - - /* ++expr(x) - * => args[0] = args[0] + 1 - * expr(x) */ - case Opreinc: - v = assign(s, args[0], addk(args[0], 1)); - append(s, v); - r = rval(s, args[0], NULL); - break; - case Opredec: - v = assign(s, args[0], subk(args[0], 1)); - append(s, v); - r = rval(s, args[0], NULL); - break; - - /* expr(x++) - * => expr - * x = x + 1 - */ - case Opostinc: - r = lval(s, args[0]); - t = assign(s, r, addk(r, 1)); - lappend(&s->incqueue, &s->nqueue, t); - break; - case Opostdec: - r = lval(s, args[0]); - t = assign(s, r, subk(r, 1)); - lappend(&s->incqueue, &s->nqueue, t); - break; - case Olit: - switch (args[0]->lit.littype) { - case Lchr: case Lbool: case Llbl: - r = n; - break; - case Lint: - /* we can only have up to 4 byte immediates, but they - * can be moved into 64 bit regs */ - if ((uint64_t)args[0]->lit.intval < 0x7fffffffULL) - r = n; - else - r = simpblob(s, n); - break; - case Lstr: case Lflt: - r = simpblob(s, n); - break; - case Lfunc: - r = capture(s, n, dst); - break; - } - break; - case Ovar: - r = loadvar(s, n, dst); - break; - case Oidxlen: - if (s->nidxctx == 0) - fatal(n, "'$' undefined outside of index or slice expression"); - return seqlen(s, s->idxctx[s->nidxctx - 1], exprtype(n)); - break; - case Ogap: - fatal(n, "'_' may not be an rvalue"); - break; - case Oret: - if (s->isbigret) { - t = rval(s, args[0], NULL); - t = addr(s, t, exprtype(args[0])); - u = disp(n->loc, size(args[0])); - v = mkexpr(n->loc, Oblit, s->ret, t, u, NULL); - append(s, v); - } else if (n->expr.nargs && n->expr.args[0]) { - t = s->ret; - /* void calls return nothing */ - if (t) { - t = set(t, rval(s, args[0], NULL)); - append(s, t); - } - } - /* drain the increment queue before we return */ - for (i = 0; i < s->nqueue; i++) - append(s, s->incqueue[i]); - lfree(&s->incqueue, &s->nqueue); - append(s, mkexpr(n->loc, Oret, NULL)); - break; - case Oasn: - r = assign(s, args[0], args[1]); - break; - case Ocall: - r = simpcall(s, n, dst); - break; - case Oaddr: - t = lval(s, args[0]); - if (exprop(t) == Ovar) /* Ovar is the only one that doesn't return Oderef(Oaddr(...)) */ - r = addr(s, t, exprtype(t)); - else - r = t->expr.args[0]; - break; - case Oneg: - if (istyfloat(exprtype(n))) { - t =mkfloat(n->loc, -1.0); - u = mkexpr(n->loc, Olit, t, NULL); - t->lit.type = n->expr.type; - u->expr.type = n->expr.type; - v = simpblob(s, u); - r = mkexpr(n->loc, Ofmul, v, rval(s, args[0], NULL), NULL); - r->expr.type = n->expr.type; - } else { - r = visit(s, n); - } - break; - case Obreak: - if (s->nloopexit == 0) - fatal(n, "trying to break when not in loop"); - jmp(s, s->loopexit[s->nloopexit - 1]); - break; - case Ocontinue: - if (s->nloopstep == 0) - fatal(n, "trying to continue when not in loop"); - jmp(s, s->loopstep[s->nloopstep - 1]); - break; - case Oeq: case One: - r = compare(s, n, 1); - break; - case Ogt: case Oge: case Olt: case Ole: - r = compare(s, n, 0); - break; - case Otupget: - assert(exprop(args[1]) == Olit); - i = args[1]->expr.args[0]->lit.intval; - t = rval(s, args[0], NULL); - r = tupget(s, t, i, dst); - break; - case Obad: - die("bad operator"); - break; - default: - if (istyfloat(exprtype(n))) { - switch (exprop(n)) { - case Oadd: n->expr.op = Ofadd; break; - case Osub: n->expr.op = Ofsub; break; - case Omul: n->expr.op = Ofmul; break; - case Odiv: n->expr.op = Ofdiv; break; - default: break; - } - } - r = visit(s, n); - break; - } - return r; + Node *t, *u, *v; /* temporary nodes */ + Node *r; /* expression result */ + Node **args; + size_t i; + Type *ty; + + const Op fusedmap[Numops] = { + [Oaddeq] = Oadd, + [Osubeq] = Osub, + [Omuleq] = Omul, + [Odiveq] = Odiv, + [Omodeq] = Omod, + [Oboreq] = Obor, + [Obandeq] = Oband, + [Obxoreq] = Obxor, + [Obsleq] = Obsl, + [Obsreq] = Obsr, + }; + + r = NULL; + args = n->expr.args; + switch (exprop(n)) { + case Olor: case Oland: + r = simplazy(s, n); + break; + case Osize: + r = mkintlit(n->loc, size(args[0])); + r->expr.type = exprtype(n); + break; + case Oslice: + r = simpslice(s, n, dst); + break; + case Oidx: + t = rval(s, n->expr.args[0], NULL); + lappend(&s->idxctx, &s->nidxctx, t); + u = idxaddr(s, t, n->expr.args[1]); + lpop(&s->idxctx, &s->nidxctx); + r = load(u); + break; + /* array.len slice.len are magic 'virtual' members. + * they need to be special cased. */ + case Omemb: + if (exprtype(args[0])->type == Tyslice || exprtype(args[0])->type == Tyarray) { + r = seqlen(s, args[0], exprtype(n)); + } else { + t = membaddr(s, n); + r = load(t); + } + break; + case Oucon: + r = simpucon(s, n, dst); + break; + case Outag: + r = uconid(s, args[0]); + break; + case Oudata: + r = simpuget(s, n, dst); + break; + case Otup: + r = simptup(s, n, dst); + break; + case Oarr: + if (!dst) + dst = temp(s, n); + t = addr(s, dst, exprtype(dst)); + for (i = 0; i < n->expr.nargs; i++) + assignat(s, t, size(n->expr.args[i])*i, rval(s, n->expr.args[i], NULL)); + r = dst; + break; + case Ostruct: + if (!dst) + dst = temp(s, n); + u = mkexpr(dst->loc, Odef, dst, NULL); + u->expr.type = mktype(u->loc, Tyvoid); + append(s, u); + t = addr(s, dst, exprtype(dst)); + ty = exprtype(n); + /* we only need to clear if we don't have things fully initialized */ + if (tybase(ty)->nmemb != n->expr.nargs) + append(s, mkexpr(n->loc, Oclear, t, mkintlit(n->loc, size(n)), NULL)); + for (i = 0; i < n->expr.nargs; i++) + assignat(s, t, offset(n, n->expr.args[i]->expr.idx), rval(s, n->expr.args[i], NULL)); + r = dst; + break; + case Ocast: + r = simpcast(s, args[0], exprtype(n)); + break; + + /* fused ops: + * foo ?= blah + * => + * foo = foo ? blah*/ + case Oaddeq: case Osubeq: case Omuleq: case Odiveq: case Omodeq: + case Oboreq: case Obandeq: case Obxoreq: case Obsleq: case Obsreq: + assert(fusedmap[exprop(n)] != Obad); + u = lval(s, args[0]); + v = rval(s, args[1], NULL); + v = mkexpr(n->loc, fusedmap[exprop(n)], u, v, NULL); + v->expr.type = u->expr.type; + r = set(u, v); + break; + + /* ++expr(x) + * => args[0] = args[0] + 1 + * expr(x) */ + case Opreinc: + v = assign(s, args[0], addk(args[0], 1)); + append(s, v); + r = rval(s, args[0], NULL); + break; + case Opredec: + v = assign(s, args[0], subk(args[0], 1)); + append(s, v); + r = rval(s, args[0], NULL); + break; + + /* expr(x++) + * => expr + * x = x + 1 + */ + case Opostinc: + r = lval(s, args[0]); + t = assign(s, r, addk(r, 1)); + lappend(&s->incqueue, &s->nqueue, t); + break; + case Opostdec: + r = lval(s, args[0]); + t = assign(s, r, subk(r, 1)); + lappend(&s->incqueue, &s->nqueue, t); + break; + case Olit: + switch (args[0]->lit.littype) { + case Lchr: case Lbool: case Llbl: + r = n; + break; + case Lint: + /* we can only have up to 4 byte immediates, but they + * can be moved into 64 bit regs */ + if ((uint64_t)args[0]->lit.intval < 0x7fffffffULL) + r = n; + else + r = simpblob(s, n); + break; + case Lstr: case Lflt: + r = simpblob(s, n); + break; + case Lfunc: + r = capture(s, n, dst); + break; + } + break; + case Ovar: + r = loadvar(s, n, dst); + break; + case Oidxlen: + if (s->nidxctx == 0) + fatal(n, "'$' undefined outside of index or slice expression"); + return seqlen(s, s->idxctx[s->nidxctx - 1], exprtype(n)); + break; + case Ogap: + fatal(n, "'_' may not be an rvalue"); + break; + case Oret: + if (s->isbigret) { + t = rval(s, args[0], NULL); + t = addr(s, t, exprtype(args[0])); + u = disp(n->loc, size(args[0])); + v = mkexpr(n->loc, Oblit, s->ret, t, u, NULL); + append(s, v); + } else if (n->expr.nargs && n->expr.args[0]) { + t = s->ret; + /* void calls return nothing */ + if (t) { + t = set(t, rval(s, args[0], NULL)); + append(s, t); + } + } + /* drain the increment queue before we return */ + for (i = 0; i < s->nqueue; i++) + append(s, s->incqueue[i]); + lfree(&s->incqueue, &s->nqueue); + append(s, mkexpr(n->loc, Oret, NULL)); + break; + case Oasn: + r = assign(s, args[0], args[1]); + break; + case Ocall: + r = simpcall(s, n, dst); + break; + case Oaddr: + t = lval(s, args[0]); + if (exprop(t) == Ovar) /* Ovar is the only one that doesn't return Oderef(Oaddr(...)) */ + r = addr(s, t, exprtype(t)); + else + r = t->expr.args[0]; + break; + case Oneg: + if (istyfloat(exprtype(n))) { + t =mkfloat(n->loc, -1.0); + u = mkexpr(n->loc, Olit, t, NULL); + t->lit.type = n->expr.type; + u->expr.type = n->expr.type; + v = simpblob(s, u); + r = mkexpr(n->loc, Ofmul, v, rval(s, args[0], NULL), NULL); + r->expr.type = n->expr.type; + } else { + r = visit(s, n); + } + break; + case Obreak: + if (s->nloopexit == 0) + fatal(n, "trying to break when not in loop"); + jmp(s, s->loopexit[s->nloopexit - 1]); + break; + case Ocontinue: + if (s->nloopstep == 0) + fatal(n, "trying to continue when not in loop"); + jmp(s, s->loopstep[s->nloopstep - 1]); + break; + case Oeq: case One: + r = compare(s, n, 1); + break; + case Ogt: case Oge: case Olt: case Ole: + r = compare(s, n, 0); + break; + case Otupget: + assert(exprop(args[1]) == Olit); + i = args[1]->expr.args[0]->lit.intval; + t = rval(s, args[0], NULL); + r = tupget(s, t, i, dst); + break; + case Obad: + die("bad operator"); + break; + default: + if (istyfloat(exprtype(n))) { + switch (exprop(n)) { + case Oadd: n->expr.op = Ofadd; break; + case Osub: n->expr.op = Ofsub; break; + case Omul: n->expr.op = Ofmul; break; + case Odiv: n->expr.op = Ofdiv; break; + default: break; + } + } + r = visit(s, n); + break; + } + return r; } static void declarearg(Simp *s, Node *n) { - assert(n->type == Ndecl || (n->type == Nexpr && exprop(n) == Ovar)); - lappend(&s->args, &s->nargs, n); + assert(n->type == Ndecl || (n->type == Nexpr && exprop(n) == Ovar)); + lappend(&s->args, &s->nargs, n); } static int islbl(Node *n) { - Node *l; - if (exprop(n) != Olit) - return 0; - l = n->expr.args[0]; - return l->type == Nlit && l->lit.littype == Llbl; + Node *l; + if (exprop(n) != Olit) + return 0; + l = n->expr.args[0]; + return l->type == Nlit && l->lit.littype == Llbl; } static void simpmatch(Simp *s, Node *n) { - Node *val; - Node **match; - size_t i, nmatch; + Node *val; + Node **match; + size_t i, nmatch; - val = rval(s, n->matchstmt.val, NULL); + val = rval(s, n->matchstmt.val, NULL); - match = NULL; - nmatch = 0; - genmatch(n, val, &match, &nmatch); - for (i = 0; i < nmatch; i++) - simp(s, match[i]); + match = NULL; + nmatch = 0; + genmatch(n, val, &match, &nmatch); + for (i = 0; i < nmatch; i++) + simp(s, match[i]); } static Node *simp(Simp *s, Node *n) { - Node *r, *t, *u; - size_t i; - - if (!n) - return NULL; - r = NULL; - switch (n->type) { - case Nblock: simpblk(s, n); break; - case Nifstmt: simpif(s, n, NULL); break; - case Nloopstmt: simploop(s, n); break; - case Niterstmt: simpiter(s, n); break; - case Nmatchstmt: simpmatch(s, n); break; - case Nexpr: - if (islbl(n)) - append(s, n); - else - r = rval(s, n, NULL); - if (r) - append(s, r); - /* drain the increment queue for this expr */ - for (i = 0; i < s->nqueue; i++) - append(s, s->incqueue[i]); - lfree(&s->incqueue, &s->nqueue); - break; - - case Ndecl: - declarelocal(s, n); - t = mkexpr(n->loc, Ovar, n->decl.name, NULL); - if (n->decl.init) { - u = mkexpr(n->loc, Oasn, t, n->decl.init, NULL); - u->expr.type = n->decl.type; - t->expr.type = n->decl.type; - t->expr.did = n->decl.did; - simp(s, u); - } - break; - default: - dump(n, stderr); - die("bad node passsed to simp()"); - break; - } - return r; + Node *r, *t, *u; + size_t i; + + if (!n) + return NULL; + r = NULL; + switch (n->type) { + case Nblock: simpblk(s, n); break; + case Nloopstmt: simploop(s, n); break; + case Niterstmt: simpiter(s, n); break; + case Nifstmt: simpif(s, n, NULL); break; + case Nmatchstmt: simpmatch(s, n); break; + case Nexpr: + if (islbl(n)) + append(s, n); + else + r = rval(s, n, NULL); + if (r) + append(s, r); + /* drain the increment queue for this expr */ + for (i = 0; i < s->nqueue; i++) + append(s, s->incqueue[i]); + lfree(&s->incqueue, &s->nqueue); + break; + + case Ndecl: + declarelocal(s, n); + t = mkexpr(n->loc, Ovar, n->decl.name, NULL); + if (n->decl.init) { + u = mkexpr(n->loc, Oasn, t, n->decl.init, NULL); + u->expr.type = n->decl.type; + t->expr.type = n->decl.type; + t->expr.did = n->decl.did; + simp(s, u); + } + break; + default: + dump(n, stderr); + die("bad node passsed to simp()"); + break; + } + return r; } /* @@ -1680,225 +1680,225 @@ static Node *simp(Simp *s, Node *n) */ static void flatten(Simp *s, Node *f) { - Node *dcl; - Type *ty; - size_t i; + Node *dcl; + Type *ty; + size_t i; - assert(f->type == Nfunc); - s->nstmts = 0; - s->stmts = NULL; - s->endlbl = genlbl(f->loc); - s->ret = NULL; + assert(f->type == Nfunc); + s->nstmts = 0; + s->stmts = NULL; + s->endlbl = genlbl(f->loc); + s->ret = NULL; - /* make a temp for the return type */ - ty = f->func.type->sub[0]; - if (isstacktype(ty)) { - s->isbigret = 1; - s->ret = gentemp(f->loc, mktyptr(f->loc, ty), &dcl); - declarearg(s, dcl); - } else if (ty->type != Tyvoid) { - s->isbigret = 0; - s->ret = gentemp(f->loc, ty, &dcl); - } + /* make a temp for the return type */ + ty = f->func.type->sub[0]; + if (isstacktype(ty)) { + s->isbigret = 1; + s->ret = gentemp(f->loc, mktyptr(f->loc, ty), &dcl); + declarearg(s, dcl); + } else if (ty->type != Tyvoid) { + s->isbigret = 0; + s->ret = gentemp(f->loc, ty, &dcl); + } - for (i = 0; i < f->func.nargs; i++) { - declarearg(s, f->func.args[i]); - } - simp(s, f->func.body); + for (i = 0; i < f->func.nargs; i++) { + declarearg(s, f->func.args[i]); + } + simp(s, f->func.body); - append(s, s->endlbl); + append(s, s->endlbl); } static int isexport(Node *dcl) { - Node *n; + Node *n; - /* Vishidden should also be exported. */ - if (dcl->decl.vis != Visintern) - return 1; - n = dcl->decl.name; - if (!n->name.ns && streq(n->name.name, "main")) - return 1; - if (streq(n->name.name, "__init__")) - return 1; - return 0; + /* Vishidden should also be exported. */ + if (dcl->decl.vis != Visintern) + return 1; + n = dcl->decl.name; + if (!n->name.ns && streq(n->name.name, "main")) + return 1; + if (streq(n->name.name, "__init__")) + return 1; + return 0; } static int envcmp(const void *pa, const void *pb) { - const Node *a, *b; + const Node *a, *b; - a = *(const Node**)pa; - b = *(const Node**)pb; - return b->decl.did - a->decl.did; + a = *(const Node**)pa; + b = *(const Node**)pb; + return b->decl.did - a->decl.did; } static void collectenv(Simp *s, Node *fn) { - size_t nenv, i; - Node **env; - size_t off; - - env = getclosure(fn->func.scope, &nenv); - if (!env) - return; - /* - we need these in a deterministic order so that we can - put them in the right place both when we use them and - when we capture them. - */ - s->hasenv = 1; - qsort(env, nenv, sizeof(Node*), envcmp); - off = Ptrsz; /* we start with the size of the env */ - for (i = 0; i < nenv; i++) { - off = alignto(off, decltype(env[i])); - htput(s->envoff, env[i], itop(off)); - off += size(env[i]); - } - free(env); + size_t nenv, i; + Node **env; + size_t off; + + env = getclosure(fn->func.scope, &nenv); + if (!env) + return; + /* + we need these in a deterministic order so that we can + put them in the right place both when we use them and + when we capture them. + */ + s->hasenv = 1; + qsort(env, nenv, sizeof(Node*), envcmp); + off = Ptrsz; /* we start with the size of the env */ + for (i = 0; i < nenv; i++) { + off = alignto(off, decltype(env[i])); + htput(s->envoff, env[i], itop(off)); + off += size(env[i]); + } + free(env); } static Func *simpfn(Simp *s, char *name, Node *dcl) { - Node *n; - size_t i; - Func *fn; - Cfg *cfg; - - n = dcl->decl.init; - if(debugopt['i'] || debugopt['F'] || debugopt['f']) - printf("\n\nfunction %s\n", name); - - /* set up the simp context */ - /* unwrap to the function body */ - n = n->expr.args[0]; - n = n->lit.fnval; - collectenv(s, n); - flatten(s, n); - - if (debugopt['f'] || debugopt['F']) - for (i = 0; i < s->nstmts; i++) - dump(s->stmts[i], stdout); - for (i = 0; i < s->nstmts; i++) { - if (s->stmts[i]->type != Nexpr) - continue; - if (debugopt['f']) { - printf("FOLD FROM ----------\n"); - dump(s->stmts[i], stdout); - } - s->stmts[i] = fold(s->stmts[i], 0); - if (debugopt['f']) { - printf("TO ------------\n"); - dump(s->stmts[i], stdout); - printf("DONE ----------------\n"); - } - } - - cfg = mkcfg(dcl, s->stmts, s->nstmts); - check(cfg); - if (debugopt['t'] || debugopt['s']) - dumpcfg(cfg, stdout); - - fn = zalloc(sizeof(Func)); - fn->name = strdup(name); - fn->type = dcl->decl.type; - fn->isexport = isexport(dcl); - fn->stksz = align(s->stksz, 8); - fn->stkoff = s->stkoff; - fn->envoff = s->envoff; - fn->ret = s->ret; - fn->args = s->args; - fn->nargs = s->nargs; - fn->cfg = cfg; - fn->hasenv = s->hasenv; - return fn; + Node *n; + size_t i; + Func *fn; + Cfg *cfg; + + n = dcl->decl.init; + if(debugopt['i'] || debugopt['F'] || debugopt['f']) + printf("\n\nfunction %s\n", name); + + /* set up the simp context */ + /* unwrap to the function body */ + n = n->expr.args[0]; + n = n->lit.fnval; + collectenv(s, n); + flatten(s, n); + + if (debugopt['f'] || debugopt['F']) + for (i = 0; i < s->nstmts; i++) + dump(s->stmts[i], stdout); + for (i = 0; i < s->nstmts; i++) { + if (s->stmts[i]->type != Nexpr) + continue; + if (debugopt['f']) { + printf("FOLD FROM ----------\n"); + dump(s->stmts[i], stdout); + } + s->stmts[i] = fold(s->stmts[i], 0); + if (debugopt['f']) { + printf("TO ------------\n"); + dump(s->stmts[i], stdout); + printf("DONE ----------------\n"); + } + } + + cfg = mkcfg(dcl, s->stmts, s->nstmts); + check(cfg); + if (debugopt['t'] || debugopt['s']) + dumpcfg(cfg, stdout); + + fn = zalloc(sizeof(Func)); + fn->name = strdup(name); + fn->type = dcl->decl.type; + fn->isexport = isexport(dcl); + fn->stksz = align(s->stksz, 8); + fn->stkoff = s->stkoff; + fn->envoff = s->envoff; + fn->ret = s->ret; + fn->args = s->args; + fn->nargs = s->nargs; + fn->cfg = cfg; + fn->hasenv = s->hasenv; + return fn; } static void extractsub(Simp *s, Node *e) { - size_t i; + size_t i; - assert(e != NULL); - switch (exprop(e)) { - case Oslice: - if (exprop(e->expr.args[0]) == Oarr) - e->expr.args[0] = simpblob(s, e->expr.args[0]); - break; - case Oarr: - case Ostruct: - for (i = 0; i < e->expr.nargs; i++) - extractsub(s, e->expr.args[i]); - break; - default: - break; - } + assert(e != NULL); + switch (exprop(e)) { + case Oslice: + if (exprop(e->expr.args[0]) == Oarr) + e->expr.args[0] = simpblob(s, e->expr.args[0]); + break; + case Oarr: + case Ostruct: + for (i = 0; i < e->expr.nargs; i++) + extractsub(s, e->expr.args[i]); + break; + default: + break; + } } static void simpconstinit(Simp *s, Node *dcl) { - Node *e; - - dcl->decl.init = fold(dcl->decl.init, 1);; - e = dcl->decl.init; - if (e && exprop(e) == Olit) { - if (e->expr.args[0]->lit.littype == Lfunc) - simpcode(s, e); - else - lappend(&s->blobs, &s->nblobs, dcl); - } else if (dcl->decl.isconst) { - switch (exprop(e)) { - case Oarr: - case Ostruct: - case Oslice: - extractsub(s, e); - lappend(&s->blobs, &s->nblobs, dcl); - break; - default: - fatal(dcl, "unsupported initializer for %s", declname(dcl)); - break; - } - } else if (!dcl->decl.isconst && !e) { - lappend(&s->blobs, &s->nblobs, dcl); - } else { - die("Non-constant initializer for %s\n", declname(dcl)); - } + Node *e; + + dcl->decl.init = fold(dcl->decl.init, 1);; + e = dcl->decl.init; + if (e && exprop(e) == Olit) { + if (e->expr.args[0]->lit.littype == Lfunc) + simpcode(s, e); + else + lappend(&s->blobs, &s->nblobs, dcl); + } else if (dcl->decl.isconst) { + switch (exprop(e)) { + case Oarr: + case Ostruct: + case Oslice: + extractsub(s, e); + lappend(&s->blobs, &s->nblobs, dcl); + break; + default: + fatal(dcl, "unsupported initializer for %s", declname(dcl)); + break; + } + } else if (!dcl->decl.isconst && !e) { + lappend(&s->blobs, &s->nblobs, dcl); + } else { + die("Non-constant initializer for %s\n", declname(dcl)); + } } int ismain(Node *dcl) { - Node *n; + Node *n; - n = dcl->decl.name; - if (n->name.ns) - return 0; - return strcmp(n->name.name, "main") == 0; + n = dcl->decl.name; + if (n->name.ns) + return 0; + return strcmp(n->name.name, "main") == 0; } void simpglobl(Node *dcl, Htab *globls, Func ***fn, size_t *nfn, Node ***blob, size_t *nblob) { - Simp s = {0,}; - char *name; - Func *f; - - if (ismain(dcl)) - dcl->decl.vis = Vishidden; - s.stkoff = mkht(varhash, vareq); - s.envoff = mkht(varhash, vareq); - s.globls = globls; - s.blobs = *blob; - s.nblobs = *nblob; - s.hasenv = 0; - name = asmname(dcl); - - if (dcl->decl.isextern || dcl->decl.isgeneric) - return; - if (isconstfn(dcl)) { - f = simpfn(&s, name, dcl); - lappend(fn, nfn, f); - } else { - simpconstinit(&s, dcl); - } - *blob = s.blobs; - *nblob = s.nblobs; - free(name); + Simp s = {0,}; + char *name; + Func *f; + + if (ismain(dcl)) + dcl->decl.vis = Vishidden; + s.stkoff = mkht(varhash, vareq); + s.envoff = mkht(varhash, vareq); + s.globls = globls; + s.blobs = *blob; + s.nblobs = *nblob; + s.hasenv = 0; + name = asmname(dcl); + + if (dcl->decl.isextern || dcl->decl.isgeneric) + return; + if (isconstfn(dcl)) { + f = simpfn(&s, name, dcl); + lappend(fn, nfn, f); + } else { + simpconstinit(&s, dcl); + } + *blob = s.blobs; + *nblob = s.nblobs; + free(name); } diff --git a/6/typeinfo.c b/6/typeinfo.c index 0f420cf..5a0cef2 100644 --- a/6/typeinfo.c +++ b/6/typeinfo.c @@ -21,353 +21,354 @@ Blob *tydescsub(Type *ty); size_t blobsz(Blob *b) { - size_t n; - size_t i; - - switch (b->type) { - case Bti8: return 1; break; - case Bti16: return 2; break; - case Bti32: return 4; break; - case Bti64: return 8; break; - case Btref: return 8; break; - case Btbytes: return b->bytes.len; break; - case Btimin: - if (b->ival >= 1ULL << 56) - die("packed int too big"); - - for (i = 1; i < 8; i++) - if (b->ival < 1ULL << (7*i)) - return i; - die("impossible blob size"); - break; - case Btseq: - n = 0; - for (i = 0; i < b->seq.nsub; i++) - n += blobsz(b->seq.sub[i]); - return n; - break; - default: - die("unknown blob type"); - } - return 0; + size_t n; + size_t i; + + switch (b->type) { + case Bti8: return 1; break; + case Bti16: return 2; break; + case Bti32: return 4; break; + case Bti64: return 8; break; + case Btref: return 8; break; + case Btbytes: return b->bytes.len; break; + case Btimin: + if (b->ival >= 1ULL << 56) + die("packed int too big"); + + for (i = 1; i < 8; i++) + if (b->ival < 1ULL << (7*i)) + return i; + die("impossible blob size"); + break; + case Btseq: + n = 0; + for (i = 0; i < b->seq.nsub; i++) + n += blobsz(b->seq.sub[i]); + return n; + break; + default: + die("unknown blob type"); + } + return 0; } void namevec(Blob ***sub, size_t *nsub, Node *n) { - char *buf; - size_t len; - - if (n->name.ns) { - len = strlen(n->name.name) + strlen(n->name.ns) + 1; - buf = xalloc(len + 1); - bprintf(buf, len + 1, "%s.%s", n->name.ns, n->name.name); - } else { - len = strlen(n->name.name); - buf = xalloc(len + 1); - bprintf(buf, len + 1, "%s", n->name.name); - } - lappend(sub, nsub, mkblobi(Btimin, len)); - lappend(sub, nsub, mkblobbytes(buf, len)); + char *buf; + size_t len; + + if (n->name.ns) { + len = strlen(n->name.name) + strlen(n->name.ns) + 1; + buf = xalloc(len + 1); + bprintf(buf, len + 1, "%s.%s", n->name.ns, n->name.name); + } else { + len = strlen(n->name.name); + buf = xalloc(len + 1); + bprintf(buf, len + 1, "%s", n->name.name); + } + lappend(sub, nsub, mkblobi(Btimin, len)); + lappend(sub, nsub, mkblobbytes(buf, len)); } static void structmemb(Blob ***sub, size_t *nsub, Node *sdecl) { - Blob *b; + Blob *b; - namevec(sub, nsub, sdecl->decl.name); - b = tydescsub(sdecl->decl.type); - lappend(sub, nsub, b); + namevec(sub, nsub, sdecl->decl.name); + b = tydescsub(sdecl->decl.type); + lappend(sub, nsub, b); } static void unionmemb(Blob ***sub, size_t *nsub, Ucon *ucon) { - namevec(sub, nsub, ucon->name); - if (ucon->etype) { - lappend(sub, nsub, tydescsub(ucon->etype)); - } else { - lappend(sub, nsub, mkblobi(Btimin, 1)); - lappend(sub, nsub, mkblobi(Bti8, Tybad)); - } + namevec(sub, nsub, ucon->name); + if (ucon->etype) { + lappend(sub, nsub, tydescsub(ucon->etype)); + } else { + lappend(sub, nsub, mkblobi(Btimin, 1)); + lappend(sub, nsub, mkblobi(Bti8, Tybad)); + } } static void encodetypeinfo(Blob ***sub, size_t *nsub, Type *t) { - lappend(sub, nsub, mkblobi(Btimin, tysize(t))); - lappend(sub, nsub, mkblobi(Btimin, tyalign(t))); + lappend(sub, nsub, mkblobi(Btimin, tysize(t))); + lappend(sub, nsub, mkblobi(Btimin, tyalign(t))); } Blob *tydescsub(Type *ty) { - Blob **sub, *sz, *bt, *b; - size_t i, nsub; - char buf[512]; - uint8_t tt; - Node *len; - - sub = NULL; - nsub = 0; - /* names are pulled out of line */ - tt = ty->type; - /* tyvars can get tagged, but aren't desired */ - if (ty->type == Tyvar) - return NULL; - - if (ty->type == Tyname) - tt |= Tdindirect; - sz = mkblobi(Btimin, 0); - bt = mkblobi(Bti8, tt); - lappend(&sub, &nsub, bt); - switch (ty->type) { - case Ntypes: case Tyvar: case Tybad: case Typaram: - case Tygeneric: case Tycode: case Tyunres: - die("invalid type in tydesc"); break; - - /* atomic types -- nothing else to do */ - case Tyvoid: case Tychar: case Tybool: case Tyint8: - case Tyint16: case Tyint: case Tyint32: case Tyint64: - case Tybyte: case Tyuint8: case Tyuint16: - case Tyuint: case Tyuint32: case Tyuint64: - case Tyflt32: case Tyflt64: case Tyvalist: - break; - - case Typtr: - lappend(&sub, &nsub, tydescsub(ty->sub[0])); - break; - case Tyslice: - lappend(&sub, &nsub, tydescsub(ty->sub[0])); - break; - case Tyarray: - encodetypeinfo(&sub, &nsub, ty); - ty->asize = fold(ty->asize, 1); - len = ty->asize; - if (len) { - assert(len->type == Nexpr); - len = len->expr.args[0]; - assert(len->type == Nlit && len->lit.littype == Lint); - lappend(&sub, &nsub, mkblobi(Btimin, len->lit.intval)); - } else { - lappend(&sub, &nsub, mkblobi(Btimin, 0)); - } - - lappend(&sub, &nsub, tydescsub(ty->sub[0])); - break; - case Tyfunc: - lappend(&sub, &nsub, mkblobi(Btimin, ty->nsub)); - for (i = 0; i < ty->nsub; i++) - lappend(&sub, &nsub, tydescsub(ty->sub[i])); - break; - case Tytuple: - encodetypeinfo(&sub, &nsub, ty); - lappend(&sub, &nsub, mkblobi(Btimin, ty->nsub)); - for (i = 0; i < ty->nsub; i++) - lappend(&sub, &nsub, tydescsub(ty->sub[i])); - break; - case Tystruct: - encodetypeinfo(&sub, &nsub, ty); - lappend(&sub, &nsub, mkblobi(Btimin, ty->nmemb)); - for (i = 0; i < ty->nmemb; i++) - structmemb(&sub, &nsub, ty->sdecls[i]); - break; - case Tyunion: - encodetypeinfo(&sub, &nsub, ty); - lappend(&sub, &nsub, mkblobi(Btimin, ty->nmemb)); - for (i = 0; i < ty->nmemb; i++) - unionmemb(&sub, &nsub, ty->udecls[i]); - break; - case Tyname: - i = bprintf(buf, sizeof buf, "%s", Symprefix); - tydescid(buf + i, sizeof buf - i, ty); - lappend(&sub, &nsub, mkblobref(buf, 0, ty->isimport || ty->vis == Visexport)); - break; - } - b = mkblobseq(sub, nsub); - sz->ival = blobsz(b); - linsert(&b->seq.sub, &b->seq.nsub, 0, sz); - return b; + Blob **sub, *sz, *bt, *b; + size_t i, nsub; + char buf[512]; + uint8_t tt; + Node *len; + + sub = NULL; + nsub = 0; + /* names are pulled out of line */ + tt = ty->type; + /* tyvars can get tagged, but aren't desired */ + if (ty->type == Tyvar) + return NULL; + + if (ty->type == Tyname) + tt |= Tdindirect; + sz = mkblobi(Btimin, 0); + bt = mkblobi(Bti8, tt); + lappend(&sub, &nsub, bt); + switch (ty->type) { + case Ntypes: case Tyvar: case Tybad: case Typaram: + case Tygeneric: case Tycode: case Tyunres: + die("invalid type in tydesc"); + break; + + /* atomic types -- nothing else to do */ + case Tyvoid: case Tychar: case Tybool: case Tyint8: + case Tyint16: case Tyint: case Tyint32: case Tyint64: + case Tybyte: case Tyuint8: case Tyuint16: + case Tyuint: case Tyuint32: case Tyuint64: + case Tyflt32: case Tyflt64: case Tyvalist: + break; + + case Typtr: + lappend(&sub, &nsub, tydescsub(ty->sub[0])); + break; + case Tyslice: + lappend(&sub, &nsub, tydescsub(ty->sub[0])); + break; + case Tyarray: + encodetypeinfo(&sub, &nsub, ty); + ty->asize = fold(ty->asize, 1); + len = ty->asize; + if (len) { + assert(len->type == Nexpr); + len = len->expr.args[0]; + assert(len->type == Nlit && len->lit.littype == Lint); + lappend(&sub, &nsub, mkblobi(Btimin, len->lit.intval)); + } else { + lappend(&sub, &nsub, mkblobi(Btimin, 0)); + } + + lappend(&sub, &nsub, tydescsub(ty->sub[0])); + break; + case Tyfunc: + lappend(&sub, &nsub, mkblobi(Btimin, ty->nsub)); + for (i = 0; i < ty->nsub; i++) + lappend(&sub, &nsub, tydescsub(ty->sub[i])); + break; + case Tytuple: + encodetypeinfo(&sub, &nsub, ty); + lappend(&sub, &nsub, mkblobi(Btimin, ty->nsub)); + for (i = 0; i < ty->nsub; i++) + lappend(&sub, &nsub, tydescsub(ty->sub[i])); + break; + case Tystruct: + encodetypeinfo(&sub, &nsub, ty); + lappend(&sub, &nsub, mkblobi(Btimin, ty->nmemb)); + for (i = 0; i < ty->nmemb; i++) + structmemb(&sub, &nsub, ty->sdecls[i]); + break; + case Tyunion: + encodetypeinfo(&sub, &nsub, ty); + lappend(&sub, &nsub, mkblobi(Btimin, ty->nmemb)); + for (i = 0; i < ty->nmemb; i++) + unionmemb(&sub, &nsub, ty->udecls[i]); + break; + case Tyname: + i = bprintf(buf, sizeof buf, "%s", Symprefix); + tydescid(buf + i, sizeof buf - i, ty); + lappend(&sub, &nsub, mkblobref(buf, 0, ty->isimport || ty->vis == Visexport)); + break; + } + b = mkblobseq(sub, nsub); + sz->ival = blobsz(b); + linsert(&b->seq.sub, &b->seq.nsub, 0, sz); + return b; } Blob *namedesc(Type *ty) { - Blob **sub; - size_t nsub; - - sub = NULL; - nsub = 0; - lappend(&sub, &nsub, mkblobi(Bti8, Tyname)); - namevec(&sub, &nsub, ty->name); - lappend(&sub, &nsub, tydescsub(ty->sub[0])); - return mkblobseq(sub, nsub); + Blob **sub; + size_t nsub; + + sub = NULL; + nsub = 0; + lappend(&sub, &nsub, mkblobi(Bti8, Tyname)); + namevec(&sub, &nsub, ty->name); + lappend(&sub, &nsub, tydescsub(ty->sub[0])); + return mkblobseq(sub, nsub); } Blob *tydescblob(Type *ty) { - char buf[512]; - Blob *b, *sz, *sub; - - if (ty->type == Tyname && hasparams(ty)) - return NULL; - - if (ty->type == Tyname) { - b = mkblobseq(NULL, 0); - sz = mkblobi(Btimin, 0); - sub = namedesc(ty); - sz->ival = blobsz(sub); - lappend(&b->seq.sub, &b->seq.nsub, sz); - lappend(&b->seq.sub, &b->seq.nsub, sub); - if (ty->vis == Visexport) - b->isglobl = 1; - } else { - b = tydescsub(ty); - } - tydescid(buf, sizeof buf, ty); - b->lbl = strdup(buf); - return b; + char buf[512]; + Blob *b, *sz, *sub; + + if (ty->type == Tyname && hasparams(ty)) + return NULL; + + if (ty->type == Tyname) { + b = mkblobseq(NULL, 0); + sz = mkblobi(Btimin, 0); + sub = namedesc(ty); + sz->ival = blobsz(sub); + lappend(&b->seq.sub, &b->seq.nsub, sz); + lappend(&b->seq.sub, &b->seq.nsub, sub); + if (ty->vis == Visexport) + b->isglobl = 1; + } else { + b = tydescsub(ty); + } + tydescid(buf, sizeof buf, ty); + b->lbl = strdup(buf); + return b; } size_t tysize(Type *t) { - size_t sz; - size_t i; - - sz = 0; - if (!t) - die("size of empty type => bailing."); - switch (t->type) { - case Tyvoid: - return 0; - case Tybool: case Tyint8: - case Tybyte: case Tyuint8: - return 1; - case Tyint16: case Tyuint16: - return 2; - case Tyint: case Tyint32: - case Tyuint: case Tyuint32: - case Tychar: /* utf32 */ - return 4; - - case Typtr: - case Tyvalist: /* ptr to first element of valist */ - return Ptrsz; - - case Tyint64: - case Tyuint64: - return 8; - - /*end integer types*/ - case Tyflt32: - return 4; - case Tyflt64: - return 8; - - case Tycode: - return Ptrsz; - case Tyfunc: - return 2*Ptrsz; - case Tyslice: - return 2*Ptrsz; /* len; ptr */ - case Tyname: - return tysize(t->sub[0]); - case Tyarray: - if (!t->asize) - return 0; - t->asize = fold(t->asize, 1); - assert(exprop(t->asize) == Olit); - return t->asize->expr.args[0]->lit.intval * tysize(t->sub[0]); - case Tytuple: - for (i = 0; i < t->nsub; i++) { - sz = alignto(sz, t->sub[i]); - sz += tysize(t->sub[i]); - } - sz = alignto(sz, t); - return sz; - break; - case Tystruct: - for (i = 0; i < t->nmemb; i++) { - sz = alignto(sz, decltype(t->sdecls[i])); - sz += size(t->sdecls[i]); - } - sz = alignto(sz, t); - return sz; - break; - case Tyunion: - sz = Wordsz; - for (i = 0; i < t->nmemb; i++) - if (t->udecls[i]->etype) - sz = max(sz, tysize(t->udecls[i]->etype) + Wordsz); - return align(sz, Ptrsz); - break; - case Tygeneric: case Tybad: case Tyvar: - case Typaram: case Tyunres: case Ntypes: - die("Type %s does not have size; why did it get down to here?", tystr(t)); - break; - } - return -1; + size_t sz; + size_t i; + + sz = 0; + if (!t) + die("size of empty type => bailing."); + switch (t->type) { + case Tyvoid: + return 0; + case Tybool: case Tyint8: + case Tybyte: case Tyuint8: + return 1; + case Tyint16: case Tyuint16: + return 2; + case Tyint: case Tyint32: + case Tyuint: case Tyuint32: + case Tychar: /* utf32 */ + return 4; + + case Typtr: + case Tyvalist: /* ptr to first element of valist */ + return Ptrsz; + + case Tyint64: + case Tyuint64: + return 8; + + /*end integer types*/ + case Tyflt32: + return 4; + case Tyflt64: + return 8; + + case Tycode: + return Ptrsz; + case Tyfunc: + return 2*Ptrsz; + case Tyslice: + return 2*Ptrsz; /* len; ptr */ + case Tyname: + return tysize(t->sub[0]); + case Tyarray: + if (!t->asize) + return 0; + t->asize = fold(t->asize, 1); + assert(exprop(t->asize) == Olit); + return t->asize->expr.args[0]->lit.intval * tysize(t->sub[0]); + case Tytuple: + for (i = 0; i < t->nsub; i++) { + sz = alignto(sz, t->sub[i]); + sz += tysize(t->sub[i]); + } + sz = alignto(sz, t); + return sz; + break; + case Tystruct: + for (i = 0; i < t->nmemb; i++) { + sz = alignto(sz, decltype(t->sdecls[i])); + sz += size(t->sdecls[i]); + } + sz = alignto(sz, t); + return sz; + break; + case Tyunion: + sz = Wordsz; + for (i = 0; i < t->nmemb; i++) + if (t->udecls[i]->etype) + sz = max(sz, tysize(t->udecls[i]->etype) + Wordsz); + return align(sz, Ptrsz); + break; + case Tygeneric: case Tybad: case Tyvar: + case Typaram: case Tyunres: case Ntypes: + die("Type %s does not have size; why did it get down to here?", tystr(t)); + break; + } + return -1; } size_t tyalign(Type *ty) { - size_t align, i; - - align = 1; - switch (ty->type) { - case Tyarray: - align = tyalign(ty->sub[0]); - break; - case Tytuple: - for (i = 0; i < ty->nsub; i++) - align = max(align, tyalign(ty->sub[0])); - break; - case Tyunion: - align = 4; - for (i = 0; i < ty->nmemb; i++) - if (ty->udecls[i]->etype) - align = max(align, tyalign(ty->udecls[i]->etype)); - break; - case Tystruct: - for (i = 0; i < ty->nmemb; i++) - align = max(align, tyalign(decltype(ty->sdecls[i]))); - break; - default: - align = tysize(ty); - } - return min(align, Ptrsz); + size_t align, i; + + align = 1; + switch (ty->type) { + case Tyarray: + align = tyalign(ty->sub[0]); + break; + case Tytuple: + for (i = 0; i < ty->nsub; i++) + align = max(align, tyalign(ty->sub[0])); + break; + case Tyunion: + align = 4; + for (i = 0; i < ty->nmemb; i++) + if (ty->udecls[i]->etype) + align = max(align, tyalign(ty->udecls[i]->etype)); + break; + case Tystruct: + for (i = 0; i < ty->nmemb; i++) + align = max(align, tyalign(decltype(ty->sdecls[i]))); + break; + default: + align = tysize(ty); + } + return min(align, Ptrsz); } /* gets the byte offset of 'memb' within the aggregate type 'aggr' */ ssize_t tyoffset(Type *ty, Node *memb) { - size_t i; - size_t off; - - ty = tybase(ty); - if (ty->type == Typtr) - ty = tybase(ty->sub[0]); - - assert(ty->type == Tystruct); - off = 0; - for (i = 0; i < ty->nmemb; i++) { - off = alignto(off, decltype(ty->sdecls[i])); - if (!strcmp(namestr(memb), declname(ty->sdecls[i]))) - return off; - off += size(ty->sdecls[i]); - } - die("bad offset"); - return 0; + size_t i; + size_t off; + + ty = tybase(ty); + if (ty->type == Typtr) + ty = tybase(ty->sub[0]); + + assert(ty->type == Tystruct); + off = 0; + for (i = 0; i < ty->nmemb; i++) { + off = alignto(off, decltype(ty->sdecls[i])); + if (!strcmp(namestr(memb), declname(ty->sdecls[i]))) + return off; + off += size(ty->sdecls[i]); + } + die("bad offset"); + return 0; } size_t size(Node *n) { - Type *t; + Type *t; - if (n->type == Nexpr) - t = n->expr.type; - else - t = n->decl.type; - return tysize(t); + if (n->type == Nexpr) + t = n->expr.type; + else + t = n->decl.type; + return tysize(t); } ssize_t offset(Node *aggr, Node *memb) { - return tyoffset(exprtype(aggr), memb); + return tyoffset(exprtype(aggr), memb); } diff --git a/bench/runner.c b/bench/runner.c deleted file mode 100644 index a43d65b..0000000 --- a/bench/runner.c +++ /dev/null @@ -1,84 +0,0 @@ -/* written in C instead of Myrddin because I don't have FP in Myrddin yet... */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define Nsamp 10 - -double run(char *prog) -{ - struct rusage ru; - double sec, usec; - int in, out; - char *cmd[2]; - int pid; - int status; - - sec = 0; - usec = 0; - pid = fork(); - if (pid < 0) { - err(1, "Could not fork\n"); - } else if (pid == 0) { - if ((in = open("/dev/zero", O_RDONLY)) < 0) - err(1, "could not open /dev/zero"); - if ((out = open("/dev/null", O_WRONLY)) < 0) - err(1, "could not open /dev/null"); - if (dup2(in, 0) < 0) - err(1, "could not reopen stdin"); - if (dup2(out, 1) < 0) - err(1, "could not reopen stdout"); - - cmd[0] = prog; - cmd[1] = NULL; - execv(prog, cmd); - err(1, "Failed to exec\n"); - } else { - wait4(pid, &status, 0, &ru); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - err(1, "Subprogram failed to execute\n"); - sec = ru.ru_utime.tv_sec; - usec = ru.ru_utime.tv_usec / (1000.0 * 1000.0); - } - return sec + usec; -} - -double timed_run(char *prog) -{ - double avg, m, d, x; - int i, n; - - avg = 0; - m = 0; - n = 0; - for (i = 0; i < Nsamp; i++) { - n++; - x = run(prog); - d = (x - avg); - avg += d/n; - m = m + d*(x - avg); - } - printf("%s:\t%fs (σ^2: %f)\n", prog, avg, m/(n-1)); - return avg; -} - -int main(int argc, char **argv) -{ - double tot; - int i; - - printf("Running benchmarks: %d samples per binary\n", Nsamp); - tot = 0; - for (i = 1; i < argc; i++) - tot += timed_run(argv[i]); - printf("total:\t%fs\n", tot); - return 0; -} - diff --git a/mi/cfg.c b/mi/cfg.c index 39b59fe..f5c6961 100644 --- a/mi/cfg.c +++ b/mi/cfg.c @@ -16,298 +16,298 @@ static Bb *mkbb(Cfg *cfg) { - Bb *bb; + Bb *bb; - bb = zalloc(sizeof(Bb)); - bb->id = cfg->nextbbid++; - bb->pred = mkbs(); - bb->succ = mkbs(); - lappend(&cfg->bb, &cfg->nbb, bb); - return bb; + bb = zalloc(sizeof(Bb)); + bb->id = cfg->nextbbid++; + bb->pred = mkbs(); + bb->succ = mkbs(); + lappend(&cfg->bb, &cfg->nbb, bb); + return bb; } static void strlabel(Cfg *cfg, char *lbl, Bb *bb) { - htput(cfg->lblmap, lbl, bb); - lappend(&bb->lbls, &bb->nlbls, lbl); + htput(cfg->lblmap, lbl, bb); + lappend(&bb->lbls, &bb->nlbls, lbl); } static void label(Cfg *cfg, Node *lbl, Bb *bb) { - strlabel(cfg, lblstr(lbl), bb); + strlabel(cfg, lblstr(lbl), bb); } static int isnonretcall(Node *fn) { - Node *dcl; + Node *dcl; - if (exprop(fn) != Ovar) - return 0; - dcl = decls[fn->expr.did]; - return dcl->decl.isnoret; + if (exprop(fn) != Ovar) + return 0; + dcl = decls[fn->expr.did]; + return dcl->decl.isnoret; } static int addnode(Cfg *cfg, Bb *bb, Node *n) { - switch (exprop(n)) { - case Ojmp: - case Ocjmp: - case Oret: - lappend(&bb->nl, &bb->nnl, n); - lappend(&cfg->fixjmp, &cfg->nfixjmp, n); - lappend(&cfg->fixblk, &cfg->nfixblk, bb); - return 1; - case Ocall: - lappend(&bb->nl, &bb->nnl, n); - return isnonretcall(n->expr.args[0]); - case Odead: - lappend(&bb->nl, &bb->nnl, n); - return 1; - default: - lappend(&bb->nl, &bb->nnl, n); - break; - } - return 0; + switch (exprop(n)) { + case Ojmp: + case Ocjmp: + case Oret: + lappend(&bb->nl, &bb->nnl, n); + lappend(&cfg->fixjmp, &cfg->nfixjmp, n); + lappend(&cfg->fixblk, &cfg->nfixblk, bb); + return 1; + case Ocall: + lappend(&bb->nl, &bb->nnl, n); + return isnonretcall(n->expr.args[0]); + case Odead: + lappend(&bb->nl, &bb->nnl, n); + return 1; + default: + lappend(&bb->nl, &bb->nnl, n); + break; + } + return 0; } static int islabel(Node *n) { - Node *l; - if (n->type != Nexpr) - return 0; - if (exprop(n) != Olit) - return 0; - l = n->expr.args[0]; - if (l->type != Nlit) - return 0; - if (l->lit.littype != Llbl) - return 0; - return 1; + Node *l; + if (n->type != Nexpr) + return 0; + if (exprop(n) != Olit) + return 0; + l = n->expr.args[0]; + if (l->type != Nlit) + return 0; + if (l->lit.littype != Llbl) + return 0; + return 1; } static Bb *addlabel(Cfg *cfg, Bb *bb, Node **nl, size_t i, Srcloc loc) { - /* if the current block assumes fall-through, insert an explicit jump */ - if (i > 0 && nl[i - 1]->type == Nexpr) { - if (exprop(nl[i - 1]) != Ocjmp && exprop(nl[i - 1]) != Ojmp) - addnode(cfg, bb, mkexpr(loc, Ojmp, mklbl(loc, lblstr(nl[i])), NULL)); - } - if (bb->nnl) - bb = mkbb(cfg); - label(cfg, nl[i], bb); - return bb; + /* if the current block assumes fall-through, insert an explicit jump */ + if (i > 0 && nl[i - 1]->type == Nexpr) { + if (exprop(nl[i - 1]) != Ocjmp && exprop(nl[i - 1]) != Ojmp) + addnode(cfg, bb, mkexpr(loc, Ojmp, mklbl(loc, lblstr(nl[i])), NULL)); + } + if (bb->nnl) + bb = mkbb(cfg); + label(cfg, nl[i], bb); + return bb; } void delete(Cfg *cfg, Bb *bb) { - size_t i, j; + size_t i, j; - if (bb == cfg->start || bb == cfg->end) - return; - for (i = 0; bsiter(bb->pred, &i); i++) { - bsunion(cfg->bb[i]->succ, bb->succ); - bsdel(cfg->bb[i]->succ, bb->id); - } - for (i = 0; bsiter(bb->succ, &i); i++) { - bsunion(cfg->bb[i]->pred, bb->pred); - bsdel(cfg->bb[i]->pred, bb->id); - for (j = 0; j < bb->nlbls; j++) - strlabel(cfg, bb->lbls[j], cfg->bb[i]); - } - cfg->bb[bb->id] = NULL; + if (bb == cfg->start || bb == cfg->end) + return; + for (i = 0; bsiter(bb->pred, &i); i++) { + bsunion(cfg->bb[i]->succ, bb->succ); + bsdel(cfg->bb[i]->succ, bb->id); + } + for (i = 0; bsiter(bb->succ, &i); i++) { + bsunion(cfg->bb[i]->pred, bb->pred); + bsdel(cfg->bb[i]->pred, bb->id); + for (j = 0; j < bb->nlbls; j++) + strlabel(cfg, bb->lbls[j], cfg->bb[i]); + } + cfg->bb[bb->id] = NULL; } void noexit(Cfg *cfg, Bb *bb) { - size_t i; - for (i = 0; bsiter(bb->succ, &i); i++) - bsdel(cfg->bb[i]->pred, bb->id); - bsclear(bb->succ); + size_t i; + for (i = 0; bsiter(bb->succ, &i); i++) + bsdel(cfg->bb[i]->pred, bb->id); + bsclear(bb->succ); } void trimdead(Cfg *cfg, Bb *bb) { - size_t i; + size_t i; - if (!bb) - return; - for (i = 0; i < bb->nnl; i++) { - switch (exprop(bb->nl[i])) { - /* if we're jumping, we can't keep going - * within this BB */ - case Ojmp: - case Ocjmp: - case Oret: - bb->nnl = i + 1; - return; - case Odead: - noexit(cfg, bb); - bb->nnl = i + 1; - return; - case Ocall: - if (isnonretcall(bb->nl[i]->expr.args[0])) { - noexit(cfg, bb); - bb->nnl = i + 1; - return; - } - break; - default: - /* nothing */ - break; - } - } + if (!bb) + return; + for (i = 0; i < bb->nnl; i++) { + switch (exprop(bb->nl[i])) { + /* if we're jumping, we can't keep going + * within this BB */ + case Ojmp: + case Ocjmp: + case Oret: + bb->nnl = i + 1; + return; + case Odead: + noexit(cfg, bb); + bb->nnl = i + 1; + return; + case Ocall: + if (isnonretcall(bb->nl[i]->expr.args[0])) { + noexit(cfg, bb); + bb->nnl = i + 1; + return; + } + break; + default: + /* nothing */ + break; + } + } } void trim(Cfg *cfg) { - Bb *bb; - size_t i; - int deleted; + Bb *bb; + size_t i; + int deleted; - deleted = 1; - while (deleted) { - deleted = 0; - for (i = 0; i < cfg->nbb; i++) { - bb = cfg->bb[i]; - if (bb == cfg->start || bb == cfg->end) - continue; - trimdead(cfg, bb); - if (bb && bsisempty(bb->pred)) { - delete(cfg, bb); - deleted = 1; - } - } - } + deleted = 1; + while (deleted) { + deleted = 0; + for (i = 0; i < cfg->nbb; i++) { + bb = cfg->bb[i]; + if (bb == cfg->start || bb == cfg->end) + continue; + trimdead(cfg, bb); + if (bb && bsisempty(bb->pred)) { + delete(cfg, bb); + deleted = 1; + } + } + } } Cfg *mkcfg(Node *fn, Node **nl, size_t nn) { - Cfg *cfg; - Bb *pre, *post; - Bb *bb, *targ; - Node *a, *b; - static int nextret; - char buf[32]; - size_t i; + Cfg *cfg; + Bb *pre, *post; + Bb *bb, *targ; + Node *a, *b; + static int nextret; + char buf[32]; + size_t i; - cfg = zalloc(sizeof(Cfg)); - cfg->fn = fn; - cfg->lblmap = mkht(strhash, streq); - pre = mkbb(cfg); - bb = mkbb(cfg); - for (i = 0; i < nn; i++) { - switch (nl[i]->type) { - case Nexpr: - if (islabel(nl[i])) - bb = addlabel(cfg, bb, nl, i, nl[i]->loc); - else if (addnode(cfg, bb, nl[i])) - bb = mkbb(cfg); - break; - break; - case Ndecl: - break; - default: - die("Invalid node type %s in mkcfg", nodestr[nl[i]->type]); - } - } - post = mkbb(cfg); - bprintf(buf, sizeof buf, ".R%d", nextret++); - label(cfg, mklbl(fn->loc, buf), post); + cfg = zalloc(sizeof(Cfg)); + cfg->fn = fn; + cfg->lblmap = mkht(strhash, streq); + pre = mkbb(cfg); + bb = mkbb(cfg); + for (i = 0; i < nn; i++) { + switch (nl[i]->type) { + case Nexpr: + if (islabel(nl[i])) + bb = addlabel(cfg, bb, nl, i, nl[i]->loc); + else if (addnode(cfg, bb, nl[i])) + bb = mkbb(cfg); + break; + break; + case Ndecl: + break; + default: + die("Invalid node type %s in mkcfg", nodestr[nl[i]->type]); + } + } + post = mkbb(cfg); + bprintf(buf, sizeof buf, ".R%d", nextret++); + label(cfg, mklbl(fn->loc, buf), post); - cfg->start = pre; - cfg->end = post; - bsput(pre->succ, cfg->bb[1]->id); - bsput(cfg->bb[1]->pred, pre->id); - bsput(cfg->bb[cfg->nbb - 2]->succ, post->id); - bsput(post->pred, cfg->bb[cfg->nbb - 2]->id); + cfg->start = pre; + cfg->end = post; + bsput(pre->succ, cfg->bb[1]->id); + bsput(cfg->bb[1]->pred, pre->id); + bsput(cfg->bb[cfg->nbb - 2]->succ, post->id); + bsput(post->pred, cfg->bb[cfg->nbb - 2]->id); - for (i = 0; i < cfg->nfixjmp; i++) { - bb = cfg->fixblk[i]; - switch (exprop(cfg->fixjmp[i])) { - case Ojmp: - a = cfg->fixjmp[i]->expr.args[0]; - b = NULL; - break; - case Ocjmp: - a = cfg->fixjmp[i]->expr.args[1]; - b = cfg->fixjmp[i]->expr.args[2]; - break; - case Oret: - a = mklbl(cfg->fixjmp[i]->loc, cfg->end->lbls[0]); - b = NULL; - break; - default: - die("Bad jump fix thingy"); - break; - } - if (a) { - targ = htget(cfg->lblmap, lblstr(a)); - if (!targ) - die("No bb with label \"%s\"", lblstr(a)); - bsput(bb->succ, targ->id); - bsput(targ->pred, bb->id); - } - if (b) { - targ = htget(cfg->lblmap, lblstr(b)); - if (!targ) - die("No bb with label \"%s\"", lblstr(b)); - bsput(bb->succ, targ->id); - bsput(targ->pred, bb->id); - } - } - trim(cfg); - return cfg; + for (i = 0; i < cfg->nfixjmp; i++) { + bb = cfg->fixblk[i]; + switch (exprop(cfg->fixjmp[i])) { + case Ojmp: + a = cfg->fixjmp[i]->expr.args[0]; + b = NULL; + break; + case Ocjmp: + a = cfg->fixjmp[i]->expr.args[1]; + b = cfg->fixjmp[i]->expr.args[2]; + break; + case Oret: + a = mklbl(cfg->fixjmp[i]->loc, cfg->end->lbls[0]); + b = NULL; + break; + default: + die("Bad jump fix thingy"); + break; + } + if (a) { + targ = htget(cfg->lblmap, lblstr(a)); + if (!targ) + die("No bb with label \"%s\"", lblstr(a)); + bsput(bb->succ, targ->id); + bsput(targ->pred, bb->id); + } + if (b) { + targ = htget(cfg->lblmap, lblstr(b)); + if (!targ) + die("No bb with label \"%s\"", lblstr(b)); + bsput(bb->succ, targ->id); + bsput(targ->pred, bb->id); + } + } + trim(cfg); + return cfg; } void dumpbb(Bb *bb, FILE *fd) { - size_t i; - char *sep; + size_t i; + char *sep; - fprintf(fd, "Bb: %d labels=(", bb->id); - sep = ""; - for (i = 0; i < bb->nlbls; i++) {; - fprintf(fd, "%s%s", bb->lbls[i], sep); - sep = ","; - } - fprintf(fd, ")\n"); + fprintf(fd, "Bb: %d labels=(", bb->id); + sep = ""; + for (i = 0; i < bb->nlbls; i++) {; + fprintf(fd, "%s%s", bb->lbls[i], sep); + sep = ","; + } + fprintf(fd, ")\n"); - /* in edges */ - fprintf(fd, "Pred: "); - sep = ""; - for (i = 0; i < bsmax(bb->pred); i++) { - if (bshas(bb->pred, i)) { - fprintf(fd, "%s%zd", sep, i); - sep = ","; - } - } - fprintf(fd, "\n"); + /* in edges */ + fprintf(fd, "Pred: "); + sep = ""; + for (i = 0; i < bsmax(bb->pred); i++) { + if (bshas(bb->pred, i)) { + fprintf(fd, "%s%zd", sep, i); + sep = ","; + } + } + fprintf(fd, "\n"); - /* out edges */ - fprintf(fd, "Succ: "); - sep = ""; - for (i = 0; i < bsmax(bb->succ); i++) { - if (bshas(bb->succ, i)) { - fprintf(fd, "%s%zd", sep, i); - sep = ","; - } - } - fprintf(fd, "\n"); + /* out edges */ + fprintf(fd, "Succ: "); + sep = ""; + for (i = 0; i < bsmax(bb->succ); i++) { + if (bshas(bb->succ, i)) { + fprintf(fd, "%s%zd", sep, i); + sep = ","; + } + } + fprintf(fd, "\n"); - for (i = 0; i < bb->nnl; i++) - dump(bb->nl[i], fd); - fprintf(fd, "\n"); + for (i = 0; i < bb->nnl; i++) + dump(bb->nl[i], fd); + fprintf(fd, "\n"); } void dumpcfg(Cfg *cfg, FILE *fd) { - size_t i; + size_t i; - for (i = 0; i < cfg->nbb; i++) { - if (!cfg->bb[i]) - continue; - fprintf(fd, "\n"); - dumpbb(cfg->bb[i], fd); - } + for (i = 0; i < cfg->nbb; i++) { + if (!cfg->bb[i]) + continue; + fprintf(fd, "\n"); + dumpbb(cfg->bb[i], fd); + } } diff --git a/mi/dfcheck.c b/mi/dfcheck.c index 316bf65..a83f1db 100644 --- a/mi/dfcheck.c +++ b/mi/dfcheck.c @@ -15,117 +15,117 @@ static void checkundef(Node *n, Reaching *r, Bitset *reach, Bitset *kill) { - size_t i, j, did; - Node *def; - Type *t; + size_t i, j, did; + Node *def; + Type *t; - if (n->type != Nexpr) - return; - if (exprop(n) == Ovar) { - did = n->expr.did; - for (j = 0; j < r->ndefs[did]; j++) { - t = tybase(exprtype(n)); - if (t->type == Tystruct || t->type == Tyunion || t->type == Tyarray || t->type == Tytuple) - continue; - if (bshas(kill, r->defs[did][j])) - continue; - if (!bshas(reach, r->defs[did][j])) - continue; - def = nodes[r->defs[did][j]]; - if (exprop(def) == Oundef) - fatal(n, "%s used before definition", namestr(n->expr.args[0])); - } - } else { - switch (exprop(n)) { - case Oset: - case Oasn: - case Oblit: - checkundef(n->expr.args[1], r, reach, kill); - break; - case Oaddr: - case Oslice: - /* these don't actually look at the of args[0], so they're ok. */ - for (i = 1; i < n->expr.nargs; i++) - checkundef(n->expr.args[i], r, reach, kill); - break; - case Ocall: - for (i = 1; i < n->expr.nargs; i++) - if (exprop(n->expr.args[i]) != Oaddr) - checkundef(n->expr.args[i], r, reach, kill); - break; - default: - for (i = 0; i < n->expr.nargs; i++) - checkundef(n->expr.args[i], r, reach, kill); - break; - } - } + if (n->type != Nexpr) + return; + if (exprop(n) == Ovar) { + did = n->expr.did; + for (j = 0; j < r->ndefs[did]; j++) { + t = tybase(exprtype(n)); + if (t->type == Tystruct || t->type == Tyunion || t->type == Tyarray || t->type == Tytuple) + continue; + if (bshas(kill, r->defs[did][j])) + continue; + if (!bshas(reach, r->defs[did][j])) + continue; + def = nodes[r->defs[did][j]]; + if (exprop(def) == Oundef) + fatal(n, "%s used before definition", namestr(n->expr.args[0])); + } + } else { + switch (exprop(n)) { + case Oset: + case Oasn: + case Oblit: + checkundef(n->expr.args[1], r, reach, kill); + break; + case Oaddr: + case Oslice: + /* these don't actually look at the of args[0], so they're ok. */ + for (i = 1; i < n->expr.nargs; i++) + checkundef(n->expr.args[i], r, reach, kill); + break; + case Ocall: + for (i = 1; i < n->expr.nargs; i++) + if (exprop(n->expr.args[i]) != Oaddr) + checkundef(n->expr.args[i], r, reach, kill); + break; + default: + for (i = 0; i < n->expr.nargs; i++) + checkundef(n->expr.args[i], r, reach, kill); + break; + } + } } static void checkreach(Cfg *cfg) { - Bitset *reach, *kill; - size_t i, j, k; - Reaching *r; - Node *n, *m; - Bb *bb; + Bitset *reach, *kill; + size_t i, j, k; + Reaching *r; + Node *n, *m; + Bb *bb; - r = reaching(cfg); - for (i = 0; i < cfg->nbb; i++) { - bb = cfg->bb[i]; - if (!bb) - continue; - reach = bsdup(r->in[i]); - kill = mkbs(); - for (j = 0; j < bb->nnl; j++) { - n = bb->nl[j]; - if (exprop(n) == Oundef) { - bsput(reach, n->nid); - } else { - m = assignee(n); - if (m) - for (k = 0; k < r->ndefs[m->expr.did]; k++) - bsput(kill, r->defs[m->expr.did][k]); - checkundef(n, r, reach, kill); - } - } - bsfree(reach); - bsfree(kill); - } + r = reaching(cfg); + for (i = 0; i < cfg->nbb; i++) { + bb = cfg->bb[i]; + if (!bb) + continue; + reach = bsdup(r->in[i]); + kill = mkbs(); + for (j = 0; j < bb->nnl; j++) { + n = bb->nl[j]; + if (exprop(n) == Oundef) { + bsput(reach, n->nid); + } else { + m = assignee(n); + if (m) + for (k = 0; k < r->ndefs[m->expr.did]; k++) + bsput(kill, r->defs[m->expr.did][k]); + checkundef(n, r, reach, kill); + } + } + bsfree(reach); + bsfree(kill); + } } static void checkpredret(Cfg *cfg, Bb *bb) { - Bb *pred; - Op op; - size_t i; + Bb *pred; + Op op; + size_t i; - for (i = 0; bsiter(bb->pred, &i); i++) { - pred = cfg->bb[i]; - if (pred->nnl == 0) { - checkpredret(cfg, pred); - } else { - op = exprop(pred->nl[pred->nnl - 1]); - if (op != Oret && op != Odead) { - fatal(pred->nl[pred->nnl-1], "Reaches end of function without return\n"); - } - } - } + for (i = 0; bsiter(bb->pred, &i); i++) { + pred = cfg->bb[i]; + if (pred->nnl == 0) { + checkpredret(cfg, pred); + } else { + op = exprop(pred->nl[pred->nnl - 1]); + if (op != Oret && op != Odead) { + fatal(pred->nl[pred->nnl-1], "Reaches end of function without return\n"); + } + } + } } static void checkret(Cfg *cfg) { - Type *ft; + Type *ft; - ft = tybase(decltype(cfg->fn)); - assert(ft->type == Tyfunc || ft->type == Tycode); - if (ft->sub[0]->type == Tyvoid) - return; + ft = tybase(decltype(cfg->fn)); + assert(ft->type == Tyfunc || ft->type == Tycode); + if (ft->sub[0]->type == Tyvoid) + return; - checkpredret(cfg, cfg->end); + checkpredret(cfg, cfg->end); } void check(Cfg *cfg) { - checkret(cfg); - if(0) checkreach(cfg); + checkret(cfg); + if(0) checkreach(cfg); } diff --git a/mi/fold.c b/mi/fold.c index 2658431..f62e440 100644 --- a/mi/fold.c +++ b/mi/fold.c @@ -15,226 +15,226 @@ static int getintlit(Node *n, vlong *v) { - Node *l; - - if (exprop(n) != Olit) - return 0; - l = n->expr.args[0]; - if (l->lit.littype != Lint) - return 0; - *v = l->lit.intval; - return 1; + Node *l; + + if (exprop(n) != Olit) + return 0; + l = n->expr.args[0]; + if (l->lit.littype != Lint) + return 0; + *v = l->lit.intval; + return 1; } static int isintval(Node *n, vlong val) { - vlong v; + vlong v; - if (!getintlit(n, &v)) - return 0; - return v == val; + if (!getintlit(n, &v)) + return 0; + return v == val; } static Node *val(Srcloc loc, vlong val, Type *t) { - Node *l, *n; + Node *l, *n; - l = mkint(loc, val); - n = mkexpr(loc, Olit, l, NULL); - l->lit.type = t; - n->expr.type = t; - return n; + l = mkint(loc, val); + n = mkexpr(loc, Olit, l, NULL); + l->lit.type = t; + n->expr.type = t; + return n; } static int issmallconst(Node *dcl) { - Type *t; - - if (!dcl->decl.isconst) - return 0; - if (!dcl->decl.init) - return 0; - t = tybase(exprtype(dcl->decl.init)); - if (t->type <= Tyflt64) - return 1; - return 0; + Type *t; + + if (!dcl->decl.isconst) + return 0; + if (!dcl->decl.init) + return 0; + t = tybase(exprtype(dcl->decl.init)); + if (t->type <= Tyflt64) + return 1; + return 0; } static Node *foldcast(Node *n) { - Type *to, *from; - Node *sub; - - sub = n->expr.args[0]; - to = exprtype(n); - from = exprtype(sub); - - switch (tybase(to)->type) { - case Tybool: - case Tyint8: case Tyint16: case Tyint32: case Tyint64: - case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64: - case Tyint: case Tyuint: case Tychar: case Tybyte: - case Typtr: - switch (tybase(from)->type) { - case Tybool: - case Tyint8: case Tyint16: case Tyint32: case Tyint64: - case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64: - case Tyint: case Tyuint: case Tychar: case Tybyte: - case Typtr: - if (exprop(sub) == Olit || tybase(from)->type == tybase(to)->type) { - sub->expr.type = to; - return sub; - } else { - return n; - } - default: - return n; - } - default: - return n; - } - return n; + Type *to, *from; + Node *sub; + + sub = n->expr.args[0]; + to = exprtype(n); + from = exprtype(sub); + + switch (tybase(to)->type) { + case Tybool: + case Tyint8: case Tyint16: case Tyint32: case Tyint64: + case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64: + case Tyint: case Tyuint: case Tychar: case Tybyte: + case Typtr: + switch (tybase(from)->type) { + case Tybool: + case Tyint8: case Tyint16: case Tyint32: case Tyint64: + case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64: + case Tyint: case Tyuint: case Tychar: case Tybyte: + case Typtr: + if (exprop(sub) == Olit || tybase(from)->type == tybase(to)->type) { + sub->expr.type = to; + return sub; + } else { + return n; + } + default: + return n; + } + default: + return n; + } + return n; } int idxcmp(const void *pa, const void *pb) { - Node *a, *b; - vlong av, bv; - - a = *(Node **)pa; - b = *(Node **)pb; - - assert(getintlit(a->expr.idx, &av)); - assert(getintlit(b->expr.idx, &bv)); - - /* don't trust overflow with int64 */ - if (av < bv) - return -1; - else if (av == bv) - return 0; - else - return 1; + Node *a, *b; + vlong av, bv; + + a = *(Node **)pa; + b = *(Node **)pb; + + assert(getintlit(a->expr.idx, &av)); + assert(getintlit(b->expr.idx, &bv)); + + /* don't trust overflow with int64 */ + if (av < bv) + return -1; + else if (av == bv) + return 0; + else + return 1; } Node *fold(Node *n, int foldvar) { - Node **args, *r; - Type *t; - vlong a, b; - size_t i; - - if (!n) - return NULL; - if (n->type != Nexpr) - return n; - - r = NULL; - args = n->expr.args; - if (n->expr.idx) - n->expr.idx = fold(n->expr.idx, foldvar); - for (i = 0; i < n->expr.nargs; i++) - args[i] = fold(args[i], foldvar); - switch (exprop(n)) { - case Ovar: - if (foldvar && issmallconst(decls[n->expr.did])) - r = fold(decls[n->expr.did]->decl.init, foldvar); - break; - case Oadd: - /* x + 0 = 0 */ - if (isintval(args[0], 0)) - r = args[1]; - if (isintval(args[1], 0)) - r = args[0]; - if (getintlit(args[0], &a) && getintlit(args[1], &b)) - r = val(n->loc, a + b, exprtype(n)); - break; - case Osub: - /* x - 0 = 0 */ - if (isintval(args[1], 0)) - r = args[0]; - if (getintlit(args[0], &a) && getintlit(args[1], &b)) - r = val(n->loc, a - b, exprtype(n)); - break; - case Omul: - /* 1 * x = x */ - if (isintval(args[0], 1)) - r = args[1]; - if (isintval(args[1], 1)) - r = args[0]; - /* 0 * x = 0 */ - if (isintval(args[0], 0)) - r = args[0]; - if (isintval(args[1], 0)) - r = args[1]; - if (getintlit(args[0], &a) && getintlit(args[1], &b)) - r = val(n->loc, a * b, exprtype(n)); - break; - case Odiv: - /* x/0 = error */ - if (isintval(args[1], 0)) - fatal(args[1], "division by zero"); - /* x/1 = x */ - if (isintval(args[1], 1)) - r = args[0]; - /* 0/x = 0 */ - if (isintval(args[1], 0)) - r = args[1]; - if (getintlit(args[0], &a) && getintlit(args[1], &b)) - r = val(n->loc, a / b, exprtype(n)); - break; - case Omod: - /* x%1 = x */ - if (isintval(args[1], 0)) - r = args[0]; - if (getintlit(args[0], &a) && getintlit(args[1], &b)) - r = val(n->loc, a % b, exprtype(n)); - break; - case Oneg: - if (getintlit(args[0], &a)) - r = val(n->loc, -a, exprtype(n)); - break; - case Obsl: - if (getintlit(args[0], &a) && getintlit(args[1], &b)) - r = val(n->loc, a << b, exprtype(n)); - break; - case Obsr: - if (getintlit(args[0], &a) && getintlit(args[1], &b)) - r = val(n->loc, a >> b, exprtype(n)); - break; - case Obor: - if (getintlit(args[0], &a) && getintlit(args[1], &b)) - r = val(n->loc, a | b, exprtype(n)); - break; - case Oband: - if (getintlit(args[0], &a) && getintlit(args[1], &b)) - r = val(n->loc, a & b, exprtype(n)); - break; - case Obxor: - if (getintlit(args[0], &a) && getintlit(args[1], &b)) - r = val(n->loc, a ^ b, exprtype(n)); - break; - case Omemb: - t = tybase(exprtype(args[0])); - /* we only fold lengths right now */ - if (t->type == Tyarray && !strcmp(namestr(args[1]), "len")) - r = t->asize; - break; - case Oarr: - qsort(n->expr.args, n->expr.nargs, sizeof(Node*), idxcmp); - break; - case Ocast: - r = foldcast(n); - break; - default: - break; - } - - if (r && n->expr.idx) - r->expr.idx = n->expr.idx; - - if (r) - return r; - else - return n; + Node **args, *r; + Type *t; + vlong a, b; + size_t i; + + if (!n) + return NULL; + if (n->type != Nexpr) + return n; + + r = NULL; + args = n->expr.args; + if (n->expr.idx) + n->expr.idx = fold(n->expr.idx, foldvar); + for (i = 0; i < n->expr.nargs; i++) + args[i] = fold(args[i], foldvar); + switch (exprop(n)) { + case Ovar: + if (foldvar && issmallconst(decls[n->expr.did])) + r = fold(decls[n->expr.did]->decl.init, foldvar); + break; + case Oadd: + /* x + 0 = 0 */ + if (isintval(args[0], 0)) + r = args[1]; + if (isintval(args[1], 0)) + r = args[0]; + if (getintlit(args[0], &a) && getintlit(args[1], &b)) + r = val(n->loc, a + b, exprtype(n)); + break; + case Osub: + /* x - 0 = 0 */ + if (isintval(args[1], 0)) + r = args[0]; + if (getintlit(args[0], &a) && getintlit(args[1], &b)) + r = val(n->loc, a - b, exprtype(n)); + break; + case Omul: + /* 1 * x = x */ + if (isintval(args[0], 1)) + r = args[1]; + if (isintval(args[1], 1)) + r = args[0]; + /* 0 * x = 0 */ + if (isintval(args[0], 0)) + r = args[0]; + if (isintval(args[1], 0)) + r = args[1]; + if (getintlit(args[0], &a) && getintlit(args[1], &b)) + r = val(n->loc, a * b, exprtype(n)); + break; + case Odiv: + /* x/0 = error */ + if (isintval(args[1], 0)) + fatal(args[1], "division by zero"); + /* x/1 = x */ + if (isintval(args[1], 1)) + r = args[0]; + /* 0/x = 0 */ + if (isintval(args[1], 0)) + r = args[1]; + if (getintlit(args[0], &a) && getintlit(args[1], &b)) + r = val(n->loc, a / b, exprtype(n)); + break; + case Omod: + /* x%1 = x */ + if (isintval(args[1], 0)) + r = args[0]; + if (getintlit(args[0], &a) && getintlit(args[1], &b)) + r = val(n->loc, a % b, exprtype(n)); + break; + case Oneg: + if (getintlit(args[0], &a)) + r = val(n->loc, -a, exprtype(n)); + break; + case Obsl: + if (getintlit(args[0], &a) && getintlit(args[1], &b)) + r = val(n->loc, a << b, exprtype(n)); + break; + case Obsr: + if (getintlit(args[0], &a) && getintlit(args[1], &b)) + r = val(n->loc, a >> b, exprtype(n)); + break; + case Obor: + if (getintlit(args[0], &a) && getintlit(args[1], &b)) + r = val(n->loc, a | b, exprtype(n)); + break; + case Oband: + if (getintlit(args[0], &a) && getintlit(args[1], &b)) + r = val(n->loc, a & b, exprtype(n)); + break; + case Obxor: + if (getintlit(args[0], &a) && getintlit(args[1], &b)) + r = val(n->loc, a ^ b, exprtype(n)); + break; + case Omemb: + t = tybase(exprtype(args[0])); + /* we only fold lengths right now */ + if (t->type == Tyarray && !strcmp(namestr(args[1]), "len")) + r = t->asize; + break; + case Oarr: + qsort(n->expr.args, n->expr.nargs, sizeof(Node*), idxcmp); + break; + case Ocast: + r = foldcast(n); + break; + default: + break; + } + + if (r && n->expr.idx) + r->expr.idx = n->expr.idx; + + if (r) + return r; + else + return n; } diff --git a/mi/match.c b/mi/match.c index 2588f59..df335f8 100644 --- a/mi/match.c +++ b/mi/match.c @@ -14,26 +14,26 @@ typedef struct Dtree Dtree; struct Dtree { - int id; - Srcloc loc; - - /* values for matching */ - Node *lbl; - Node *load; - size_t nconstructors; - int accept; - int emitted; - - /* the decision tree step */ - Node **pat; - size_t npat; - Dtree **next; - size_t nnext; - Dtree *any; - - /* captured variables and action */ - Node **cap; - size_t ncap; + int id; + Srcloc loc; + + /* values for matching */ + Node *lbl; + Node *load; + size_t nconstructors; + int accept; + int emitted; + + /* the decision tree step */ + Node **pat; + size_t npat; + Dtree **next; + size_t nnext; + Dtree *any; + + /* captured variables and action */ + Node **cap; + size_t ncap; }; @@ -44,752 +44,752 @@ void dtreedump(FILE *fd, Dtree *dt); static Node *utag(Node *n) { - Node *tag; + Node *tag; - tag = mkexpr(n->loc, Outag, n, NULL); - tag->expr.type = mktype(n->loc, Tyint32); - return tag; + tag = mkexpr(n->loc, Outag, n, NULL); + tag->expr.type = mktype(n->loc, Tyint32); + return tag; } static Node *uvalue(Node *n, Type *ty) { - Node *elt; + Node *elt; - elt = mkexpr(n->loc, Oudata, n, NULL); - elt->expr.type = ty; - return elt; + elt = mkexpr(n->loc, Oudata, n, NULL); + elt->expr.type = ty; + return elt; } static Node *tupelt(Node *n, size_t i) { - Node *idx, *elt; + Node *idx, *elt; - idx = mkintlit(n->loc, i); - idx->expr.type = mktype(n->loc, Tyuint64); - elt = mkexpr(n->loc, Otupget, n, idx, NULL); - elt->expr.type = tybase(exprtype(n))->sub[i]; - return elt; + idx = mkintlit(n->loc, i); + idx->expr.type = mktype(n->loc, Tyuint64); + elt = mkexpr(n->loc, Otupget, n, idx, NULL); + elt->expr.type = tybase(exprtype(n))->sub[i]; + return elt; } static Node *arrayelt(Node *n, size_t i) { - Node *idx, *elt; + Node *idx, *elt; - idx = mkintlit(n->loc, i); - idx->expr.type = mktype(n->loc, Tyuint64); - elt = mkexpr(n->loc, Oidx, n, idx, NULL); - elt->expr.type = tybase(exprtype(n))->sub[0]; - return elt; + idx = mkintlit(n->loc, i); + idx->expr.type = mktype(n->loc, Tyuint64); + elt = mkexpr(n->loc, Oidx, n, idx, NULL); + elt->expr.type = tybase(exprtype(n))->sub[0]; + return elt; } static Node *findmemb(Node *pat, Node *name) { - Node *n; - size_t i; - - for (i = 0; i < pat->expr.nargs; i++) { - n = pat->expr.args[i]; - if (nameeq(n->expr.idx, name)) - return n; - } - return NULL; + Node *n; + size_t i; + + for (i = 0; i < pat->expr.nargs; i++) { + n = pat->expr.args[i]; + if (nameeq(n->expr.idx, name)) + return n; + } + return NULL; } static Dtree *dtbytag(Dtree *t, Ucon *uc) { - uint32_t tagval; - Node *taglit; - size_t i; - - for (i = 0; i < t->npat; i++) { - taglit = t->pat[i]->expr.args[0]; - tagval = taglit->lit.intval; - if (tagval == uc->id) { - return t->next[i]; - } - } - return NULL; + uint32_t tagval; + Node *taglit; + size_t i; + + for (i = 0; i < t->npat; i++) { + taglit = t->pat[i]->expr.args[0]; + tagval = taglit->lit.intval; + if (tagval == uc->id) { + return t->next[i]; + } + } + return NULL; } static Node *structmemb(Node *n, Node *name, Type *ty) { - Node *elt; + Node *elt; - elt = mkexpr(n->loc, Omemb, n, name, NULL); - elt->expr.type = ty; - return elt; + elt = mkexpr(n->loc, Omemb, n, name, NULL); + elt->expr.type = ty; + return elt; } static Node *addcapture(Node *n, Node **cap, size_t ncap) { - Node **blk; - size_t nblk, i; - - nblk = 0; - blk = NULL; - - for (i = 0; i < ncap; i++) - lappend(&blk, &nblk, cap[i]); - for (i = 0; i < n->block.nstmts; i++) - lappend(&blk, &nblk, n->block.stmts[i]); - lfree(&n->block.stmts, &n->block.nstmts); - n->block.stmts = blk; - n->block.nstmts = nblk; - return n; + Node **blk; + size_t nblk, i; + + nblk = 0; + blk = NULL; + + for (i = 0; i < ncap; i++) + lappend(&blk, &nblk, cap[i]); + for (i = 0; i < n->block.nstmts; i++) + lappend(&blk, &nblk, n->block.stmts[i]); + lfree(&n->block.stmts, &n->block.nstmts); + n->block.stmts = blk; + n->block.nstmts = nblk; + return n; } static Dtree *mkdtree(Srcloc loc, Node *lbl) { - static int ndtree; - Dtree *t; - - t = zalloc(sizeof(Dtree)); - t->lbl = lbl; - t->loc = loc; - t->id = ndtree++; - return t; + static int ndtree; + Dtree *t; + + t = zalloc(sizeof(Dtree)); + t->lbl = lbl; + t->loc = loc; + t->id = ndtree++; + return t; } static Dtree *nextnode(Srcloc loc, size_t idx, size_t count, Dtree *accept) { - if (idx == count - 1) - return accept; - else - return mkdtree(loc, genlbl(loc)); + if (idx == count - 1) + return accept; + else + return mkdtree(loc, genlbl(loc)); } static size_t nconstructors(Type *t) { - if (!t) - return 0; - - t = tybase(t); - switch (t->type) { - case Tyvoid: return 0; break; - case Tybool: return 2; break; - case Tychar: return 0x10ffff; break; - - /* signed ints */ - case Tyint8: return 0x100; break; - case Tyint16: return 0x10000; break; - case Tyint32: return 0x100000000; break; - case Tyint: return 0x100000000; break; - case Tyint64: return ~0ull; break; - - /* unsigned ints */ - case Tybyte: return 0x100; break; - case Tyuint8: return 0x100; break; - case Tyuint16: return 0x10000; break; - case Tyuint32: return 0x100000000; break; - case Tyuint: return 0x100000000; break; - case Tyuint64: return ~0ull; break; - - /* floats */ - case Tyflt32: return ~0ull; break; - case Tyflt64: return ~0ull; break; - - /* complex types */ - case Typtr: return 1; break; - case Tyarray: return 1; break; - case Tytuple: return 1; break; - case Tystruct: return 1; - case Tyunion: return t->nmemb; break; - case Tyslice: return ~0ULL; break; - - case Tyvar: case Typaram: case Tyunres: case Tyname: - case Tybad: case Tyvalist: case Tygeneric: case Ntypes: - case Tyfunc: case Tycode: - die("Invalid constructor type %s in match", tystr(t)); - break; - } - return 0; + if (!t) + return 0; + + t = tybase(t); + switch (t->type) { + case Tyvoid: return 0; break; + case Tybool: return 2; break; + case Tychar: return 0x10ffff; break; + + /* signed ints */ + case Tyint8: return 0x100; break; + case Tyint16: return 0x10000; break; + case Tyint32: return 0x100000000; break; + case Tyint: return 0x100000000; break; + case Tyint64: return ~0ull; break; + + /* unsigned ints */ + case Tybyte: return 0x100; break; + case Tyuint8: return 0x100; break; + case Tyuint16: return 0x10000; break; + case Tyuint32: return 0x100000000; break; + case Tyuint: return 0x100000000; break; + case Tyuint64: return ~0ull; break; + + /* floats */ + case Tyflt32: return ~0ull; break; + case Tyflt64: return ~0ull; break; + + /* complex types */ + case Typtr: return 1; break; + case Tyarray: return 1; break; + case Tytuple: return 1; break; + case Tystruct: return 1; + case Tyunion: return t->nmemb; break; + case Tyslice: return ~0ULL; break; + + case Tyvar: case Typaram: case Tyunres: case Tyname: + case Tybad: case Tyvalist: case Tygeneric: case Ntypes: + case Tyfunc: case Tycode: + die("Invalid constructor type %s in match", tystr(t)); + break; + } + return 0; } static int verifymatch(Dtree *t) { - size_t i; - int ret; - - if (t->accept) - return 1; - - ret = 0; - if (t->nnext == t->nconstructors || t->any) - ret = 1; - for (i = 0; i < t->nnext; i++) - if (!verifymatch(t->next[i])) - ret = 0; - return ret; + size_t i; + int ret; + + if (t->accept) + return 1; + + ret = 0; + if (t->nnext == t->nconstructors || t->any) + ret = 1; + for (i = 0; i < t->nnext; i++) + if (!verifymatch(t->next[i])) + ret = 0; + return ret; } static int acceptall(Dtree *t, Dtree *accept) { - size_t i; - int ret; - - if (t->any == accept) - return 0; - - ret = 0; - if (t->any) { - if (acceptall(t->any, accept)) - ret = 1; - } else { - t->any = accept; - ret = 1; - } - - for (i = 0; i < t->nnext; i++) - if (acceptall(t->next[i], accept)) - ret = 1; - return ret; + size_t i; + int ret; + + if (t->any == accept) + return 0; + + ret = 0; + if (t->any) { + if (acceptall(t->any, accept)) + ret = 1; + } else { + t->any = accept; + ret = 1; + } + + for (i = 0; i < t->nnext; i++) + if (acceptall(t->next[i], accept)) + ret = 1; + return ret; } static int addwildrec(Srcloc loc, Type *ty, Dtree *start, Dtree *accept, Dtree ***end, size_t *nend) { - Dtree *next, **last, **tail; - size_t i, j, nelt, nlast, ntail; - Node *asize; - Ucon *uc; - int ret; - - tail = NULL; - ntail = 0; - ty = tybase(ty); - if (istyprimitive(ty)) { - for (i = 0; i < start->nnext; i++) - lappend(end, nend, start->next[i]); - if (start->any) { - lappend(end, nend, start->any); - return 0; - } else { - start->any = accept; - lappend(end, nend, accept); - return 1; - } - } - - ret = 0; - last = NULL; - nlast = 0; - lappend(&last, &nlast, start); - switch (ty->type) { - case Tytuple: - for (i = 0; i < ty->nsub; i++) { - next = nextnode(loc, i, ty->nsub, accept); - tail = NULL; - ntail = 0; - for (j = 0; j < nlast; j++) - if (addwildrec(loc, ty->sub[i], last[j], next, &tail, &ntail)) - ret = 1; - lfree(&last, &nlast); - last = tail; - nlast = ntail; - } - break; - case Tyarray: - asize = fold(ty->asize, 1); - nelt = asize->expr.args[0]->lit.intval; - for (i = 0; i < nelt; i++) { - next = nextnode(loc, i, nelt, accept); - tail = NULL; - ntail = 0; - for (j = 0; j < nlast; j++) - if (addwildrec(loc, ty->sub[0], last[j], next, &tail, &ntail)) - ret = 1; - lfree(&last, &nlast); - last = tail; - nlast = ntail; - } - break; - case Tystruct: - for (i = 0; i < ty->nmemb; i++) { - next = nextnode(loc, i, ty->nmemb, accept); - tail = NULL; - ntail = 0; - for (j = 0; j < nlast; j++) - if (addwildrec(loc, decltype(ty->sdecls[i]), last[j], next, &tail, &ntail)) - ret = 1; - lfree(&last, &nlast); - last = tail; - nlast = ntail; - } - break; - case Tyunion: - for (i = 0; i < ty->nmemb; i++) { - uc = ty->udecls[i]; - next = dtbytag(start, uc); - if (next) { - if (uc->etype) { - if (addwildrec(loc, uc->etype, next, accept, end, nend)) - ret = 1; - } else { - lappend(end, nend, next); - } - } - } - if (!start->any) { - start->any = accept; - ret = 1; - } - lappend(end, nend, start->any); - break; - case Tyslice: - ret = acceptall(start, accept); - lappend(&last, &nlast, accept); - break; - default: - lappend(&last, &nlast, accept); - break; - } - lcat(end, nend, last, nlast); - lfree(&last, &nlast); - return ret; + Dtree *next, **last, **tail; + size_t i, j, nelt, nlast, ntail; + Node *asize; + Ucon *uc; + int ret; + + tail = NULL; + ntail = 0; + ty = tybase(ty); + if (istyprimitive(ty)) { + for (i = 0; i < start->nnext; i++) + lappend(end, nend, start->next[i]); + if (start->any) { + lappend(end, nend, start->any); + return 0; + } else { + start->any = accept; + lappend(end, nend, accept); + return 1; + } + } + + ret = 0; + last = NULL; + nlast = 0; + lappend(&last, &nlast, start); + switch (ty->type) { + case Tytuple: + for (i = 0; i < ty->nsub; i++) { + next = nextnode(loc, i, ty->nsub, accept); + tail = NULL; + ntail = 0; + for (j = 0; j < nlast; j++) + if (addwildrec(loc, ty->sub[i], last[j], next, &tail, &ntail)) + ret = 1; + lfree(&last, &nlast); + last = tail; + nlast = ntail; + } + break; + case Tyarray: + asize = fold(ty->asize, 1); + nelt = asize->expr.args[0]->lit.intval; + for (i = 0; i < nelt; i++) { + next = nextnode(loc, i, nelt, accept); + tail = NULL; + ntail = 0; + for (j = 0; j < nlast; j++) + if (addwildrec(loc, ty->sub[0], last[j], next, &tail, &ntail)) + ret = 1; + lfree(&last, &nlast); + last = tail; + nlast = ntail; + } + break; + case Tystruct: + for (i = 0; i < ty->nmemb; i++) { + next = nextnode(loc, i, ty->nmemb, accept); + tail = NULL; + ntail = 0; + for (j = 0; j < nlast; j++) + if (addwildrec(loc, decltype(ty->sdecls[i]), last[j], next, &tail, &ntail)) + ret = 1; + lfree(&last, &nlast); + last = tail; + nlast = ntail; + } + break; + case Tyunion: + for (i = 0; i < ty->nmemb; i++) { + uc = ty->udecls[i]; + next = dtbytag(start, uc); + if (next) { + if (uc->etype) { + if (addwildrec(loc, uc->etype, next, accept, end, nend)) + ret = 1; + } else { + lappend(end, nend, next); + } + } + } + if (!start->any) { + start->any = accept; + ret = 1; + } + lappend(end, nend, start->any); + break; + case Tyslice: + ret = acceptall(start, accept); + lappend(&last, &nlast, accept); + break; + default: + lappend(&last, &nlast, accept); + break; + } + lcat(end, nend, last, nlast); + lfree(&last, &nlast); + return ret; } static int addwild(Node *pat, Node *val, Dtree *start, Dtree *accept, Node ***cap, size_t *ncap, Dtree ***end, size_t *nend) { - Node *asn; - - asn = mkexpr(pat->loc, Oasn, pat, val, NULL); - asn->expr.type = exprtype(pat); - if (cap && ncap) { - asn = mkexpr(pat->loc, Oasn, pat, val, NULL); - asn->expr.type = exprtype(pat); - lappend(cap, ncap, asn); - } - return addwildrec(pat->loc, exprtype(pat), start, accept, end, nend); + Node *asn; + + asn = mkexpr(pat->loc, Oasn, pat, val, NULL); + asn->expr.type = exprtype(pat); + if (cap && ncap) { + asn = mkexpr(pat->loc, Oasn, pat, val, NULL); + asn->expr.type = exprtype(pat); + lappend(cap, ncap, asn); + } + return addwildrec(pat->loc, exprtype(pat), start, accept, end, nend); } static int addunion(Node *pat, Node *val, Dtree *start, Dtree *accept, Node ***cap, size_t *ncap, Dtree ***end, size_t *nend) { - Node *tagid; - Dtree *next; - Ucon *uc; - - if (start->any) { - lappend(end, nend, start->any); - return 0; - } - - uc = finducon(tybase(exprtype(pat)), pat->expr.args[0]); - next = dtbytag(start, uc); - if (next) { - if (!uc->etype) { - lappend(end, nend, next); - return 0; - } else { - return addpat(pat->expr.args[1], uvalue(val, uc->etype), next, accept, cap, ncap, end, nend); - } - } - - if (!start->load) { - start->load = utag(val); - start->nconstructors = nconstructors(tybase(exprtype(pat))); - } - - tagid = mkintlit(pat->loc, uc->id); - tagid->expr.type = mktype(pat->loc, Tyint32); - lappend(&start->pat, &start->npat, tagid); - if (uc->etype) { - next = mkdtree(pat->loc, genlbl(pat->loc)); - lappend(&start->next, &start->nnext, next); - addpat(pat->expr.args[1], uvalue(val, uc->etype), next, accept, cap, ncap, end, nend); - } else { - lappend(&start->next, &start->nnext, accept); - lappend(end, nend, accept); - } - return 1; + Node *tagid; + Dtree *next; + Ucon *uc; + + if (start->any) { + lappend(end, nend, start->any); + return 0; + } + + uc = finducon(tybase(exprtype(pat)), pat->expr.args[0]); + next = dtbytag(start, uc); + if (next) { + if (!uc->etype) { + lappend(end, nend, next); + return 0; + } else { + return addpat(pat->expr.args[1], uvalue(val, uc->etype), next, accept, cap, ncap, end, nend); + } + } + + if (!start->load) { + start->load = utag(val); + start->nconstructors = nconstructors(tybase(exprtype(pat))); + } + + tagid = mkintlit(pat->loc, uc->id); + tagid->expr.type = mktype(pat->loc, Tyint32); + lappend(&start->pat, &start->npat, tagid); + if (uc->etype) { + next = mkdtree(pat->loc, genlbl(pat->loc)); + lappend(&start->next, &start->nnext, next); + addpat(pat->expr.args[1], uvalue(val, uc->etype), next, accept, cap, ncap, end, nend); + } else { + lappend(&start->next, &start->nnext, accept); + lappend(end, nend, accept); + } + return 1; } static int addstr(Node *pat, Node *val, Dtree *start, Dtree *accept, Node ***cap, size_t *ncap, Dtree ***end, size_t *nend) { - Dtree **tail, **last, *next; - size_t i, j, n, ntail, nlast; - Node *p, *v, *lit; - Type *ty; - char *s; - int ret; - - lit = pat->expr.args[0]; - n = lit->lit.strval.len; - s = lit->lit.strval.buf; - - ty = mktype(pat->loc, Tyuint64); - p = mkintlit(lit->loc, n); - v = structmemb(val, mkname(pat->loc, "len"), ty); - p->expr.type = ty; - - if (n == 0) - next = accept; - else - next = mkdtree(pat->loc, genlbl(pat->loc)); - - last = NULL; - nlast = 0; - if (addpat(p, v, start, next, cap, ncap, &last, &nlast)) - ret = 1; - - ty = mktype(pat->loc, Tybyte); - for (i = 0; i < n; i++) { - p = mkintlit(lit->loc, s[i]); - p->expr.type = ty; - v = arrayelt(val, i); - - tail = NULL; - ntail = 0; - next = nextnode(pat->loc, i, n, accept); - for (j = 0; j < nlast; j++) - if (addpat(p, v, last[j], next, NULL, NULL, &tail, &ntail)) - ret = 1; - lfree(&last, &nlast); - last = tail; - nlast = ntail; - } - lcat(end, nend, last, nlast); - lfree(&last, &nlast); - return ret; + Dtree **tail, **last, *next; + size_t i, j, n, ntail, nlast; + Node *p, *v, *lit; + Type *ty; + char *s; + int ret; + + lit = pat->expr.args[0]; + n = lit->lit.strval.len; + s = lit->lit.strval.buf; + + ty = mktype(pat->loc, Tyuint64); + p = mkintlit(lit->loc, n); + v = structmemb(val, mkname(pat->loc, "len"), ty); + p->expr.type = ty; + + if (n == 0) + next = accept; + else + next = mkdtree(pat->loc, genlbl(pat->loc)); + + last = NULL; + nlast = 0; + if (addpat(p, v, start, next, cap, ncap, &last, &nlast)) + ret = 1; + + ty = mktype(pat->loc, Tybyte); + for (i = 0; i < n; i++) { + p = mkintlit(lit->loc, s[i]); + p->expr.type = ty; + v = arrayelt(val, i); + + tail = NULL; + ntail = 0; + next = nextnode(pat->loc, i, n, accept); + for (j = 0; j < nlast; j++) + if (addpat(p, v, last[j], next, NULL, NULL, &tail, &ntail)) + ret = 1; + lfree(&last, &nlast); + last = tail; + nlast = ntail; + } + lcat(end, nend, last, nlast); + lfree(&last, &nlast); + return ret; } static int addlit(Node *pat, Node *val, Dtree *start, Dtree *accept, Node ***cap, size_t *ncap, Dtree ***end, size_t *nend) { - size_t i; - - if (pat->expr.args[0]->lit.littype == Lstr) { - return addstr(pat, val, start, accept, cap, ncap, end, nend); - } else { - /* if we already have a match, we're not adding a new node */ - if (start->any) { - lappend(end, nend, start->any); - return 0; - } - - for (i = 0; i < start->npat; i++) { - if (liteq(start->pat[i]->expr.args[0], pat->expr.args[0])) { - lappend(end, nend, start->next[i]); - return 0; - } - } - - /* wire up an edge from start to 'accept' */ - if (!start->load) { - start->load = val; - start->nconstructors = nconstructors(exprtype(pat)); - } - lappend(&start->pat, &start->npat, pat); - lappend(&start->next, &start->nnext, accept); - lappend(end, nend, accept); - return 1; - } + size_t i; + + if (pat->expr.args[0]->lit.littype == Lstr) { + return addstr(pat, val, start, accept, cap, ncap, end, nend); + } else { + /* if we already have a match, we're not adding a new node */ + if (start->any) { + lappend(end, nend, start->any); + return 0; + } + + for (i = 0; i < start->npat; i++) { + if (liteq(start->pat[i]->expr.args[0], pat->expr.args[0])) { + lappend(end, nend, start->next[i]); + return 0; + } + } + + /* wire up an edge from start to 'accept' */ + if (!start->load) { + start->load = val; + start->nconstructors = nconstructors(exprtype(pat)); + } + lappend(&start->pat, &start->npat, pat); + lappend(&start->next, &start->nnext, accept); + lappend(end, nend, accept); + return 1; + } } static int addtup(Node *pat, Node *val, Dtree *start, Dtree *accept, Node ***cap, size_t *ncap, Dtree ***end, size_t *nend) { - size_t nargs, nlast, ntail, i, j; - Dtree *next, **last, **tail; - Node **args; - int ret; - - args = pat->expr.args; - nargs = pat->expr.nargs; - last = NULL; - nlast = 0; - lappend(&last, &nlast, start); - ret = 0; - - for (i = 0; i < nargs; i++) { - next = nextnode(args[i]->loc, i, nargs, accept); - tail = NULL; - ntail = 0; - for (j = 0; j < nlast; j++) - if (addpat(pat->expr.args[i], tupelt(val, i), last[j], next, cap, ncap, &tail, &ntail)) - ret = 1; - lfree(&last, &nlast); - last = tail; - nlast = ntail; - } - lcat(end, nend, last, nlast); - lfree(&last, &nlast); - return ret; + size_t nargs, nlast, ntail, i, j; + Dtree *next, **last, **tail; + Node **args; + int ret; + + args = pat->expr.args; + nargs = pat->expr.nargs; + last = NULL; + nlast = 0; + lappend(&last, &nlast, start); + ret = 0; + + for (i = 0; i < nargs; i++) { + next = nextnode(args[i]->loc, i, nargs, accept); + tail = NULL; + ntail = 0; + for (j = 0; j < nlast; j++) + if (addpat(pat->expr.args[i], tupelt(val, i), last[j], next, cap, ncap, &tail, &ntail)) + ret = 1; + lfree(&last, &nlast); + last = tail; + nlast = ntail; + } + lcat(end, nend, last, nlast); + lfree(&last, &nlast); + return ret; } static int addarr(Node *pat, Node *val, Dtree *start, Dtree *accept, Node ***cap, size_t *ncap, Dtree ***end, size_t *nend) { - size_t nargs, nlast, ntail, i, j; - Dtree *next, **last, **tail; - Node **args; - int ret; - - args = pat->expr.args; - nargs = pat->expr.nargs; - last = NULL; - nlast = 0; - lappend(&last, &nlast, start); - ret = 0; - - for (i = 0; i < nargs; i++) { - next = nextnode(args[i]->loc, i, nargs, accept); - tail = NULL; - ntail = 0; - for (j = 0; j < nlast; j++) - if (addpat(pat->expr.args[i], arrayelt(val, i), last[j], next, cap, ncap, &tail, &ntail)) - ret = 1; - lfree(&last, &nlast); - last = tail; - nlast = ntail; - } - lcat(end, nend, last, nlast); - lfree(&last, &nlast); - return ret; + size_t nargs, nlast, ntail, i, j; + Dtree *next, **last, **tail; + Node **args; + int ret; + + args = pat->expr.args; + nargs = pat->expr.nargs; + last = NULL; + nlast = 0; + lappend(&last, &nlast, start); + ret = 0; + + for (i = 0; i < nargs; i++) { + next = nextnode(args[i]->loc, i, nargs, accept); + tail = NULL; + ntail = 0; + for (j = 0; j < nlast; j++) + if (addpat(pat->expr.args[i], arrayelt(val, i), last[j], next, cap, ncap, &tail, &ntail)) + ret = 1; + lfree(&last, &nlast); + last = tail; + nlast = ntail; + } + lcat(end, nend, last, nlast); + lfree(&last, &nlast); + return ret; } static int addstruct(Node *pat, Node *val, Dtree *start, Dtree *accept, Node ***cap, size_t *ncap, Dtree ***end, size_t *nend) { - Dtree *next, **last, **tail; - Node *memb, *name; - Type *ty, *mty; - size_t i, j, ntail, nlast; - int ret; - - ret = 0; - last = NULL; - nlast = 0; - lappend(&last, &nlast, start); - ty = tybase(exprtype(pat)); - - for (i = 0; i < ty->nmemb; i++) { - mty = decltype(ty->sdecls[i]); - name = ty->sdecls[i]->decl.name; - memb = findmemb(pat, name); - next = nextnode(pat->loc, i, ty->nmemb, accept); - tail = NULL; - ntail = 0; - - for (j = 0; j < nlast; j++) { - /* add a _ capture if we don't specify the value */ - if (!memb) { - if (addwild(memb, NULL, last[j], next, NULL, NULL, &tail, &ntail)) - ret = 1; - } else { - if (addpat(memb, structmemb(val, name, mty), last[j], next, cap, ncap, &tail, &ntail)) - ret = 1; - } - } - lfree(&last, &nlast); - last = tail; - nlast = ntail; - } - lcat(end, nend, last, nlast); - lfree(&last, &nlast); - return ret; + Dtree *next, **last, **tail; + Node *memb, *name; + Type *ty, *mty; + size_t i, j, ntail, nlast; + int ret; + + ret = 0; + last = NULL; + nlast = 0; + lappend(&last, &nlast, start); + ty = tybase(exprtype(pat)); + + for (i = 0; i < ty->nmemb; i++) { + mty = decltype(ty->sdecls[i]); + name = ty->sdecls[i]->decl.name; + memb = findmemb(pat, name); + next = nextnode(pat->loc, i, ty->nmemb, accept); + tail = NULL; + ntail = 0; + + for (j = 0; j < nlast; j++) { + /* add a _ capture if we don't specify the value */ + if (!memb) { + if (addwild(memb, NULL, last[j], next, NULL, NULL, &tail, &ntail)) + ret = 1; + } else { + if (addpat(memb, structmemb(val, name, mty), last[j], next, cap, ncap, &tail, &ntail)) + ret = 1; + } + } + lfree(&last, &nlast); + last = tail; + nlast = ntail; + } + lcat(end, nend, last, nlast); + lfree(&last, &nlast); + return ret; } static int addpat(Node *pat, Node *val, Dtree *start, Dtree *accept, Node ***cap, size_t *ncap, Dtree ***end, size_t *nend) { - int ret; - Node *dcl; - - pat = fold(pat, 1); - ret = 0; - switch (exprop(pat)) { - case Ovar: - dcl = decls[pat->expr.did]; - if (dcl->decl.isconst) - ret = addpat(dcl->decl.init, val, start, accept, cap, ncap, end, nend); - else - ret = addwild(pat, val, start, accept, cap, ncap, end, nend); - break; - case Oucon: - ret = addunion(pat, val, start, accept, cap, ncap, end, nend); - break; - case Olit: - ret = addlit(pat, val, start, accept, cap, ncap, end, nend); - break; - case Otup: - ret = addtup(pat, val, start, accept, cap, ncap, end, nend); - break; - case Oarr: - ret = addarr(pat, val, start, accept, cap, ncap, end, nend); - break; - case Ostruct: - ret = addstruct(pat, val, start, accept, cap, ncap, end, nend); - break; - case Ogap: - ret = addwild(pat, NULL, start, accept, NULL, NULL, end, nend); - break; - default: - fatal(pat, "unsupported pattern %s of type %s", opstr[exprop(pat)], tystr(exprtype(pat))); - break; - } - return ret; + int ret; + Node *dcl; + + pat = fold(pat, 1); + ret = 0; + switch (exprop(pat)) { + case Ovar: + dcl = decls[pat->expr.did]; + if (dcl->decl.isconst) + ret = addpat(dcl->decl.init, val, start, accept, cap, ncap, end, nend); + else + ret = addwild(pat, val, start, accept, cap, ncap, end, nend); + break; + case Oucon: + ret = addunion(pat, val, start, accept, cap, ncap, end, nend); + break; + case Olit: + ret = addlit(pat, val, start, accept, cap, ncap, end, nend); + break; + case Otup: + ret = addtup(pat, val, start, accept, cap, ncap, end, nend); + break; + case Oarr: + ret = addarr(pat, val, start, accept, cap, ncap, end, nend); + break; + case Ostruct: + ret = addstruct(pat, val, start, accept, cap, ncap, end, nend); + break; + case Ogap: + ret = addwild(pat, NULL, start, accept, NULL, NULL, end, nend); + break; + default: + fatal(pat, "unsupported pattern %s of type %s", opstr[exprop(pat)], tystr(exprtype(pat))); + break; + } + return ret; } /* val must be a pure, fully evaluated value */ Dtree *gendtree(Node *m, Node *val, Node **lbl, size_t nlbl) { - Dtree *start, *accept, **end; - Node **pat, **cap; - size_t npat, ncap, nend; - size_t i; - - pat = m->matchstmt.matches; - npat = m->matchstmt.nmatches; - - end = NULL; - nend = 0; - start = mkdtree(m->loc, genlbl(m->loc)); - for (i = 0; i < npat; i++) { - cap = NULL; - ncap = 0; - accept = mkdtree(lbl[i]->loc, lbl[i]); - accept->accept = 1; - - if (!addpat(pat[i]->match.pat, val, start, accept, &cap, &ncap, &end, &nend)) - fatal(pat[i], "pattern matched by earlier case"); - addcapture(pat[i]->match.block, cap, ncap); - } - if (!verifymatch(start)) - fatal(m, "nonexhaustive pattern set in match statement"); - return start; + Dtree *start, *accept, **end; + Node **pat, **cap; + size_t npat, ncap, nend; + size_t i; + + pat = m->matchstmt.matches; + npat = m->matchstmt.nmatches; + + end = NULL; + nend = 0; + start = mkdtree(m->loc, genlbl(m->loc)); + for (i = 0; i < npat; i++) { + cap = NULL; + ncap = 0; + accept = mkdtree(lbl[i]->loc, lbl[i]); + accept->accept = 1; + + if (!addpat(pat[i]->match.pat, val, start, accept, &cap, &ncap, &end, &nend)) + fatal(pat[i], "pattern matched by earlier case"); + addcapture(pat[i]->match.block, cap, ncap); + } + if (!verifymatch(start)) + fatal(m, "nonexhaustive pattern set in match statement"); + return start; } void genmatchcode(Dtree *dt, Node ***out, size_t *nout) { - Node *jmp, *eq, *fail; - int emit; - size_t i; - - if (dt->emitted) - return; - dt->emitted = 1; - - /* the we jump to the accept label when generating the parent */ - if (dt->accept) { - jmp = mkexpr(dt->loc, Ojmp, dt->lbl, NULL); - jmp->expr.type = mktype(dt->loc, Tyvoid); - lappend(out, nout, jmp); - return; - } - - lappend(out, nout, dt->lbl); - for (i = 0; i < dt->nnext; i++) { - if (i == dt->nnext - 1 && dt->any) { - fail = dt->any->lbl; - emit = 0; - } else { - fail = genlbl(dt->loc); - emit = 1; - } - - eq = mkexpr(dt->loc, Oeq, dt->load, dt->pat[i], NULL); - eq->expr.type = mktype(dt->loc, Tybool); - jmp = mkexpr(dt->loc, Ocjmp, eq, dt->next[i]->lbl, fail, NULL); - jmp->expr.type = mktype(dt->loc, Tyvoid); - lappend(out, nout, jmp); - - genmatchcode(dt->next[i], out, nout); - if (emit) - lappend(out, nout, fail); - } - if (dt->any) { - jmp = mkexpr(dt->loc, Ojmp, dt->any->lbl, NULL); - jmp->expr.type = mktype(dt->loc, Tyvoid); - lappend(out, nout, jmp); - genmatchcode(dt->any, out, nout); - } + Node *jmp, *eq, *fail; + int emit; + size_t i; + + if (dt->emitted) + return; + dt->emitted = 1; + + /* the we jump to the accept label when generating the parent */ + if (dt->accept) { + jmp = mkexpr(dt->loc, Ojmp, dt->lbl, NULL); + jmp->expr.type = mktype(dt->loc, Tyvoid); + lappend(out, nout, jmp); + return; + } + + lappend(out, nout, dt->lbl); + for (i = 0; i < dt->nnext; i++) { + if (i == dt->nnext - 1 && dt->any) { + fail = dt->any->lbl; + emit = 0; + } else { + fail = genlbl(dt->loc); + emit = 1; + } + + eq = mkexpr(dt->loc, Oeq, dt->load, dt->pat[i], NULL); + eq->expr.type = mktype(dt->loc, Tybool); + jmp = mkexpr(dt->loc, Ocjmp, eq, dt->next[i]->lbl, fail, NULL); + jmp->expr.type = mktype(dt->loc, Tyvoid); + lappend(out, nout, jmp); + + genmatchcode(dt->next[i], out, nout); + if (emit) + lappend(out, nout, fail); + } + if (dt->any) { + jmp = mkexpr(dt->loc, Ojmp, dt->any->lbl, NULL); + jmp->expr.type = mktype(dt->loc, Tyvoid); + lappend(out, nout, jmp); + genmatchcode(dt->any, out, nout); + } } void genonematch(Node *pat, Node *val, Node *iftrue, Node *iffalse, Node ***out, size_t *nout, Node ***cap, size_t *ncap) { - Dtree *start, *accept, *reject, **end; - size_t nend; + Dtree *start, *accept, *reject, **end; + size_t nend; - end = NULL; - nend = 0; + end = NULL; + nend = 0; - start = mkdtree(pat->loc, genlbl(pat->loc)); - accept = mkdtree(iftrue->loc, iftrue); - accept->accept = 1; - reject = mkdtree(iffalse->loc, iffalse); - reject->accept = 1; + start = mkdtree(pat->loc, genlbl(pat->loc)); + accept = mkdtree(iftrue->loc, iftrue); + accept->accept = 1; + reject = mkdtree(iffalse->loc, iffalse); + reject->accept = 1; - assert(addpat(pat, val, start, accept, cap, ncap, &end, &nend)); - acceptall(start, reject); - genmatchcode(start, out, nout); + assert(addpat(pat, val, start, accept, cap, ncap, &end, &nend)); + acceptall(start, reject); + genmatchcode(start, out, nout); } void genmatch(Node *m, Node *val, Node ***out, size_t *nout) { - Node **pat, **lbl, *end, *endlbl; - size_t npat, nlbl, i; - Dtree *dt; - - lbl = NULL; - nlbl = 0; - - pat = m->matchstmt.matches; - npat = m->matchstmt.nmatches; - for (i = 0; i < npat; i++) - lappend(&lbl, &nlbl, genlbl(pat[i]->match.block->loc)); - - - endlbl = genlbl(m->loc); - dt = gendtree(m, val, lbl, nlbl); - genmatchcode(dt, out, nout); - - for (i = 0; i < npat; i++) { - end = mkexpr(pat[i]->loc, Ojmp, endlbl, NULL); - end->expr.type = mktype(end->loc, Tyvoid); - lappend(out, nout, lbl[i]); - lappend(out, nout, pat[i]->match.block); - lappend(out, nout, end); - } - lappend(out, nout, endlbl); - - if (debugopt['m']) { - dtreedump(stdout, dt); - for (i = 0; i < *nout; i++) - dump((*out)[i], stdout); - } + Node **pat, **lbl, *end, *endlbl; + size_t npat, nlbl, i; + Dtree *dt; + + lbl = NULL; + nlbl = 0; + + pat = m->matchstmt.matches; + npat = m->matchstmt.nmatches; + for (i = 0; i < npat; i++) + lappend(&lbl, &nlbl, genlbl(pat[i]->match.block->loc)); + + + endlbl = genlbl(m->loc); + dt = gendtree(m, val, lbl, nlbl); + genmatchcode(dt, out, nout); + + for (i = 0; i < npat; i++) { + end = mkexpr(pat[i]->loc, Ojmp, endlbl, NULL); + end->expr.type = mktype(end->loc, Tyvoid); + lappend(out, nout, lbl[i]); + lappend(out, nout, pat[i]->match.block); + lappend(out, nout, end); + } + lappend(out, nout, endlbl); + + if (debugopt['m']) { + dtreedump(stdout, dt); + for (i = 0; i < *nout; i++) + dump((*out)[i], stdout); + } } void dtreedumplit(FILE *fd, Dtree *dt, Node *n, size_t depth) { - char *s; - - s = lblstr(dt->lbl); - switch (n->lit.littype) { - case Lchr: findentf(fd, depth, "%s: Lchr %c\n", s, n->lit.chrval); break; - case Lbool: findentf(fd, depth, "%s: Lbool %s\n", s, n->lit.boolval ? "true" : "false"); break; - case Lint: findentf(fd, depth, "%s: Lint %llu\n", s, n->lit.intval); break; - case Lflt: findentf(fd, depth, "%s: Lflt %lf\n", s, n->lit.fltval); break; - case Lstr: findentf(fd, depth, "%s: Lstr %.*s\n", s, (int)n->lit.strval.len, n->lit.strval.buf); break; - case Llbl: findentf(fd, depth, "%s: Llbl %s\n", s, n->lit.lblval); break; - case Lfunc: findentf(fd, depth, "%s: Lfunc\n"); break; - } + char *s; + + s = lblstr(dt->lbl); + switch (n->lit.littype) { + case Lchr: findentf(fd, depth, "%s: Lchr %c\n", s, n->lit.chrval); break; + case Lbool: findentf(fd, depth, "%s: Lbool %s\n", s, n->lit.boolval ? "true" : "false"); break; + case Lint: findentf(fd, depth, "%s: Lint %llu\n", s, n->lit.intval); break; + case Lflt: findentf(fd, depth, "%s: Lflt %lf\n", s, n->lit.fltval); break; + case Lstr: findentf(fd, depth, "%s: Lstr %.*s\n", s, (int)n->lit.strval.len, n->lit.strval.buf); break; + case Llbl: findentf(fd, depth, "%s: Llbl %s\n", s, n->lit.lblval); break; + case Lfunc: findentf(fd, depth, "%s: Lfunc\n"); break; + } } void dtreedumpnode(FILE *fd, Dtree *dt, size_t depth) { - size_t i; - - if (dt->accept) - findentf(fd, depth, "%s: accept\n", lblstr(dt->lbl)); - - for (i = 0; i < dt->nnext; i++) { - dtreedumplit(fd, dt, dt->pat[i]->expr.args[0], depth); - dtreedumpnode(fd, dt->next[i], depth + 1); - } - if (dt->any) { - findentf(fd, depth, "%s: wildcard\n", lblstr(dt->lbl)); - dtreedumpnode(fd, dt->any, depth + 1); - } + size_t i; + + if (dt->accept) + findentf(fd, depth, "%s: accept\n", lblstr(dt->lbl)); + + for (i = 0; i < dt->nnext; i++) { + dtreedumplit(fd, dt, dt->pat[i]->expr.args[0], depth); + dtreedumpnode(fd, dt->next[i], depth + 1); + } + if (dt->any) { + findentf(fd, depth, "%s: wildcard\n", lblstr(dt->lbl)); + dtreedumpnode(fd, dt->any, depth + 1); + } } void dtreedump(FILE *fd, Dtree *dt) { - dtreedumpnode(fd, dt, 0); + dtreedumpnode(fd, dt, 0); } diff --git a/mi/mi.h b/mi/mi.h index 0b9c8a8..021a3f7 100644 --- a/mi/mi.h +++ b/mi/mi.h @@ -3,36 +3,36 @@ typedef struct Bb Bb; typedef struct Reaching Reaching; struct Cfg { - Node *fn; - Bb **bb; - Bb *start; - Bb *end; - size_t nbb; - - /* for building bb */ - int nextbbid; - Htab *lblmap; /* label => Bb mapping */ - Node **fixjmp; - size_t nfixjmp; - Bb **fixblk; - size_t nfixblk; + Node *fn; + Bb **bb; + Bb *start; + Bb *end; + size_t nbb; + + /* for building bb */ + int nextbbid; + Htab *lblmap; /* label => Bb mapping */ + Node **fixjmp; + size_t nfixjmp; + Bb **fixblk; + size_t nfixblk; }; struct Bb { - int id; - char **lbls; - size_t nlbls; - Node **nl; - size_t nnl; - Bitset *pred; - Bitset *succ; + int id; + char **lbls; + size_t nlbls; + Node **nl; + size_t nnl; + Bitset *pred; + Bitset *succ; }; struct Reaching { - Bitset **in; - Bitset **out; - size_t **defs; - size_t *ndefs; + Bitset **in; + Bitset **out; + size_t **defs; + size_t *ndefs; }; /* expression folding */ diff --git a/mi/reaching.c b/mi/reaching.c index 01bd798..aaaaedc 100644 --- a/mi/reaching.c +++ b/mi/reaching.c @@ -15,153 +15,138 @@ Node *assignee(Node *n) { - Node *a; + Node *a; - switch (exprop(n)) { - case Oundef: case Odef: - case Oset: - case Oasn: case Oaddeq: - case Osubeq: case Omuleq: - case Odiveq: case Omodeq: - case Oboreq: case Obandeq: - case Obxoreq: case Obsleq: - case Obsreq: - return n->expr.args[0]; - break; - case Oblit: - case Oclear: - a = n->expr.args[0]; - if (exprop(a) != Oaddr) - break; - a = a->expr.args[0]; - if (exprop(a) != Ovar) - break; - return a; - default: - break; - } - return NULL; + switch (exprop(n)) { + case Oundef: case Odef: + case Oset: + case Oasn: case Oaddeq: + case Osubeq: case Omuleq: + case Odiveq: case Omodeq: + case Oboreq: case Obandeq: + case Obxoreq: case Obsleq: + case Obsreq: + return n->expr.args[0]; + break; + case Oblit: + case Oclear: + a = n->expr.args[0]; + if (exprop(a) != Oaddr) + break; + a = a->expr.args[0]; + if (exprop(a) != Ovar) + break; + return a; + default: + break; + } + return NULL; } static void collectdefs(Cfg *cfg, size_t **defs, size_t *ndefs) { - size_t i, j, did; - Node *n; - Bb *bb; + size_t i, j, did; + Node *n; + Bb *bb; - for (i = 0; i < cfg->nbb; i++) { - bb = cfg->bb[i]; - if (!bb) - continue; - for (j = 0; j < bb->nnl; j++) { - n = assignee(bb->nl[j]); - if (n && exprop(n) == Ovar) { - did = n->expr.did; - ndefs[did]++; - defs[did] = xrealloc(defs[did], ndefs[did] * sizeof(size_t)); - defs[did][ndefs[did] - 1] = bb->nl[j]->nid; - } - } - } + for (i = 0; i < cfg->nbb; i++) { + bb = cfg->bb[i]; + if (!bb) + continue; + for (j = 0; j < bb->nnl; j++) { + n = assignee(bb->nl[j]); + if (n && exprop(n) == Ovar) { + did = n->expr.did; + ndefs[did]++; + defs[did] = xrealloc(defs[did], ndefs[did] * sizeof(size_t)); + defs[did][ndefs[did] - 1] = bb->nl[j]->nid; + } + } + } } static void genkill(Bb *bb, size_t **defs, size_t *ndefs, Bitset *gen, Bitset *kill) { - size_t i, j, did; - Node *n; + size_t i, j, did; + Node *n; - for (i = 0; i < bb->nnl; i++) { - n = assignee(bb->nl[i]); - if (!n) - continue; - did = n->expr.did; - for (j = 0; j < ndefs[did]; j++) { - bsput(kill, defs[did][j]); - bsdel(gen, defs[did][j]); - } - bsput(gen, bb->nl[i]->nid); - bsdel(kill, bb->nl[i]->nid); - } + for (i = 0; i < bb->nnl; i++) { + n = assignee(bb->nl[i]); + if (!n) + continue; + did = n->expr.did; + for (j = 0; j < ndefs[did]; j++) { + bsput(kill, defs[did][j]); + bsdel(gen, defs[did][j]); + } + bsput(gen, bb->nl[i]->nid); + bsdel(kill, bb->nl[i]->nid); + } } void bsdump(Bitset *bs) { - size_t i; - for (i = 0; bsiter(bs, &i); i++) - printf("%zd ", i); - printf("\n"); + size_t i; + for (i = 0; bsiter(bs, &i); i++) + printf("%zd ", i); + printf("\n"); } Reaching *reaching(Cfg *cfg) { - Bitset **in, **out; - Bitset **gen, **kill; - Bitset *bbin, *bbout; - Reaching *reaching; - size_t **defs; /* mapping from did => [def,list] */ - size_t *ndefs; - size_t i, j; - int changed; + Bitset **in, **out; + Bitset **gen, **kill; + Bitset *bbin, *bbout; + Reaching *reaching; + size_t **defs; /* mapping from did => [def,list] */ + size_t *ndefs; + size_t i, j; + int changed; - in = zalloc(cfg->nbb * sizeof(Bb*)); - out = zalloc(cfg->nbb * sizeof(Bb*)); - gen = zalloc(cfg->nbb * sizeof(Bb*)); - kill = zalloc(cfg->nbb * sizeof(Bb*)); - defs = zalloc(ndecls * sizeof(size_t*)); - ndefs = zalloc(ndecls * sizeof(size_t)); + in = zalloc(cfg->nbb * sizeof(Bb*)); + out = zalloc(cfg->nbb * sizeof(Bb*)); + gen = zalloc(cfg->nbb * sizeof(Bb*)); + kill = zalloc(cfg->nbb * sizeof(Bb*)); + defs = zalloc(ndecls * sizeof(size_t*)); + ndefs = zalloc(ndecls * sizeof(size_t)); - collectdefs(cfg, defs, ndefs); - for (i = 0; i < cfg->nbb; i++) { - in[i] = mkbs(); - out[i] = mkbs(); - gen[i] = mkbs(); - kill[i] = mkbs(); - if (cfg->bb[i]) - genkill(cfg->bb[i], defs, ndefs, gen[i], kill[i]); - } + collectdefs(cfg, defs, ndefs); + for (i = 0; i < cfg->nbb; i++) { + in[i] = mkbs(); + out[i] = mkbs(); + gen[i] = mkbs(); + kill[i] = mkbs(); + if (cfg->bb[i]) + genkill(cfg->bb[i], defs, ndefs, gen[i], kill[i]); + } - do { - changed = 0; - for (i = 0; i < cfg->nbb; i++) { - if (!cfg->bb[i]) - continue; - bbin = mkbs(); - for (j = 0; bsiter(cfg->bb[i]->pred, &j); j++) - bsunion(bbin, out[j]); - bbout = bsdup(bbin); - bsdiff(bbout, kill[i]); - bsunion(bbout, gen[i]); + do { + changed = 0; + for (i = 0; i < cfg->nbb; i++) { + if (!cfg->bb[i]) + continue; + bbin = mkbs(); + for (j = 0; bsiter(cfg->bb[i]->pred, &j); j++) + bsunion(bbin, out[j]); + bbout = bsdup(bbin); + bsdiff(bbout, kill[i]); + bsunion(bbout, gen[i]); - if (!bseq(out[i], bbout) || !bseq(in[i], bbin)) { - changed = 1; - bsfree(in[i]); - bsfree(out[i]); - in[i] = bbin; - out[i] = bbout; - } - } - } while (changed); + if (!bseq(out[i], bbout) || !bseq(in[i], bbin)) { + changed = 1; + bsfree(in[i]); + bsfree(out[i]); + in[i] = bbin; + out[i] = bbout; + } + } + } while (changed); -// for (i = 0; i < ndecls; i++) { -// if (defs[i]) -// printf("\t%zd: ", i); -// for (j = 0; j < ndefs[i]; j++) -// printf("%zd ", defs[i][j]); -// if (defs[i]) -// printf("\n"); -// } -// for (i = 0; i < cfg->nbb; i++) { -// printf("bb %zd\n", i); -// printf("\tin: "); -// bsdump(in[i]); -// printf("\tout: "); -// bsdump(out[i]); -// } - reaching = xalloc(sizeof(Reaching)); - reaching->in = in; - reaching->out = out; - reaching->defs = defs; - reaching->ndefs = ndefs; - return reaching; + reaching = xalloc(sizeof(Reaching)); + reaching->in = in; + reaching->out = out; + reaching->defs = defs; + reaching->ndefs = ndefs; + return reaching; } diff --git a/mk/lexyacc.mk b/mk/lexyacc.mk index 5306d97..4851366 100644 --- a/mk/lexyacc.mk +++ b/mk/lexyacc.mk @@ -3,7 +3,7 @@ %.h %.c: %.y rm -f $*.h y.tab.h yacc -d -o$*.c $< - [ -f y.tab.h ] && mv y.tab.h $*.h + [ -f y.tab.h ] && mv y.tab.h $*.h || [ -f $*.h ] %.c: %.l flex -o$*.c $< diff --git a/muse/muse.c b/muse/muse.c index c00ade6..cec2b20 100644 --- a/muse/muse.c +++ b/muse/muse.c @@ -26,87 +26,87 @@ size_t nextralibs; static void usage(char *prog) { - printf("%s [-hIdos] [-o outfile] [-m] inputs\n", prog); - printf("\t-h\tprint this help\n"); - printf("\t\tThe outfile must be the same name as each package merged.\n"); - printf("\t-I path\tAdd 'path' to use search path\n"); - printf("\t-d\tPrint debug dumps\n"); - printf("\t-o out\tOutput to outfile\n"); - printf("\t-s\tShow the contents of usefiles `inputs`\n"); + printf("%s [-hIdos] [-o outfile] [-m] inputs\n", prog); + printf("\t-h\tprint this help\n"); + printf("\t\tThe outfile must be the same name as each package merged.\n"); + printf("\t-I path\tAdd 'path' to use search path\n"); + printf("\t-d\tPrint debug dumps\n"); + printf("\t-o out\tOutput to outfile\n"); + printf("\t-s\tShow the contents of usefiles `inputs`\n"); } static void mergeuse(char *path) { - FILE *f; - Stab *st; + FILE *f; + Stab *st; - st = file->file.globls; - f = fopen(path, "r"); - if (!f) - die("Couldn't open %s\n", path); - loaduse(path, f, st, Visexport); - fclose(f); + st = file->file.globls; + f = fopen(path, "r"); + if (!f) + die("Couldn't open %s\n", path); + loaduse(path, f, st, Visexport); + fclose(f); } int main(int argc, char **argv) { - Optctx ctx; - size_t i; - FILE *f; + Optctx ctx; + size_t i; + FILE *f; - optinit(&ctx, "d:hmo:I:l:", argv, argc); - while (!optdone(&ctx)) { - switch (optnext(&ctx)) { - case 'h': - usage(argv[0]); - exit(0); - break; - case 'o': - outfile = ctx.optarg; - break; - case 'd': - while (ctx.optarg && *ctx.optarg) - debugopt[*ctx.optarg++ & 0x7f] = 1; - break; - case 'I': - lappend(&incpaths, &nincpaths, ctx.optarg); - break; - case 'l': - lappend(&extralibs, &nextralibs, ctx.optarg); - break; - case 's': - show = 1; - break; - default: - usage(argv[0]); - exit(0); - break; - } - } + optinit(&ctx, "d:hmo:I:l:", argv, argc); + while (!optdone(&ctx)) { + switch (optnext(&ctx)) { + case 'h': + usage(argv[0]); + exit(0); + break; + case 'o': + outfile = ctx.optarg; + break; + case 'd': + while (ctx.optarg && *ctx.optarg) + debugopt[*ctx.optarg++ & 0x7f] = 1; + break; + case 'I': + lappend(&incpaths, &nincpaths, ctx.optarg); + break; + case 'l': + lappend(&extralibs, &nextralibs, ctx.optarg); + break; + case 's': + show = 1; + break; + default: + usage(argv[0]); + exit(0); + break; + } + } - lappend(&incpaths, &nincpaths, Instroot "/lib/myr"); - if (!outfile) { - fprintf(stderr, "output file needed when merging usefiles.\n"); - exit(1); - } + lappend(&incpaths, &nincpaths, Instroot "/lib/myr"); + if (!outfile) { + fprintf(stderr, "output file needed when merging usefiles.\n"); + exit(1); + } - /* read and parse the file */ - file = mkfile("internal"); - file->file.globls = mkstab(0); - updatens(file->file.globls, outfile); - tyinit(file->file.globls); - for (i = 0; i < ctx.nargs; i++) - mergeuse(ctx.args[i]); - infer(file); - tagexports(file, 1); - addextlibs(file, extralibs, nextralibs); + /* read and parse the file */ + file = mkfile("internal"); + file->file.globls = mkstab(0); + updatens(file->file.globls, outfile); + tyinit(file->file.globls); + for (i = 0; i < ctx.nargs; i++) + mergeuse(ctx.args[i]); + infer(file); + tagexports(file, 1); + addextlibs(file, extralibs, nextralibs); - /* generate the usefile */ - f = fopen(outfile, "w"); - if (debugopt['s'] || show) - dumpstab(file->file.globls, stdout); - else - writeuse(f, file); - fclose(f); - return 0; + /* generate the usefile */ + f = fopen(outfile, "w"); + if (debugopt['s'] || show) + dumpstab(file->file.globls, stdout); + else + writeuse(f, file); + fclose(f); + return 0; } diff --git a/parse/bitset.c b/parse/bitset.c index 7450515..ac72f6e 100644 --- a/parse/bitset.c +++ b/parse/bitset.c @@ -8,7 +8,7 @@ #include "parse.h" -#define Sizetbits (CHAR_BIT*sizeof(size_t)) /* used in graph reprs */ +#define Sizetbits (CHAR_BIT * sizeof(size_t)) /* used in graph reprs */ /* Equalizes the size of a and b by * growing the smaller to the size of the @@ -19,91 +19,91 @@ */ static void eqsz(Bitset *a, Bitset *b) { - size_t sz; - size_t i; - size_t *p; - - if (a->nchunks > b->nchunks) - sz = a->nchunks; - else - sz = b->nchunks; - - if (a->nchunks != sz) { - p = zalloc(sz * sizeof(size_t)); - for (i = 0; i < a->nchunks; i++) - p[i] = a->chunks[i]; - free(a->chunks); - a->chunks = p; - a->nchunks = sz; - } - - if (b->nchunks != sz) { - p = zalloc(sz * sizeof(size_t)); - for (i = 0; i < b->nchunks; i++) - p[i] = b->chunks[i]; - free(b->chunks); - b->chunks = p; - b->nchunks = sz; - } + size_t sz; + size_t i; + size_t *p; + + if (a->nchunks > b->nchunks) + sz = a->nchunks; + else + sz = b->nchunks; + + if (a->nchunks != sz) { + p = zalloc(sz * sizeof(size_t)); + for (i = 0; i < a->nchunks; i++) + p[i] = a->chunks[i]; + free(a->chunks); + a->chunks = p; + a->nchunks = sz; + } + + if (b->nchunks != sz) { + p = zalloc(sz * sizeof(size_t)); + for (i = 0; i < b->nchunks; i++) + p[i] = b->chunks[i]; + free(b->chunks); + b->chunks = p; + b->nchunks = sz; + } } /* Creates a new all-zero bit set */ Bitset *mkbs() { - Bitset *bs; + Bitset *bs; - bs = xalloc(sizeof(Bitset)); - bs->nchunks = 1; - bs->chunks = zalloc(1*sizeof(size_t)); - return bs; + bs = xalloc(sizeof(Bitset)); + bs->nchunks = 1; + bs->chunks = zalloc(1 * sizeof(size_t)); + return bs; } /* Frees a bitset. Safe to call on NULL. */ void bsfree(Bitset *bs) { - if (!bs) - return; - free(bs->chunks); - free(bs); + if (!bs) + return; + free(bs->chunks); + free(bs); } /* Duplicates a bitset. NULL is duplicated to NULL. */ Bitset *bsdup(Bitset *a) { - Bitset *bs; - - if (!a) - return NULL; - bs = xalloc(sizeof(Bitset)); - bs->nchunks = a->nchunks; - bs->chunks = xalloc(a->nchunks*sizeof(size_t)); - memcpy(bs->chunks, a->chunks, a->nchunks*sizeof(size_t)); - return bs; + Bitset *bs; + + if (!a) + return NULL; + bs = xalloc(sizeof(Bitset)); + bs->nchunks = a->nchunks; + bs->chunks = xalloc(a->nchunks * sizeof(size_t)); + memcpy(bs->chunks, a->chunks, a->nchunks * sizeof(size_t)); + return bs; } /* Zeroes all values in a bit set */ Bitset *bsclear(Bitset *bs) { - size_t i; + size_t i; - if (!bs) - return mkbs(); - for (i = 0; i < bs->nchunks; i++) - bs->chunks[i] = 0; - return bs; + if (!bs) + return mkbs(); + for (i = 0; i < bs->nchunks; i++) + bs->chunks[i] = 0; + return bs; } /* Counts the number of values held in a bit set */ size_t bscount(Bitset *bs) { - size_t i, j, n; - - n = 0; - for (i = 0; i < bs->nchunks; i++) - for (j = 0; j < sizeof(size_t)*CHAR_BIT; j++) - if (bs->chunks[i] & 1ULL << j) - n++; - return n; + size_t i, j, n; + + n = 0; + for (i = 0; i < bs->nchunks; i++) + for (j = 0; j < sizeof(size_t) * CHAR_BIT; j++) + if (bs->chunks[i] & 1ULL << j) + n++; + return n; } /* A slightly tricky function to iterate over the contents @@ -116,8 +116,8 @@ size_t bscount(Bitset *bs) * * Typical usage of this function: * - * for (i = 0; bsiter(set, &i); i++) - * use(i); + * for (i = 0; bsiter(set, &i); i++) + * use(i); * * The increment of 'i' in the for loop is needed in order * to prevent the function from returning the same value @@ -125,105 +125,101 @@ size_t bscount(Bitset *bs) */ int bsiter(Bitset *bs, size_t *elt) { - size_t i; - - for (i = *elt; i < bsmax(bs); i++) { - while (i < bsmax(bs) && !bs->chunks[i/Sizetbits]) - i = (i + Sizetbits) & ~(Sizetbits - 1); - if (bshas(bs, i)) { - *elt = i; - return 1; - } - } - return 0; + size_t i; + + for (i = *elt; i < bsmax(bs); i++) { + while (i < bsmax(bs) && !bs->chunks[i / Sizetbits]) + i = (i + Sizetbits) & ~(Sizetbits - 1); + if (bshas(bs, i)) { + *elt = i; + return 1; + } + } + return 0; } /* Returns the largest value that the bitset can possibly * hold. It's conservative, but scanning the entire bitset * is a bit slow. This is mostly an aid to iterate over it. */ -size_t bsmax(Bitset *bs) -{ - return bs->nchunks*Sizetbits; -} +size_t bsmax(Bitset *bs) { return bs->nchunks * Sizetbits; } void bsput(Bitset *bs, size_t elt) { - size_t sz; - if (elt >= bs->nchunks*Sizetbits) { - sz = (elt/Sizetbits)+1; - bs->chunks = zrealloc(bs->chunks, bs->nchunks*sizeof(size_t), sz*sizeof(size_t)); - bs->nchunks = sz; - } - bs->chunks[elt/Sizetbits] |= 1ULL << (elt % Sizetbits); + size_t sz; + if (elt >= bs->nchunks * Sizetbits) { + sz = (elt / Sizetbits) + 1; + bs->chunks = zrealloc(bs->chunks, bs->nchunks * sizeof(size_t), sz * sizeof(size_t)); + bs->nchunks = sz; + } + bs->chunks[elt / Sizetbits] |= 1ULL << (elt % Sizetbits); } void bsdel(Bitset *bs, size_t elt) { - if (elt < bs->nchunks*Sizetbits) - bs->chunks[elt/Sizetbits] &= ~(1ULL << (elt % Sizetbits)); + if (elt < bs->nchunks * Sizetbits) + bs->chunks[elt / Sizetbits] &= ~(1ULL << (elt % Sizetbits)); } - void bsunion(Bitset *a, Bitset *b) { - size_t i; + size_t i; - eqsz(a, b); - for (i = 0; i < a->nchunks; i++) - a->chunks[i] |= b->chunks[i]; + eqsz(a, b); + for (i = 0; i < a->nchunks; i++) + a->chunks[i] |= b->chunks[i]; } void bsintersect(Bitset *a, Bitset *b) { - size_t i; + size_t i; - eqsz(a, b); - for (i = 0; i < a->nchunks; i++) - a->chunks[i] &= b->chunks[i]; + eqsz(a, b); + for (i = 0; i < a->nchunks; i++) + a->chunks[i] &= b->chunks[i]; } void bsdiff(Bitset *a, Bitset *b) { - size_t i; + size_t i; - eqsz(a, b); - for (i = 0; i < a->nchunks; i++) - a->chunks[i] &= ~b->chunks[i]; + eqsz(a, b); + for (i = 0; i < a->nchunks; i++) + a->chunks[i] &= ~b->chunks[i]; } int bseq(Bitset *a, Bitset *b) { - size_t i; - - if (!a || !b) - return bsisempty(a) && bsisempty(b); - eqsz(a, b); - for (i = 0; i < a->nchunks; i++) { - if (a->chunks[i] != b->chunks[i]) - return 0; - } - return 1; + size_t i; + + if (!a || !b) + return bsisempty(a) && bsisempty(b); + eqsz(a, b); + for (i = 0; i < a->nchunks; i++) { + if (a->chunks[i] != b->chunks[i]) + return 0; + } + return 1; } int bsissubset(Bitset *set, Bitset *sub) { - size_t i; + size_t i; - eqsz(set, sub); - for (i = 0; i < set->nchunks; i++) - if ((sub->chunks[i] & set->chunks[i]) != set->chunks[i]) - return 0; - return 1; + eqsz(set, sub); + for (i = 0; i < set->nchunks; i++) + if ((sub->chunks[i] & set->chunks[i]) != set->chunks[i]) + return 0; + return 1; } int bsisempty(Bitset *set) { - size_t i; - - if (!set) - return 1; - for (i = 0; i < set->nchunks; i++) - if (set->chunks[i]) - return 0; - return 1; + size_t i; + + if (!set) + return 1; + for (i = 0; i < set->nchunks; i++) + if (set->chunks[i]) + return 0; + return 1; } diff --git a/parse/dump.c b/parse/dump.c index 92dc99b..9651b60 100644 --- a/parse/dump.c +++ b/parse/dump.c @@ -15,9 +15,9 @@ /* outputs a fully qualified name */ static void outname(Node *n, FILE *fd) { - if (n->name.ns) - fprintf(fd, "%s.", n->name.ns); - fprintf(fd, "%s", n->name.name); + if (n->name.ns) + fprintf(fd, "%s.", n->name.ns); + fprintf(fd, "%s", n->name.name); } /* outputs a sym in a one-line short form (ie, @@ -25,20 +25,17 @@ static void outname(Node *n, FILE *fd) * expressed in indented tree. */ static void outsym(Node *s, FILE *fd, int depth) { - char buf[1024]; + char buf[1024]; - if (s->decl.isconst) - findentf(fd, depth, "const "); - else - findentf(fd, depth, "var "); - outname(s->decl.name, fd); - fprintf(fd, " : %s\n", tyfmt(buf, 1024, s->decl.type)); + if (s->decl.isconst) + findentf(fd, depth, "const "); + else + findentf(fd, depth, "var "); + outname(s->decl.name, fd); + fprintf(fd, " : %s\n", tyfmt(buf, 1024, s->decl.type)); } -void dumpsym(Node *s, FILE *fd) -{ - outsym(s, fd, 0); -} +void dumpsym(Node *s, FILE *fd) { outsym(s, fd, 0); } /* Outputs a symbol table, and it's sub-tables * recursively, with a sigil describing the symbol @@ -51,71 +48,68 @@ void dumpsym(Node *s, FILE *fd) */ static void outstab(Stab *st, FILE *fd, int depth) { - size_t i, n; - char *name; - void **k; - char *ty; - Type *t; + size_t i, n; + char *name; + void **k; + char *ty; + Type *t; - name = ""; - if (st->name) - name = st->name; - findentf(fd, depth, "Stab %p (super = %p, name=\"%s\")\n", st, st->super, name); - if (!st) - return; + name = ""; + if (st->name) + name = st->name; + findentf(fd, depth, "Stab %p (super = %p, name=\"%s\")\n", st, st->super, name); + if (!st) + return; - /* print types */ - k = htkeys(st->ty, &n); - for (i = 0; i < n; i++) { - findentf(fd, depth + 1, "T "); - /* already indented */ - outname(k[i], fd); - t = gettype(st, k[i]); - if (t->nsub) - ty = tystr(t->sub[0]); - else - ty = strdup("none"); - fprintf(fd, " = %s [tid=%d]\n", ty, t->tid); - free(ty); - } - free(k); + /* print types */ + k = htkeys(st->ty, &n); + for (i = 0; i < n; i++) { + findentf(fd, depth + 1, "T "); + /* already indented */ + outname(k[i], fd); + t = gettype(st, k[i]); + if (t->nsub) + ty = tystr(t->sub[0]); + else + ty = strdup("none"); + fprintf(fd, " = %s [tid=%d]\n", ty, t->tid); + free(ty); + } + free(k); - /* dump declarations */ - k = htkeys(st->dcl, &n); - for (i = 0; i < n; i++) { - findentf(fd, depth + 1, "S "); - /* already indented */ - outsym(getdcl(st, k[i]), fd, 0); - } - free(k); + /* dump declarations */ + k = htkeys(st->dcl, &n); + for (i = 0; i < n; i++) { + findentf(fd, depth + 1, "S "); + /* already indented */ + outsym(getdcl(st, k[i]), fd, 0); + } + free(k); - /* dump closure */ - if (st->env) { - k = htkeys(st->env, &n); - for (i = 0; i < n; i++) { - findentf(fd, depth + 1, "U "); - /* already indented */ - outsym(getclosed(st, k[i]), fd, 0); - } - free(k); - } + /* dump closure */ + if (st->env) { + k = htkeys(st->env, &n); + for (i = 0; i < n; i++) { + findentf(fd, depth + 1, "U "); + /* already indented */ + outsym(getclosed(st, k[i]), fd, 0); + } + free(k); + } } -void dumpstab(Stab *st, FILE *fd) -{ - outstab(st, fd, 0); -} +void dumpstab(Stab *st, FILE *fd) { outstab(st, fd, 0); } void dumpfilestabs(Node *file, int depth, FILE *fd) { - size_t nk, i; - void **k; + size_t nk, i; + void **k; - k = htkeys(file->file.ns, &nk); - for (i = 0; i < nk; i++) { - outstab(htget(file->file.ns, k[i]), fd, depth); - } - free(k); + k = htkeys(file->file.ns, &nk); + for (i = 0; i < nk; i++) { + outstab(htget(file->file.ns, k[i]), fd, depth); + } + free(k); } /* Outputs a node in indented tree form. This is @@ -123,148 +117,142 @@ void dumpfilestabs(Node *file, int depth, FILE *fd) * understanding and debugging. */ static void outnode(Node *n, FILE *fd, int depth) { - size_t i; - char *ty; - char *tr; - int tid; - char buf[1024]; + size_t i; + char *ty; + char *tr; + int tid; + char buf[1024]; - if (!n) { - findentf(fd, depth, "Nil\n"); - return; - } - findentf(fd, depth, "%s.%zd@%i", nodestr[n->type], n->nid, lnum(n->loc)); - switch(n->type) { - case Nfile: - fprintf(fd, "(name = %s)\n", n->file.files[0]); - dumpfilestabs(file, depth + 1, fd); - for (i = 0; i < n->file.nuses; i++) - outnode(n->file.uses[i], fd, depth + 1); - for (i = 0; i < n->file.nstmts; i++) - outnode(n->file.stmts[i], fd, depth + 1); - break; - case Ndecl: - tr = ""; - if (n->decl.trait) - tr = namestr(n->decl.trait->name); - fprintf(fd, "(did = %zd, trait=%s, vis = %d)\n", - n->decl.did, tr, n->decl.vis); - findentf(fd, depth + 1, "isglobl=%d\n", n->decl.isglobl); - findentf(fd, depth + 1, "isconst=%d\n", n->decl.isconst); - findentf(fd, depth + 1, "isgeneric=%d\n", n->decl.isgeneric); - findentf(fd, depth + 1, "isextern=%d\n", n->decl.isextern); - findentf(fd, depth + 1, "ispkglocal=%d\n", n->decl.ispkglocal); - findentf(fd, depth + 1, "ishidden=%d\n", n->decl.ishidden); - findentf(fd, depth + 1, "isimport=%d\n", n->decl.isimport); - findentf(fd, depth + 1, "isnoret=%d\n", n->decl.isnoret); - findentf(fd, depth + 1, "isexportinit=%d\n", n->decl.isexportinit); - findentf(fd, depth, ")\n"); - outsym(n, fd, depth + 1); - outnode(n->decl.init, fd, depth + 1); - break; - case Nblock: - fprintf(fd, "\n"); - outstab(n->block.scope, fd, depth + 1); - for (i = 0; i < n->block.nstmts; i++) - outnode(n->block.stmts[i], fd, depth+1); - break; - case Nifstmt: - fprintf(fd, "\n"); - outnode(n->ifstmt.cond, fd, depth+1); - outnode(n->ifstmt.iftrue, fd, depth+1); - outnode(n->ifstmt.iffalse, fd, depth+1); - break; - case Nloopstmt: - fprintf(fd, "\n"); - outnode(n->loopstmt.init, fd, depth+1); - outnode(n->loopstmt.cond, fd, depth+1); - outnode(n->loopstmt.step, fd, depth+1); - outnode(n->loopstmt.body, fd, depth+1); - break; - case Niterstmt: - fprintf(fd, "\n"); - outnode(n->iterstmt.elt, fd, depth+1); - outnode(n->iterstmt.seq, fd, depth+1); - outnode(n->iterstmt.body, fd, depth+1); - break; - case Nmatchstmt: - fprintf(fd, "\n"); - outnode(n->matchstmt.val, fd, depth+1); - for (i = 0; i < n->matchstmt.nmatches; i++) - outnode(n->matchstmt.matches[i], fd, depth+1); - break; - case Nmatch: - fprintf(fd, "\n"); - outnode(n->match.pat, fd, depth+1); - outnode(n->match.block, fd, depth+1); - break; - case Nuse: - fprintf(fd, " (name = %s, islocal = %d)\n", n->use.name, n->use.islocal); - break; - case Nexpr: - if (exprop(n) == Ovar) - assert(decls[n->expr.did]->decl.did == n->expr.did); - ty = tystr(n->expr.type); - if (n->expr.type) - tid = n->expr.type->tid; - else - tid = -1; - fprintf(fd, " (type = %s [tid %d], op = %s, isconst = %d, did=%zd)\n", - ty, tid, opstr[n->expr.op], n->expr.isconst, n->expr.did); - free(ty); - outnode(n->expr.idx, fd, depth + 1); - for (i = 0; i < n->expr.nargs; i++) - outnode(n->expr.args[i], fd, depth+1); - break; - case Nlit: - switch (n->lit.littype) { - case Lchr: fprintf(fd, " Lchr %c\n", n->lit.chrval); break; - case Lbool: fprintf(fd, " Lbool %s\n", n->lit.boolval ? "true" : "false"); break; - case Lint: fprintf(fd, " Lint %llu\n", n->lit.intval); break; - case Lflt: fprintf(fd, " Lflt %lf\n", n->lit.fltval); break; - case Lstr: fprintf(fd, " Lstr %.*s\n", (int)n->lit.strval.len, n->lit.strval.buf); break; - case Llbl: fprintf(fd, " Llbl %s\n", n->lit.lblval); break; - case Lfunc: - fprintf(fd, " Lfunc\n"); - outnode(n->lit.fnval, fd, depth+1); - break; - } - break; - case Nfunc: - fprintf(fd, " (args =\n"); - for (i = 0; i < n->func.nargs; i++) - outnode(n->func.args[i], fd, depth+1); - findentf(fd, depth, ")\n"); - outstab(n->func.scope, fd, depth + 1); - outnode(n->func.body, fd, depth+1); - break; - case Nname: - fprintf(fd, "("); - if (n->name.ns) - fprintf(fd, "%s.", n->name.ns); - fprintf(fd, "%s", n->name.name); - fprintf(fd, ")\n"); - break; - case Nimpl: - fprintf(fd, "(name = %s, type = %s)\n", namestr(n->impl.traitname), tyfmt(buf, sizeof buf, n->impl.type)); - findentf(fd, depth, ""); - outnode(n->impl.traitname, fd, depth + 1); - for (i = 0; i < n->impl.ndecls; i++) - outnode(n->impl.decls[i], fd, depth+1); - break; - case Nnone: - fprintf(stderr, "Nnone not a real node type!"); - fprintf(fd, "Nnone\n"); - break; - } + if (!n) { + findentf(fd, depth, "Nil\n"); + return; + } + findentf(fd, depth, "%s.%zd@%i", nodestr[n->type], n->nid, lnum(n->loc)); + switch (n->type) { + case Nfile: + fprintf(fd, "(name = %s)\n", n->file.files[0]); + dumpfilestabs(file, depth + 1, fd); + for (i = 0; i < n->file.nuses; i++) + outnode(n->file.uses[i], fd, depth + 1); + for (i = 0; i < n->file.nstmts; i++) + outnode(n->file.stmts[i], fd, depth + 1); + break; + case Ndecl: + tr = ""; + if (n->decl.trait) + tr = namestr(n->decl.trait->name); + fprintf(fd, "(did = %zd, trait=%s, vis = %d)\n", n->decl.did, tr, n->decl.vis); + findentf(fd, depth + 1, "isglobl=%d\n", n->decl.isglobl); + findentf(fd, depth + 1, "isconst=%d\n", n->decl.isconst); + findentf(fd, depth + 1, "isgeneric=%d\n", n->decl.isgeneric); + findentf(fd, depth + 1, "isextern=%d\n", n->decl.isextern); + findentf(fd, depth + 1, "ispkglocal=%d\n", n->decl.ispkglocal); + findentf(fd, depth + 1, "ishidden=%d\n", n->decl.ishidden); + findentf(fd, depth + 1, "isimport=%d\n", n->decl.isimport); + findentf(fd, depth + 1, "isnoret=%d\n", n->decl.isnoret); + findentf(fd, depth + 1, "isexportinit=%d\n", n->decl.isexportinit); + findentf(fd, depth, ")\n"); + outsym(n, fd, depth + 1); + outnode(n->decl.init, fd, depth + 1); + break; + case Nblock: + fprintf(fd, "\n"); + outstab(n->block.scope, fd, depth + 1); + for (i = 0; i < n->block.nstmts; i++) + outnode(n->block.stmts[i], fd, depth + 1); + break; + case Nifstmt: + fprintf(fd, "\n"); + outnode(n->ifstmt.cond, fd, depth + 1); + outnode(n->ifstmt.iftrue, fd, depth + 1); + outnode(n->ifstmt.iffalse, fd, depth + 1); + break; + case Nloopstmt: + fprintf(fd, "\n"); + outnode(n->loopstmt.init, fd, depth + 1); + outnode(n->loopstmt.cond, fd, depth + 1); + outnode(n->loopstmt.step, fd, depth + 1); + outnode(n->loopstmt.body, fd, depth + 1); + break; + case Niterstmt: + fprintf(fd, "\n"); + outnode(n->iterstmt.elt, fd, depth + 1); + outnode(n->iterstmt.seq, fd, depth + 1); + outnode(n->iterstmt.body, fd, depth + 1); + break; + case Nmatchstmt: + fprintf(fd, "\n"); + outnode(n->matchstmt.val, fd, depth + 1); + for (i = 0; i < n->matchstmt.nmatches; i++) + outnode(n->matchstmt.matches[i], fd, depth + 1); + break; + case Nmatch: + fprintf(fd, "\n"); + outnode(n->match.pat, fd, depth + 1); + outnode(n->match.block, fd, depth + 1); + break; + case Nuse: fprintf(fd, " (name = %s, islocal = %d)\n", n->use.name, n->use.islocal); break; + case Nexpr: + if (exprop(n) == Ovar) + assert(decls[n->expr.did]->decl.did == n->expr.did); + ty = tystr(n->expr.type); + if (n->expr.type) + tid = n->expr.type->tid; + else + tid = -1; + fprintf(fd, " (type = %s [tid %d], op = %s, isconst = %d, did=%zd)\n", ty, tid, + opstr[n->expr.op], n->expr.isconst, n->expr.did); + free(ty); + outnode(n->expr.idx, fd, depth + 1); + for (i = 0; i < n->expr.nargs; i++) + outnode(n->expr.args[i], fd, depth + 1); + break; + case Nlit: + switch (n->lit.littype) { + case Lchr: fprintf(fd, " Lchr %c\n", n->lit.chrval); break; + case Lbool: fprintf(fd, " Lbool %s\n", n->lit.boolval ? "true" : "false"); break; + case Lint: fprintf(fd, " Lint %llu\n", n->lit.intval); break; + case Lflt: fprintf(fd, " Lflt %lf\n", n->lit.fltval); break; + case Llbl: fprintf(fd, " Llbl %s\n", n->lit.lblval); break; + case Lstr: + fprintf(fd, " Lstr %.*s\n", (int)n->lit.strval.len, n->lit.strval.buf); + break; + case Lfunc: + fprintf(fd, " lfunc\n"); + outnode(n->lit.fnval, fd, depth + 1); + break; + } + break; + case Nfunc: + fprintf(fd, " (args =\n"); + for (i = 0; i < n->func.nargs; i++) + outnode(n->func.args[i], fd, depth + 1); + findentf(fd, depth, ")\n"); + outstab(n->func.scope, fd, depth + 1); + outnode(n->func.body, fd, depth + 1); + break; + case Nname: + fprintf(fd, "("); + if (n->name.ns) + fprintf(fd, "%s.", n->name.ns); + fprintf(fd, "%s", n->name.name); + fprintf(fd, ")\n"); + break; + case Nimpl: + fprintf(fd, "(name = %s, type = %s)\n", namestr(n->impl.traitname), + tyfmt(buf, sizeof buf, n->impl.type)); + findentf(fd, depth, ""); + outnode(n->impl.traitname, fd, depth + 1); + for (i = 0; i < n->impl.ndecls; i++) + outnode(n->impl.decls[i], fd, depth + 1); + break; + case Nnone: + fprintf(stderr, "Nnone not a real node type!"); + fprintf(fd, "Nnone\n"); + break; + } } -void dump(Node *n, FILE *fd) -{ - outnode(n, fd, 0); -} +void dump(Node *n, FILE *fd) { outnode(n, fd, 0); } -void dumpn(Node *n) -{ - dump(n, stdout); -} +void dumpn(Node *n) { dump(n, stdout); } diff --git a/parse/gram.y b/parse/gram.y index f082be1..64e0da6 100644 --- a/parse/gram.y +++ b/parse/gram.y @@ -163,911 +163,910 @@ static void setupinit(Node *n); %type unionbody %union { - struct { - Srcloc loc; - Node **nl; - size_t nn; - } nodelist; - struct { - char **str; - size_t nstr; - } strlist; - struct { - Srcloc loc; - Ucon **ucl; - size_t nucl; - } uconlist; - struct { - Srcloc loc; - Type **types; - size_t ntypes; - } tylist; - struct { /* FIXME: unused */ - Srcloc loc; - char *name; - Type *type; - Type **params; - size_t nparams; - } tydef; - Trait *trait; - Node *node; - Tok *tok; - Type *ty; - Ucon *ucon; + struct { + Srcloc loc; + Node **nl; + size_t nn; + } nodelist; + struct { + char **str; + size_t nstr; + } strlist; + struct { + Srcloc loc; + Ucon **ucl; + size_t nucl; + } uconlist; + struct { + Srcloc loc; + Type **types; + size_t ntypes; + } tylist; + struct { /* FIXME: unused */ + Srcloc loc; + char *name; + Type *type; + Type **params; + size_t nparams; + } tydef; + Trait *trait; + Node *node; + Tok *tok; + Type *ty; + Ucon *ucon; } %% file : toplev - | file Tendln toplev - ; - -toplev : package - | use {lappend(&file->file.uses, &file->file.nuses, $1);} - | implstmt { - lappend(&file->file.stmts, &file->file.nstmts, $1); - } - | traitdef { - size_t i; - puttrait(file->file.globls, $1->name, $1); - for (i = 0; i < $1->nfuncs; i++) - putdcl(file->file.globls, $1->funcs[i]); - } - | tydef { - puttype(file->file.globls, mkname($1.loc, $1.name), $1.type); - installucons(file->file.globls, $1.type); - } - | decl { - size_t i; - Node *n; - - for (i = 0; i < $1.nn; i++) { - if (!strcmp(declname($1.nl[i]), "__init__")) - setupinit($1.nl[i]); - /* putdcl can merge, so we need to getdcl after */ - putdcl(file->file.globls, $1.nl[i]); - n = getdcl(file->file.globls, $1.nl[i]->decl.name); - lappend(&file->file.stmts, &file->file.nstmts, n); - $1.nl[i]->decl.isglobl = 1; - if ($1.nl[i]->decl.isinit) - file->file.localinit = $1.nl[i]; - } - } - | /* empty */ - ; + | file Tendln toplev + ; + +toplev : package + | use {lappend(&file->file.uses, &file->file.nuses, $1);} + | implstmt { + lappend(&file->file.stmts, &file->file.nstmts, $1); + } + | traitdef { + size_t i; + puttrait(file->file.globls, $1->name, $1); + for (i = 0; i < $1->nfuncs; i++) + putdcl(file->file.globls, $1->funcs[i]); + } + | tydef { + puttype(file->file.globls, mkname($1.loc, $1.name), $1.type); + installucons(file->file.globls, $1.type); + } + | decl { + size_t i; + Node *n; + + for (i = 0; i < $1.nn; i++) { + if (!strcmp(declname($1.nl[i]), "__init__")) + setupinit($1.nl[i]); + /* putdcl can merge, so we need to getdcl after */ + putdcl(file->file.globls, $1.nl[i]); + n = getdcl(file->file.globls, $1.nl[i]->decl.name); + lappend(&file->file.stmts, &file->file.nstmts, n); + $1.nl[i]->decl.isglobl = 1; + if ($1.nl[i]->decl.isinit) + file->file.localinit = $1.nl[i]; + } + } + | /* empty */ + ; decl : attrs Tvar decllist { - size_t i; - - for (i = 0; i < $3.nn; i++) - setattrs($3.nl[i], $1.str, $1.nstr); - $$ = $3; - } - | attrs Tconst decllist { - size_t i; - for (i = 0; i < $3.nn; i++) { - setattrs($3.nl[i], $1.str, $1.nstr); - $3.nl[i]->decl.isconst = 1; - } - $$ = $3; - } - | attrs Tgeneric decllist { - size_t i; - - for (i = 0; i < $3.nn; i++) { - setattrs($3.nl[i], $1.str, $1.nstr); - $3.nl[i]->decl.isconst = 1; - $3.nl[i]->decl.isgeneric = 1; - } - $$ = $3; - } + size_t i; + + for (i = 0; i < $3.nn; i++) + setattrs($3.nl[i], $1.str, $1.nstr); + $$ = $3; + } + | attrs Tconst decllist { + size_t i; + for (i = 0; i < $3.nn; i++) { + setattrs($3.nl[i], $1.str, $1.nstr); + $3.nl[i]->decl.isconst = 1; + } + $$ = $3; + } + | attrs Tgeneric decllist { + size_t i; + + for (i = 0; i < $3.nn; i++) { + setattrs($3.nl[i], $1.str, $1.nstr); + $3.nl[i]->decl.isconst = 1; + $3.nl[i]->decl.isgeneric = 1; + } + $$ = $3; + } attrs : /* empty */ {$$.nstr = 0; $$.str = NULL;} - | Tattr attrs { - $$ = $2; - lappend(&$$.str, &$$.nstr, strdup($1->id)); - } - ; + | Tattr attrs { + $$ = $2; + lappend(&$$.str, &$$.nstr, strdup($1->id)); + } + ; decllist: declbody { - $$.nl = NULL; $$.nn = 0; - lappend(&$$.nl, &$$.nn, $1); - } - | declbody Tcomma decllist { - linsert(&$3.nl, &$3.nn, 0, $1); - $$=$3; - } - ; + $$.nl = NULL; $$.nn = 0; + lappend(&$$.nl, &$$.nn, $1); + } + | declbody Tcomma decllist { + linsert(&$3.nl, &$3.nn, 0, $1); + $$=$3; + } + ; use : Tuse Tident {$$ = mkuse($1->loc, $2->id, 0);} - | Tuse Tstrlit {$$ = mkuse($1->loc, $2->strval.buf, 1);} - ; + | Tuse Tstrlit {$$ = mkuse($1->loc, $2->strval.buf, 1);} + ; optident: Tident {$$ = $1;} - | /* empty */ {$$ = NULL;} - ; + | /* empty */ {$$ = NULL;} + ; package : Tpkg optident Tasn pkgbody Tendblk { - if (file->file.globls->name) - lfatal($1->loc, "Package already declared\n"); - if ($2) { - updatens(file->file.globls, $2->id); - } - } - ; + if (file->file.globls->name) + lfatal($1->loc, "Package already declared\n"); + if ($2) { + updatens(file->file.globls, $2->id); + } + } + ; pkgbody : pkgitem - | pkgbody Tendln pkgitem - ; + | pkgbody Tendln pkgitem + ; pkgitem : decl { - size_t i; - for (i = 0; i < $1.nn; i++) { - $1.nl[i]->decl.vis = Visexport; - $1.nl[i]->decl.isglobl = 1; - putdcl(file->file.globls, $1.nl[i]); - if ($1.nl[i]->decl.init) - lappend(&file->file.stmts, &file->file.nstmts, $1.nl[i]); - } - } - | pkgtydef { - /* the type may only be null in a package context, so we - can set the type when merging in this case. - - FIXME: clean up the fucking special cases. */ - if ($1.type) - $1.type->vis = Visexport; - puttype(file->file.globls, mkname($1.loc, $1.name), $1.type); - installucons(file->file.globls, $1.type); - } - | traitdef { - size_t i; - $1->vis = Visexport; - puttrait(file->file.globls, $1->name, $1); - for (i = 0; i < $1->nfuncs; i++) - putdcl(file->file.globls, $1->funcs[i]); - } - | implstmt { - $1->impl.vis = Visexport; - lappend(&file->file.stmts, &file->file.nstmts, $1); - } - | /* empty */ - ; + size_t i; + for (i = 0; i < $1.nn; i++) { + $1.nl[i]->decl.vis = Visexport; + $1.nl[i]->decl.isglobl = 1; + putdcl(file->file.globls, $1.nl[i]); + if ($1.nl[i]->decl.init) + lappend(&file->file.stmts, &file->file.nstmts, $1.nl[i]); + } + } + | pkgtydef { + /* the type may only be null in a package context, so we + can set the type when merging in this case. + + FIXME: clean up the fucking special cases. */ + if ($1.type) + $1.type->vis = Visexport; + puttype(file->file.globls, mkname($1.loc, $1.name), $1.type); + installucons(file->file.globls, $1.type); + } + | traitdef { + size_t i; + $1->vis = Visexport; + puttrait(file->file.globls, $1->name, $1); + for (i = 0; i < $1->nfuncs; i++) + putdcl(file->file.globls, $1->funcs[i]); + } + | implstmt { + $1->impl.vis = Visexport; + lappend(&file->file.stmts, &file->file.nstmts, $1); + } + | /* empty */ + ; pkgtydef: attrs tydef { - size_t i; - $$ = $2; - for (i = 0; i < $1.nstr; i++) { - if (!strcmp($1.str[i], "pkglocal")) - $$.type->ispkglocal = 1; - else - lfatal($$.loc, "invalid type attribute '%s'", $1.str[i]); - } - } - ; + size_t i; + $$ = $2; + for (i = 0; i < $1.nstr; i++) { + if (!strcmp($1.str[i], "pkglocal")) + $$.type->ispkglocal = 1; + else + lfatal($$.loc, "invalid type attribute '%s'", $1.str[i]); + } + } + ; declbody: declcore Tasn expr {$$ = $1; $1->decl.init = $3;} - | declcore - ; + | declcore + ; declcore: name {$$ = mkdecl($1->loc, $1, mktyvar($1->loc));} - | typedeclcore {$$ = $1;} - ; + | typedeclcore {$$ = $1;} + ; typedeclcore - : name Tcolon type {$$ = mkdecl($1->loc, $1, $3);} - ; + : name Tcolon type {$$ = mkdecl($1->loc, $1, $3);} + ; name : Tident {$$ = mkname($1->loc, $1->id);} - | Tident Tdot name {$$ = $3; setns($3, $1->id);} - ; + | Tident Tdot name {$$ = $3; setns($3, $1->id);} + ; implstmt: Timpl name type { - $$ = mkimplstmt($1->loc, $2, $3, NULL, 0); - $$->impl.isproto = 1; - } - | Timpl name type Tasn Tendln implbody Tendblk { - $$ = mkimplstmt($1->loc, $2, $3, $6.nl, $6.nn); - } - ; + $$ = mkimplstmt($1->loc, $2, $3, NULL, 0); + $$->impl.isproto = 1; + } + | Timpl name type Tasn Tendln implbody Tendblk { + $$ = mkimplstmt($1->loc, $2, $3, $6.nl, $6.nn); + } + ; implbody - : optendlns {$$.nl = NULL; $$.nn = 0;} - | implbody Tident Tasn exprln optendlns { - Node *d; - $$ = $1; - d = mkdecl($2->loc, mkname($2->loc, $2->id), mktyvar($2->loc)); - d->decl.init = $4; - d->decl.isconst = 1; - d->decl.isglobl = 1; - lappend(&$$.nl, &$$.nn, d); - } - ; + : optendlns {$$.nl = NULL; $$.nn = 0;} + | implbody Tident Tasn exprln optendlns { + Node *d; + $$ = $1; + d = mkdecl($2->loc, mkname($2->loc, $2->id), mktyvar($2->loc)); + d->decl.init = $4; + d->decl.isconst = 1; + d->decl.isglobl = 1; + lappend(&$$.nl, &$$.nn, d); + } + ; traitdef: Ttrait Tident generictype /* trait prototype */ { - $$ = mktrait($1->loc, mkname($2->loc, $2->id), $3, NULL, 0, NULL, 0, 1); - } - | Ttrait Tident generictype Tasn traitbody Tendblk /* trait definition */ { - size_t i; - $$ = mktrait($1->loc, mkname($2->loc, $2->id), $3, NULL, 0, $5.nl, $5.nn, 0); - for (i = 0; i < $5.nn; i++) { - $5.nl[i]->decl.trait = $$; - $5.nl[i]->decl.isgeneric = 1; - } - } - ; + $$ = mktrait($1->loc, mkname($2->loc, $2->id), $3, NULL, 0, NULL, 0, 1); + } + | Ttrait Tident generictype Tasn traitbody Tendblk /* trait definition */ { + size_t i; + $$ = mktrait($1->loc, mkname($2->loc, $2->id), $3, NULL, 0, $5.nl, $5.nn, 0); + for (i = 0; i < $5.nn; i++) { + $5.nl[i]->decl.trait = $$; + $5.nl[i]->decl.isgeneric = 1; + } + } + ; traitbody - : optendlns {$$.nl = NULL; $$.nn = 0;} - | traitbody Tident Tcolon type optendlns { - Node *d; - $$ = $1; - d = mkdecl($2->loc, mkname($2->loc, $2->id), $4); - d->decl.isgeneric = 1; - d->decl.isconst = 1; - lappend(&$$.nl, &$$.nn, d); - } - ; + : optendlns {$$.nl = NULL; $$.nn = 0;} + | traitbody Tident Tcolon type optendlns { + Node *d; + $$ = $1; + d = mkdecl($2->loc, mkname($2->loc, $2->id), $4); + d->decl.isgeneric = 1; + d->decl.isconst = 1; + lappend(&$$.nl, &$$.nn, d); + } + ; tydef : Ttype typeid {$$ = $2;} - | Ttype typeid Tasn type { - $$ = $2; - if ($$.nparams == 0) { - $$.type = mktyname($2.loc, mkname($2.loc, $2.name), $4); - } else { - $$.type = mktygeneric($2.loc, mkname($2.loc, $2.name), $2.params, $2.nparams, $4); - } - } - ; + | Ttype typeid Tasn type { + $$ = $2; + if ($$.nparams == 0) { + $$.type = mktyname($2.loc, mkname($2.loc, $2.name), $4); + } else { + $$.type = mktygeneric($2.loc, mkname($2.loc, $2.name), $2.params, $2.nparams, $4); + } + } + ; typeid : Tident { - $$.loc = $1->loc; - $$.name = $1->id; - $$.params = NULL; - $$.type = NULL; - } - | Tident Toparen typarams Tcparen { - $$.loc = $1->loc; - $$.name = $1->id; - $$.params = $3.types; - $$.nparams = $3.ntypes; - $$.type = NULL; - } - ; + $$.loc = $1->loc; + $$.name = $1->id; + $$.params = NULL; + $$.type = NULL; + } + | Tident Toparen typarams Tcparen { + $$.loc = $1->loc; + $$.name = $1->id; + $$.params = $3.types; + $$.nparams = $3.ntypes; + $$.type = NULL; + } + ; typarams: generictype { - $$.types = NULL; $$.ntypes = 0; - lappend(&$$.types, &$$.ntypes, $1); - } - | typarams Tcomma generictype {lappend(&$$.types, &$$.ntypes, $3);} - ; + $$.types = NULL; $$.ntypes = 0; + lappend(&$$.types, &$$.ntypes, $1); + } + | typarams Tcomma generictype {lappend(&$$.types, &$$.ntypes, $3);} + ; type : structdef - | tupledef - | uniondef - | compoundtype - | generictype - | Tellipsis {$$ = mktype($1->loc, Tyvalist);} - ; + | tupledef + | uniondef + | compoundtype + | generictype + | Tellipsis {$$ = mktype($1->loc, Tyvalist);} + ; generictype - : Ttyparam {$$ = mktyparam($1->loc, $1->id);} - | Ttyparam Twith name { - $$ = mktyparam($1->loc, $1->id); - addtrait($$, $3->name.name); - } - | Ttyparam Twith Toparen typaramlist Tcparen { - size_t i; - $$ = mktyparam($1->loc, $1->id); - for (i = 0; i < $4.nn; i++) - addtrait($$, $4.nl[i]->name.name); - } - ; + : Ttyparam {$$ = mktyparam($1->loc, $1->id);} + | Ttyparam Twith name { + $$ = mktyparam($1->loc, $1->id); + addtrait($$, $3->name.name); + } + | Ttyparam Twith Toparen typaramlist Tcparen { + size_t i; + $$ = mktyparam($1->loc, $1->id); + for (i = 0; i < $4.nn; i++) + addtrait($$, $4.nl[i]->name.name); + } + ; typaramlist - : name { - $$.nl = NULL; $$.nn = 0; - lappend(&$$.nl, &$$.nn, $1); - } - | typaramlist Tcomma name {lappend(&$$.nl, &$$.nn, $3);} - ; + : name { + $$.nl = NULL; $$.nn = 0; + lappend(&$$.nl, &$$.nn, $1); + } + | typaramlist Tcomma name {lappend(&$$.nl, &$$.nn, $3);} + ; compoundtype - : functype {$$ = $1;} - | type Tosqbrac Tcolon Tcsqbrac {$$ = mktyslice($2->loc, $1);} - | type Tosqbrac expr Tcsqbrac {$$ = mktyarray($2->loc, $1, $3);} - | type Tosqbrac Tellipsis Tcsqbrac {$$ = mktyarray($2->loc, $1, NULL);} - | type Tderef {$$ = mktyptr($2->loc, $1);} - | Tat Tident {$$ = mktyparam($1->loc, $2->id);} - | name {$$ = mktyunres($1->loc, $1, NULL, 0);} - | name Toparen typelist Tcparen {$$ = mktyunres($1->loc, $1, $3.types, $3.ntypes);} - ; + : functype {$$ = $1;} + | type Tosqbrac Tcolon Tcsqbrac {$$ = mktyslice($2->loc, $1);} + | type Tosqbrac expr Tcsqbrac {$$ = mktyarray($2->loc, $1, $3);} + | type Tosqbrac Tellipsis Tcsqbrac {$$ = mktyarray($2->loc, $1, NULL);} + | type Tderef {$$ = mktyptr($2->loc, $1);} + | Tat Tident {$$ = mktyparam($1->loc, $2->id);} + | name {$$ = mktyunres($1->loc, $1, NULL, 0);} + | name Toparen typelist Tcparen {$$ = mktyunres($1->loc, $1, $3.types, $3.ntypes);} + ; functype: Toparen funcsig Tcparen {$$ = $2;} - ; + ; funcsig : argdefs Tret type - {$$ = mktyfunc($2->loc, $1.nl, $1.nn, $3);} - ; + {$$ = mktyfunc($2->loc, $1.nl, $1.nn, $3);} + ; argdefs : typedeclcore { - $$.loc = $1->loc; - $$.nl = NULL; - $$.nn = 0; lappend(&$$.nl, &$$.nn, $1); - } - | argdefs Tcomma declcore {lappend(&$$.nl, &$$.nn, $3);} - | /* empty */ { - $$.loc.line = 0; - $$.loc.file = 0; - $$.nl = NULL; - $$.nn = 0; - } - ; + $$.loc = $1->loc; + $$.nl = NULL; + $$.nn = 0; lappend(&$$.nl, &$$.nn, $1); + } + | argdefs Tcomma declcore {lappend(&$$.nl, &$$.nn, $3);} + | /* empty */ { + $$.loc.line = 0; + $$.loc.file = 0; + $$.nl = NULL; + $$.nn = 0; + } + ; tupledef: Toparen typelist Tcparen - {$$ = mktytuple($1->loc, $2.types, $2.ntypes);} - ; + {$$ = mktytuple($1->loc, $2.types, $2.ntypes);} + ; typelist: type { - $$.types = NULL; $$.ntypes = 0; - lappend(&$$.types, &$$.ntypes, $1); - } - | typelist Tcomma type - {lappend(&$$.types, &$$.ntypes, $3);} - ; + $$.types = NULL; $$.ntypes = 0; + lappend(&$$.types, &$$.ntypes, $1); + } + | typelist Tcomma type + {lappend(&$$.types, &$$.ntypes, $3);} + ; structdef - : Tstruct structbody Tendblk - {$$ = mktystruct($1->loc, $2.nl, $2.nn);} - ; + : Tstruct structbody Tendblk + {$$ = mktystruct($1->loc, $2.nl, $2.nn);} + ; structbody - : structent { - if ($1) { - $$.nl = NULL; - $$.nn = 0; - lappend(&$$.nl, &$$.nn, $1); - } - } - | structbody structent { - if ($2) - lappend(&$$.nl, &$$.nn, $2); - } - ; + : structent { + if ($1) { + $$.nl = NULL; + $$.nn = 0; + lappend(&$$.nl, &$$.nn, $1); + } + } + | structbody structent { + if ($2) + lappend(&$$.nl, &$$.nn, $2); + } + ; structent - : declcore Tendln {$$ = $1;} - | Tendln {$$ = NULL;} - ; + : declcore Tendln {$$ = $1;} + | Tendln {$$ = NULL;} + ; uniondef - : Tunion unionbody Tendblk - {$$ = mktyunion($1->loc, $2.ucl, $2.nucl);} - ; + : Tunion unionbody Tendblk + {$$ = mktyunion($1->loc, $2.ucl, $2.nucl);} + ; unionbody - : unionelt { - $$.ucl = NULL; - $$.nucl = 0; - if ($1) - lappend(&$$.ucl, &$$.nucl, $1); - } - | unionbody unionelt { - if ($2) - lappend(&$$.ucl, &$$.nucl, $2); - } - ; + : unionelt { + $$.ucl = NULL; + $$.nucl = 0; + if ($1) + lappend(&$$.ucl, &$$.nucl, $1); + } + | unionbody unionelt { + if ($2) + lappend(&$$.ucl, &$$.nucl, $2); + } + ; unionelt /* nb: the ucon union type gets filled in when we have context */ - : Ttick name type Tendln {$$ = mkucon($2->loc, $2, NULL, $3);} - | Ttick name Tendln {$$ = mkucon($2->loc, $2, NULL, NULL);} - | Tendln {$$ = NULL;} - ; + : Ttick name type Tendln {$$ = mkucon($2->loc, $2, NULL, $3);} + | Ttick name Tendln {$$ = mkucon($2->loc, $2, NULL, NULL);} + | Tendln {$$ = NULL;} + ; goto : Tgoto Tident {$$ = mkexpr($1->loc, Ojmp, mklbl($2->loc, $2->id), NULL);} - ; + ; retexpr : Tret expr {$$ = mkexpr($1->loc, Oret, $2, NULL);} - | Tret {$$ = mkexpr($1->loc, Oret, NULL);} - | expr - ; + | Tret {$$ = mkexpr($1->loc, Oret, NULL);} + | expr + ; optexpr : expr {$$ = $1;} - | /* empty */ {$$ = NULL;} - ; + | /* empty */ {$$ = NULL;} + ; optexprln: exprln {$$ = $1;} - | Tendln {$$ = NULL;} - ; + | Tendln {$$ = NULL;} + ; exprln : expr Tendln - ; + ; expr : asnexpr - ; + ; asnexpr : lorexpr asnop asnexpr - {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} - | lorexpr - ; + {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} + | lorexpr + ; asnop : Tasn - | Taddeq /* += */ - | Tsubeq /* -= */ - | Tmuleq /* *= */ - | Tdiveq /* /= */ - | Tmodeq /* %= */ - | Tboreq /* |= */ - | Tbxoreq /* ^= */ - | Tbandeq /* &= */ - | Tbsleq /* <<= */ - | Tbsreq /* >>= */ - ; + | Taddeq /* += */ + | Tsubeq /* -= */ + | Tmuleq /* *= */ + | Tdiveq /* /= */ + | Tmodeq /* %= */ + | Tboreq /* |= */ + | Tbxoreq /* ^= */ + | Tbandeq /* &= */ + | Tbsleq /* <<= */ + | Tbsreq /* >>= */ + ; lorexpr : lorexpr Tlor landexpr - {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} - | landexpr - ; + {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} + | landexpr + ; landexpr: landexpr Tland cmpexpr - {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} - | cmpexpr - ; + {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} + | cmpexpr + ; cmpexpr : cmpexpr cmpop castexpr - {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} - | unionexpr - ; + {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} + | unionexpr + ; cmpop : Teq | Tgt | Tlt | Tge | Tle | Tne ; unionexpr - : Ttick name unionexpr {$$ = mkexpr($1->loc, Oucon, $2, $3, NULL);} - | Ttick name {$$ = mkexpr($1->loc, Oucon, $2, NULL);} - | castexpr - ; + : Ttick name unionexpr {$$ = mkexpr($1->loc, Oucon, $2, $3, NULL);} + | Ttick name {$$ = mkexpr($1->loc, Oucon, $2, NULL);} + | castexpr + ; castexpr: castexpr Tcast Toparen type Tcparen { - $$ = mkexpr($1->loc, Ocast, $1, NULL); - $$->expr.type = $4; - } - | borexpr - ; + $$ = mkexpr($1->loc, Ocast, $1, NULL); + $$->expr.type = $4; + } + | borexpr + ; borexpr : borexpr Tbor bandexpr - {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} - | borexpr Tbxor bandexpr - {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} - | bandexpr - ; + {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} + | borexpr Tbxor bandexpr + {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} + | bandexpr + ; bandexpr: bandexpr Tband addexpr - {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} - | addexpr - ; + {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} + | addexpr + ; addexpr : addexpr addop mulexpr - {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} - | mulexpr - ; + {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} + | mulexpr + ; addop : Tplus | Tminus ; mulexpr : mulexpr mulop shiftexpr - {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} - | shiftexpr - ; + {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} + | shiftexpr + ; mulop : Tmul | Tdiv | Tmod - ; + ; shiftexpr - : shiftexpr shiftop prefixexpr - {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} - | prefixexpr - ; + : shiftexpr shiftop prefixexpr + {$$ = mkexpr($1->loc, binop($2->type), $1, $3, NULL);} + | prefixexpr + ; shiftop : Tbsl | Tbsr; prefixexpr - : Tinc prefixexpr {$$ = mkexpr($1->loc, Opreinc, $2, NULL);} - | Tdec prefixexpr {$$ = mkexpr($1->loc, Opredec, $2, NULL);} - | Tband prefixexpr {$$ = mkexpr($1->loc, Oaddr, $2, NULL);} - | Tlnot prefixexpr {$$ = mkexpr($1->loc, Olnot, $2, NULL);} - | Tbnot prefixexpr {$$ = mkexpr($1->loc, Obnot, $2, NULL);} - | Tminus prefixexpr {$$ = mkexpr($1->loc, Oneg, $2, NULL);} - | Tplus prefixexpr {$$ = $2;} /* positive is a nop */ - | postfixexpr - ; + : Tinc prefixexpr {$$ = mkexpr($1->loc, Opreinc, $2, NULL);} + | Tdec prefixexpr {$$ = mkexpr($1->loc, Opredec, $2, NULL);} + | Tband prefixexpr {$$ = mkexpr($1->loc, Oaddr, $2, NULL);} + | Tlnot prefixexpr {$$ = mkexpr($1->loc, Olnot, $2, NULL);} + | Tbnot prefixexpr {$$ = mkexpr($1->loc, Obnot, $2, NULL);} + | Tminus prefixexpr {$$ = mkexpr($1->loc, Oneg, $2, NULL);} + | Tplus prefixexpr {$$ = $2;} /* positive is a nop */ + | postfixexpr + ; postfixexpr - : postfixexpr Tdot Tident - {$$ = mkexpr($1->loc, Omemb, $1, mkname($3->loc, $3->id), NULL);} - | postfixexpr Tinc - {$$ = mkexpr($1->loc, Opostinc, $1, NULL);} - | postfixexpr Tdec - {$$ = mkexpr($1->loc, Opostdec, $1, NULL);} - | postfixexpr Tosqbrac expr Tcsqbrac - {$$ = mkexpr($1->loc, Oidx, $1, $3, NULL);} - | postfixexpr Tosqbrac optexpr Tcolon optexpr Tcsqbrac - {$$ = mksliceexpr($1->loc, $1, $3, $5);} - | postfixexpr Tderef - {$$ = mkexpr($1->loc, Oderef, $1, NULL);} - | postfixexpr Toparen arglist Tcparen - {$$ = mkcall($1->loc, $1, $3.nl, $3.nn);} - | atomicexpr - ; + : postfixexpr Tdot Tident + {$$ = mkexpr($1->loc, Omemb, $1, mkname($3->loc, $3->id), NULL);} + | postfixexpr Tinc + {$$ = mkexpr($1->loc, Opostinc, $1, NULL);} + | postfixexpr Tdec + {$$ = mkexpr($1->loc, Opostdec, $1, NULL);} + | postfixexpr Tosqbrac expr Tcsqbrac + {$$ = mkexpr($1->loc, Oidx, $1, $3, NULL);} + | postfixexpr Tosqbrac optexpr Tcolon optexpr Tcsqbrac + {$$ = mksliceexpr($1->loc, $1, $3, $5);} + | postfixexpr Tderef + {$$ = mkexpr($1->loc, Oderef, $1, NULL);} + | postfixexpr Toparen arglist Tcparen + {$$ = mkcall($1->loc, $1, $3.nl, $3.nn);} + | atomicexpr + ; arglist : asnexpr - {$$.nl = NULL; $$.nn = 0; lappend(&$$.nl, &$$.nn, $1);} - | arglist Tcomma asnexpr - {lappend(&$$.nl, &$$.nn, $3);} - | /* empty */ - {$$.nl = NULL; $$.nn = 0;} - ; + {$$.nl = NULL; $$.nn = 0; lappend(&$$.nl, &$$.nn, $1);} + | arglist Tcomma asnexpr + {lappend(&$$.nl, &$$.nn, $3);} + | /* empty */ + {$$.nl = NULL; $$.nn = 0;} + ; atomicexpr - : Tident - {$$ = mkexpr($1->loc, Ovar, mkname($1->loc, $1->id), NULL);} - | Tgap - {$$ = mkexpr($1->loc, Ogap, NULL);} - | Tidxlen - {$$ = mkexpr($1->loc, Oidxlen, NULL);} - | literal - | Toparen expr Tcparen - {$$ = $2;} - | Tsizeof Toparen type Tcparen - {$$ = mkexpr($1->loc, Osize, mkpseudodecl($1->loc, $3), NULL);} - ; + : Tident + {$$ = mkexpr($1->loc, Ovar, mkname($1->loc, $1->id), NULL);} + | Tgap + {$$ = mkexpr($1->loc, Ogap, NULL);} + | Tidxlen + {$$ = mkexpr($1->loc, Oidxlen, NULL);} + | literal + | Toparen expr Tcparen + {$$ = $2;} + | Tsizeof Toparen type Tcparen + {$$ = mkexpr($1->loc, Osize, mkpseudodecl($1->loc, $3), NULL);} + ; tupbody : tuphead tuprest - {$$ = $2; - linsert(&$$.nl, &$$.nn, 0, $1);} - ; + {$$ = $2; + linsert(&$$.nl, &$$.nn, 0, $1);} + ; tuphead : expr Tcomma {$$ = $1;} - ; + ; tuprest : /*empty */ - {$$.nl = NULL; $$.nn = 0;} - | expr { - $$.nl = NULL; $$.nn = 0; - lappend(&$$.nl, &$$.nn, $1); - } - | tuprest Tcomma expr {lappend(&$$.nl, &$$.nn, $3);} - ; + {$$.nl = NULL; $$.nn = 0;} + | expr { + $$.nl = NULL; $$.nn = 0; + lappend(&$$.nl, &$$.nn, $1); + } + | tuprest Tcomma expr {lappend(&$$.nl, &$$.nn, $3);} + ; literal : funclit {$$ = mkexpr($1->loc, Olit, $1, NULL);} - | littok {$$ = mkexpr($1->loc, Olit, $1, NULL);} - | seqlit {$$ = $1;} - | tuplit {$$ = $1;} - ; + | littok {$$ = mkexpr($1->loc, Olit, $1, NULL);} + | seqlit {$$ = $1;} + | tuplit {$$ = $1;} + ; tuplit : Toparen tupbody Tcparen - {$$ = mkexprl($1->loc, Otup, $2.nl, $2.nn);} + {$$ = mkexprl($1->loc, Otup, $2.nl, $2.nn);} littok : Tstrlit {$$ = mkstr($1->loc, $1->strval);} - | Tchrlit {$$ = mkchar($1->loc, $1->chrval);} - | Tfloatlit {$$ = mkfloat($1->loc, $1->fltval);} - | Tboollit {$$ = mkbool($1->loc, !strcmp($1->id, "true"));} - | Tintlit { - $$ = mkint($1->loc, $1->intval); - if ($1->inttype) - $$->lit.type = mktype($1->loc, $1->inttype); - } - ; + | Tchrlit {$$ = mkchar($1->loc, $1->chrval);} + | Tfloatlit {$$ = mkfloat($1->loc, $1->fltval);} + | Tboollit {$$ = mkbool($1->loc, !strcmp($1->id, "true"));} + | Tintlit { + $$ = mkint($1->loc, $1->intval); + if ($1->inttype) + $$->lit.type = mktype($1->loc, $1->inttype); + } + ; funclit : Tobrace params Tendln blkbody Tcbrace - {$$ = mkfunc($1->loc, $2.nl, $2.nn, mktyvar($3->loc), $4);} - | Tobrace params Tret type Tendln blkbody Tcbrace - {$$ = mkfunc($1->loc, $2.nl, $2.nn, $4, $6);} - ; + {$$ = mkfunc($1->loc, $2.nl, $2.nn, mktyvar($3->loc), $4);} + | Tobrace params Tret type Tendln blkbody Tcbrace + {$$ = mkfunc($1->loc, $2.nl, $2.nn, $4, $6);} + ; params : fnparam { - $$.nl = NULL; - $$.nn = 0; - lappend(&$$.nl, &$$.nn, $1); - } - | params Tcomma fnparam {lappend(&$$.nl, &$$.nn, $3);} - | /* empty */ {$$.nl = NULL; $$.nn = 0;} - ; + $$.nl = NULL; + $$.nn = 0; + lappend(&$$.nl, &$$.nn, $1); + } + | params Tcomma fnparam {lappend(&$$.nl, &$$.nn, $3);} + | /* empty */ {$$.nl = NULL; $$.nn = 0;} + ; fnparam : declcore {$$ = $1;} - | Tgap { $$ = mkpseudodecl($1->loc, mktyvar($1->loc)); } - | Tgap Tcolon type { $$ = mkpseudodecl($1->loc, $3); } - ; + | Tgap { $$ = mkpseudodecl($1->loc, mktyvar($1->loc)); } + | Tgap Tcolon type { $$ = mkpseudodecl($1->loc, $3); } + ; seqlit : Tosqbrac arrayelts optcomma Tcsqbrac - {$$ = mkexprl($1->loc, Oarr, $2.nl, $2.nn);} - | Tosqbrac structelts optcomma Tcsqbrac - {$$ = mkexprl($1->loc, Ostruct, $2.nl, $2.nn);} - | Tosqbrac optendlns optcomma Tcsqbrac /* [] is the empty array. */ - {$$ = mkexprl($1->loc, Oarr, NULL, 0);} - ; + {$$ = mkexprl($1->loc, Oarr, $2.nl, $2.nn);} + | Tosqbrac structelts optcomma Tcsqbrac + {$$ = mkexprl($1->loc, Ostruct, $2.nl, $2.nn);} + | Tosqbrac optendlns optcomma Tcsqbrac /* [] is the empty array. */ + {$$ = mkexprl($1->loc, Oarr, NULL, 0);} + ; optcomma: Tcomma optendlns - | /* empty */ - ; + | /* empty */ + ; arrayelts - : optendlns arrayelt { - $$.nl = NULL; - $$.nn = 0; - if ($2->expr.idx) - lappend(&$$.nl, &$$.nn, $2); - else - lappend(&$$.nl, &$$.nn, mkidxinit($2->loc, mkintlit($2->loc, 0), $2)); - } - | arrayelts Tcomma optendlns arrayelt { - if ($4->expr.idx) - lappend(&$$.nl, &$$.nn, $4); - else - lappend(&$$.nl, &$$.nn, mkidxinit($4->loc, mkintlit($4->loc, $$.nn), $4)); - } - ; + : optendlns arrayelt { + $$.nl = NULL; + $$.nn = 0; + if ($2->expr.idx) + lappend(&$$.nl, &$$.nn, $2); + else + lappend(&$$.nl, &$$.nn, mkidxinit($2->loc, mkintlit($2->loc, 0), $2)); + } + | arrayelts Tcomma optendlns arrayelt { + if ($4->expr.idx) + lappend(&$$.nl, &$$.nn, $4); + else + lappend(&$$.nl, &$$.nn, mkidxinit($4->loc, mkintlit($4->loc, $$.nn), $4)); + } + ; arrayelt: expr optendlns {$$ = $1;} - | expr Tcolon expr optendlns { - $$ = mkidxinit($2->loc, $1, $3); - } - ; + | expr Tcolon expr optendlns { + $$ = mkidxinit($2->loc, $1, $3); + } + ; structelts - : optendlns structelt { - $$.nl = NULL; - $$.nn = 0; - lappend(&$$.nl, &$$.nn, $2); - } - | structelts Tcomma optendlns structelt { - lappend(&$$.nl, &$$.nn, $4); - } - ; + : optendlns structelt { + $$.nl = NULL; + $$.nn = 0; + lappend(&$$.nl, &$$.nn, $2); + } + | structelts Tcomma optendlns structelt { + lappend(&$$.nl, &$$.nn, $4); + } + ; structelt: Tdot Tident Tasn expr optendlns { - $$ = $4; - mkidxinit($2->loc, mkname($2->loc, $2->id), $4); - } - ; + $$ = $4; + mkidxinit($2->loc, mkname($2->loc, $2->id), $4); + } + ; optendlns : /* none */ - | optendlns Tendln - ; + | optendlns Tendln + ; stmt : goto - | break - | continue - | retexpr - | label - | ifstmt - | forstmt - | whilestmt - | matchstmt - | /* empty */ {$$ = NULL;} - ; + | break + | continue + | retexpr + | label + | ifstmt + | forstmt + | whilestmt + | matchstmt + | /* empty */ {$$ = NULL;} + ; break : Tbreak - {$$ = mkexpr($1->loc, Obreak, NULL);} - ; + {$$ = mkexpr($1->loc, Obreak, NULL);} + ; continue : Tcontinue - {$$ = mkexpr($1->loc, Ocontinue, NULL);} - ; + {$$ = mkexpr($1->loc, Ocontinue, NULL);} + ; forstmt : Tfor optexprln optexprln optexprln block - {$$ = mkloopstmt($1->loc, $2, $3, $4, $5);} - | Tfor expr Tin exprln block - {$$ = mkiterstmt($1->loc, $2, $4, $5);} - | Tfor decl Tendln optexprln optexprln block { - //Node *init; - if ($2.nn != 1) - lfatal($1->loc, "only one declaration is allowed in for loop"); - $$ = mkloopstmt($1->loc, $2.nl[0], $4, $5, $6); - putdcl($$->loopstmt.scope, $2.nl[0]); - } - - ; + {$$ = mkloopstmt($1->loc, $2, $3, $4, $5);} + | Tfor expr Tin exprln block + {$$ = mkiterstmt($1->loc, $2, $4, $5);} + | Tfor decl Tendln optexprln optexprln block { + //Node *init; + if ($2.nn != 1) + lfatal($1->loc, "only one declaration is allowed in for loop"); + $$ = mkloopstmt($1->loc, $2.nl[0], $4, $5, $6); + putdcl($$->loopstmt.scope, $2.nl[0]); + } + + ; whilestmt - : Twhile exprln block - {$$ = mkloopstmt($1->loc, NULL, $2, NULL, $3);} - ; + : Twhile exprln block + {$$ = mkloopstmt($1->loc, NULL, $2, NULL, $3);} + ; ifstmt : Tif exprln blkbody elifs - {$$ = mkifstmt($1->loc, $2, $3, $4);} - ; + {$$ = mkifstmt($1->loc, $2, $3, $4);} + ; elifs : Telif exprln blkbody elifs - {$$ = mkifstmt($1->loc, $2, $3, $4);} - | Telse block - {$$ = $2;} - | Tendblk - {$$ = NULL;} - ; + {$$ = mkifstmt($1->loc, $2, $3, $4);} + | Telse block + {$$ = $2;} + | Tendblk + {$$ = NULL;} + ; matchstmt: Tmatch exprln optendlns Tbor matches Tendblk - {$$ = mkmatchstmt($1->loc, $2, $5.nl, $5.nn);} - ; + {$$ = mkmatchstmt($1->loc, $2, $5.nl, $5.nn);} + ; matches : match { - $$.nl = NULL; - $$.nn = 0; - if ($1) - lappend(&$$.nl, &$$.nn, $1); - } - | matches Tbor match { - if ($2) - lappend(&$$.nl, &$$.nn, $3); - } - ; + $$.nl = NULL; + $$.nn = 0; + if ($1) + lappend(&$$.nl, &$$.nn, $1); + } + | matches Tbor match { + if ($2) + lappend(&$$.nl, &$$.nn, $3); + } + ; match : expr Tcolon blkbody Tendln {$$ = mkmatch($1->loc, $1, $3);} - ; + ; block : blkbody Tendblk - ; + ; blkbody : decl { - size_t i; - Node *n, *d, *u; - - $$ = mkblock($1.loc, mkstab(0)); - for (i = 0; i < $1.nn; i++) { - d = $1.nl[i]; - putdcl($$->block.scope, d); - if (!d->decl.init) { - n = mkexpr(d->loc, Ovar, d->decl.name, NULL); - u = mkexpr(n->loc, Oundef, n, NULL); - n->expr.did = d->decl.did; - lappend(&$$->block.stmts, &$$->block.nstmts, u); - } - lappend(&$$->block.stmts, &$$->block.nstmts, d); - } - } - | stmt { - $$ = mkblock(curloc, mkstab(0)); - if ($1) - lappend(&$$->block.stmts, &$$->block.nstmts, $1); - } - | blkbody Tendln stmt { - if ($3) - lappend(&$1->block.stmts, &$1->block.nstmts, $3); - $$ = $1; - } - | blkbody Tendln decl { - size_t i; - for (i = 0; i < $3.nn; i++){ - putdcl($$->block.scope, $3.nl[i]); - lappend(&$1->block.stmts, &$1->block.nstmts, $3.nl[i]); - } - } - ; - -label : Tcolon Tident - {$$ = mklbl($2->loc, $2->id);} - ; + size_t i; + Node *n, *d, *u; + + $$ = mkblock($1.loc, mkstab(0)); + for (i = 0; i < $1.nn; i++) { + d = $1.nl[i]; + putdcl($$->block.scope, d); + if (!d->decl.init) { + n = mkexpr(d->loc, Ovar, d->decl.name, NULL); + u = mkexpr(n->loc, Oundef, n, NULL); + n->expr.did = d->decl.did; + lappend(&$$->block.stmts, &$$->block.nstmts, u); + } + lappend(&$$->block.stmts, &$$->block.nstmts, d); + } + } + | stmt { + $$ = mkblock(curloc, mkstab(0)); + if ($1) + lappend(&$$->block.stmts, &$$->block.nstmts, $1); + } + | blkbody Tendln stmt { + if ($3) + lappend(&$1->block.stmts, &$1->block.nstmts, $3); + $$ = $1; + } + | blkbody Tendln decl { + size_t i; + for (i = 0; i < $3.nn; i++){ + putdcl($$->block.scope, $3.nl[i]); + lappend(&$1->block.stmts, &$1->block.nstmts, $3.nl[i]); + } + } + ; + +label : Tcolon Tident {$$ = mklbl($2->loc, $2->id);} + ; %% static void setupinit(Node *n) { - char name[1024]; - char *p; - - bprintf(name, sizeof name, "%s$__init__", file->file.files[0]); - p = name; - while (*p) { - if (!isalnum(*p) && *p != '_') - *p = '$'; - p++; - } - n->decl.isinit = 1; - n->decl.vis = Vishidden; - n->decl.name->name.name = strdup(name); + char name[1024]; + char *p; + + bprintf(name, sizeof name, "%s$__init__", file->file.files[0]); + p = name; + while (*p) { + if (!isalnum(*p) && *p != '_') + *p = '$'; + p++; + } + n->decl.isinit = 1; + n->decl.vis = Vishidden; + n->decl.name->name.name = strdup(name); } static void addtrait(Type *t, char *str) { - size_t i; - - for (i = 0; i < ntraittab; i++) { - if (!strcmp(namestr(traittab[i]->name), str)) { - settrait(t, traittab[i]); - return; - } - } - lfatal(t->loc, "Constraint %s does not exist", str); + size_t i; + + for (i = 0; i < ntraittab; i++) { + if (!strcmp(namestr(traittab[i]->name), str)) { + settrait(t, traittab[i]); + return; + } + } + lfatal(t->loc, "Constraint %s does not exist", str); } static Node *mkpseudodecl(Srcloc l, Type *t) { - static int nextpseudoid; - char buf[128]; + static int nextpseudoid; + char buf[128]; - bprintf(buf, 128, ".pdecl%d", nextpseudoid++); - return mkdecl(l, mkname(l, buf), t); + bprintf(buf, 128, ".pdecl%d", nextpseudoid++); + return mkdecl(l, mkname(l, buf), t); } static void setattrs(Node *dcl, char **attrs, size_t nattrs) { - size_t i; - - for (i = 0; i < nattrs; i++) { - if (!strcmp(attrs[i], "extern")) - dcl->decl.isextern = 1; - else if (!strcmp(attrs[i], "$noret")) - dcl->decl.isnoret = 1; - else if (!strcmp(attrs[i], "pkglocal")) - dcl->decl.ispkglocal = 1; - } + size_t i; + + for (i = 0; i < nattrs; i++) { + if (!strcmp(attrs[i], "extern")) + dcl->decl.isextern = 1; + else if (!strcmp(attrs[i], "$noret")) + dcl->decl.isnoret = 1; + else if (!strcmp(attrs[i], "pkglocal")) + dcl->decl.ispkglocal = 1; + } } static void installucons(Stab *st, Type *t) { - Type *b; - size_t i; - - if (!t) - return; - b = tybase(t); - switch (b->type) { - case Tystruct: - for (i = 0; i < b->nmemb; i++) - installucons(st, b->sdecls[i]->decl.type); - break; - case Tyunion: - for (i = 0; i < b->nmemb; i++) { - b->udecls[i]->utype = b; - b->udecls[i]->id = i; - putucon(st, b->udecls[i]); - } - break; - default: - break; - } + Type *b; + size_t i; + + if (!t) + return; + b = tybase(t); + switch (b->type) { + case Tystruct: + for (i = 0; i < b->nmemb; i++) + installucons(st, b->sdecls[i]->decl.type); + break; + case Tyunion: + for (i = 0; i < b->nmemb; i++) { + b->udecls[i]->utype = b; + b->udecls[i]->id = i; + putucon(st, b->udecls[i]); + } + break; + default: + break; + } } static Op binop(int tt) { - Op o; - - o = Obad; - switch (tt) { - case Tplus: o = Oadd; break; - case Tminus: o = Osub; break; - case Tmul: o = Omul; break; - case Tdiv: o = Odiv; break; - case Tmod: o = Omod; break; - case Tasn: o = Oasn; break; - case Taddeq: o = Oaddeq; break; - case Tsubeq: o = Osubeq; break; - case Tmuleq: o = Omuleq; break; - case Tdiveq: o = Odiveq; break; - case Tmodeq: o = Omodeq; break; - case Tboreq: o = Oboreq; break; - case Tbxoreq: o = Obxoreq; break; - case Tbandeq: o = Obandeq; break; - case Tbsleq: o = Obsleq; break; - case Tbsreq: o = Obsreq; break; - case Tbor: o = Obor; break; - case Tbxor: o = Obxor; break; - case Tband: o = Oband; break; - case Tbsl: o = Obsl; break; - case Tbsr: o = Obsr; break; - case Teq: o = Oeq; break; - case Tgt: o = Ogt; break; - case Tlt: o = Olt; break; - case Tge: o = Oge; break; - case Tle: o = Ole; break; - case Tne: o = One; break; - case Tlor: o = Olor; break; - case Tland: o = Oland; break; - default: - die("Unimplemented binop\n"); - break; - } - return o; + Op o; + + o = Obad; + switch (tt) { + case Tplus: o = Oadd; break; + case Tminus: o = Osub; break; + case Tmul: o = Omul; break; + case Tdiv: o = Odiv; break; + case Tmod: o = Omod; break; + case Tasn: o = Oasn; break; + case Taddeq: o = Oaddeq; break; + case Tsubeq: o = Osubeq; break; + case Tmuleq: o = Omuleq; break; + case Tdiveq: o = Odiveq; break; + case Tmodeq: o = Omodeq; break; + case Tboreq: o = Oboreq; break; + case Tbxoreq: o = Obxoreq; break; + case Tbandeq: o = Obandeq; break; + case Tbsleq: o = Obsleq; break; + case Tbsreq: o = Obsreq; break; + case Tbor: o = Obor; break; + case Tbxor: o = Obxor; break; + case Tband: o = Oband; break; + case Tbsl: o = Obsl; break; + case Tbsr: o = Obsr; break; + case Teq: o = Oeq; break; + case Tgt: o = Ogt; break; + case Tlt: o = Olt; break; + case Tge: o = Oge; break; + case Tle: o = Ole; break; + case Tne: o = One; break; + case Tlor: o = Olor; break; + case Tland: o = Oland; break; + default: + die("Unimplemented binop\n"); + break; + } + return o; } diff --git a/parse/htab.c b/parse/htab.c index 1bdad3a..a8f3633 100644 --- a/parse/htab.c +++ b/parse/htab.c @@ -15,45 +15,45 @@ * hash collisions. */ Htab *mkht(ulong (*hash)(void *key), int (*cmp)(void *k1, void *k2)) { - Htab *ht; - - ht = xalloc(sizeof(Htab)); - ht->nelt = 0; - ht->ndead = 0; - ht->sz = Initsz; - ht->hash = hash; - ht->cmp = cmp; - ht->keys = zalloc(Initsz*sizeof(void*)); - ht->vals = zalloc(Initsz*sizeof(void*)); - ht->hashes = zalloc(Initsz*sizeof(void*)); - ht->dead = zalloc(Initsz*sizeof(char)); - - return ht; + Htab *ht; + + ht = xalloc(sizeof(Htab)); + ht->nelt = 0; + ht->ndead = 0; + ht->sz = Initsz; + ht->hash = hash; + ht->cmp = cmp; + ht->keys = zalloc(Initsz * sizeof(void *)); + ht->vals = zalloc(Initsz * sizeof(void *)); + ht->hashes = zalloc(Initsz * sizeof(void *)); + ht->dead = zalloc(Initsz * sizeof(char)); + + return ht; } /* Frees a hash table. Passing this function * NULL is a no-op. */ void htfree(Htab *ht) { - if (!ht) - return; - free(ht->keys); - free(ht->vals); - free(ht->hashes); - free(ht->dead); - free(ht); + if (!ht) + return; + free(ht->keys); + free(ht->vals); + free(ht->hashes); + free(ht->dead); + free(ht); } /* Offsets the hash so that '0' can be * used as a 'no valid value */ static ulong hash(Htab *ht, void *k) { - ulong h; - h = ht->hash(k); - if (h == 0) - return 1; - else - return h; + ulong h; + h = ht->hash(k); + if (h == 0) + return 1; + else + return h; } /* Resizes the hash table by copying all @@ -61,35 +61,35 @@ static ulong hash(Htab *ht, void *k) * new table. */ static void grow(Htab *ht, int sz) { - void **oldk; - void **oldv; - ulong *oldh; - char *oldd; - int oldsz; - int i; - - oldk = ht->keys; - oldv = ht->vals; - oldh = ht->hashes; - oldd = ht->dead; - oldsz = ht->sz; - - ht->nelt = 0; - ht->ndead = 0; - ht->sz = sz; - ht->keys = zalloc(sz*sizeof(void*)); - ht->vals = zalloc(sz*sizeof(void*)); - ht->hashes = zalloc(sz*sizeof(void*)); - ht->dead = zalloc(sz*sizeof(void*)); - - for (i = 0; i < oldsz; i++) - if (oldh[i] && !oldd[i]) - htput(ht, oldk[i], oldv[i]); - - free(oldh); - free(oldk); - free(oldv); - free(oldd); + void **oldk; + void **oldv; + ulong *oldh; + char *oldd; + int oldsz; + int i; + + oldk = ht->keys; + oldv = ht->vals; + oldh = ht->hashes; + oldd = ht->dead; + oldsz = ht->sz; + + ht->nelt = 0; + ht->ndead = 0; + ht->sz = sz; + ht->keys = zalloc(sz * sizeof(void *)); + ht->vals = zalloc(sz * sizeof(void *)); + ht->hashes = zalloc(sz * sizeof(void *)); + ht->dead = zalloc(sz * sizeof(void *)); + + for (i = 0; i < oldsz; i++) + if (oldh[i] && !oldd[i]) + htput(ht, oldk[i], oldv[i]); + + free(oldh); + free(oldk); + free(oldv); + free(oldd); } /* Inserts 'k' into the hash table, possibly @@ -97,62 +97,62 @@ static void grow(Htab *ht, int sz) * as equal. */ int htput(Htab *ht, void *k, void *v) { - int i; - ulong h; - int di; - - di = 0; - h = hash(ht, k); - i = h & (ht->sz - 1); - while (ht->hashes[i] && !ht->dead[i]) { - /* second insertion overwrites first. nb, we shouldn't touch the - * keys for dead values */ - if (ht->hashes[i] == h) { - if (ht->dead[i]) - break; - else if (ht->cmp(ht->keys[i], k)) - goto conflicted; - } - di++; - i = (h + di) & (ht->sz - 1); - } - ht->nelt++; + int i; + ulong h; + int di; + + di = 0; + h = hash(ht, k); + i = h & (ht->sz - 1); + while (ht->hashes[i] && !ht->dead[i]) { + /* second insertion overwrites first. nb, we shouldn't touch the + * keys for dead values */ + if (ht->hashes[i] == h) { + if (ht->dead[i]) + break; + else if (ht->cmp(ht->keys[i], k)) + goto conflicted; + } + di++; + i = (h + di) & (ht->sz - 1); + } + ht->nelt++; conflicted: - if (ht->dead[i]) - ht->ndead--; - ht->hashes[i] = h; - ht->keys[i] = k; - ht->vals[i] = v; - ht->dead[i] = 0; - - if (ht->sz < ht->nelt * 2) - grow(ht, ht->sz * 2); - if (ht->sz < ht->ndead * 4) - grow(ht, ht->sz); - return 1; + if (ht->dead[i]) + ht->ndead--; + ht->hashes[i] = h; + ht->keys[i] = k; + ht->vals[i] = v; + ht->dead[i] = 0; + + if (ht->sz < ht->nelt * 2) + grow(ht, ht->sz * 2); + if (ht->sz < ht->ndead * 4) + grow(ht, ht->sz); + return 1; } /* Finds the index that we would insert * the key into */ static ssize_t htidx(Htab *ht, void *k) { - ssize_t i; - ulong h; - int di; - - di = 0; - h = hash(ht, k); - i = h & (ht->sz - 1); - while (ht->hashes[i] && !ht->dead[i] && ht->hashes[i] != h) { + ssize_t i; + ulong h; + int di; + + di = 0; + h = hash(ht, k); + i = h & (ht->sz - 1); + while (ht->hashes[i] && !ht->dead[i] && ht->hashes[i] != h) { searchmore: - di++; - i = (h + di) & (ht->sz - 1); - } - if (!ht->hashes[i]) - return -1; - if ((ht->hashes[i] == h && ht->dead[i]) || !ht->cmp(ht->keys[i], k)) - goto searchmore; /* collision */ - return i; + di++; + i = (h + di) & (ht->sz - 1); + } + if (!ht->hashes[i]) + return -1; + if ((ht->hashes[i] == h && ht->dead[i]) || !ht->cmp(ht->keys[i], k)) + goto searchmore; /* collision */ + return i; } /* Looks up a key, returning NULL if @@ -162,35 +162,31 @@ searchmore: * not there */ void *htget(Htab *ht, void *k) { - ssize_t i; + ssize_t i; - i = htidx(ht, k); - if (i < 0) - return NULL; - else - return ht->vals[i]; + i = htidx(ht, k); + if (i < 0) + return NULL; + else + return ht->vals[i]; } void htdel(Htab *ht, void *k) { - ssize_t i; - - i = htidx(ht, k); - if (i < 0) - return; - assert(!ht->dead[i]); - assert(ht->hashes[i]); - ht->dead[i] = 1; - ht->nelt--; - ht->ndead++; + ssize_t i; + + i = htidx(ht, k); + if (i < 0) + return; + assert(!ht->dead[i]); + assert(ht->hashes[i]); + ht->dead[i] = 1; + ht->nelt--; + ht->ndead++; } - /* Tests for 'k's presence in 'ht' */ -int hthas(Htab *ht, void *k) -{ - return htidx(ht, k) >= 0; -} +int hthas(Htab *ht, void *k) { return htidx(ht, k) >= 0; } /* Returns a list of all keys in the hash * table, storing the size of the returned @@ -199,103 +195,94 @@ int hthas(Htab *ht, void *k) * job of the caller to free it */ void **htkeys(Htab *ht, size_t *nkeys) { - void **k; - size_t i, j; - - j = 0; - k = xalloc(sizeof(void*)*ht->nelt); - for (i = 0; i < ht->sz; i++) - if (ht->hashes[i] && !ht->dead[i]) - k[j++] = ht->keys[i]; - *nkeys = ht->nelt; - return k; + void **k; + size_t i, j; + + j = 0; + k = xalloc(sizeof(void *) * ht->nelt); + for (i = 0; i < ht->sz; i++) + if (ht->hashes[i] && !ht->dead[i]) + k[j++] = ht->keys[i]; + *nkeys = ht->nelt; + return k; } ulong strhash(void *_s) { - char *s; - ulong h; - ulong g; + char *s; + ulong h; + ulong g; - s = _s; - h = 0; - while (s && *s) { - h = ((h << 4) + *s++); + s = _s; + h = 0; + while (s && *s) { + h = ((h << 4) + *s++); - if ((g = (h & 0xF0000000))) - h ^= (g >> 24); + if ((g = (h & 0xF0000000))) + h ^= (g >> 24); - h &= ~g; - } - return h; + h &= ~g; + } + return h; } int streq(void *a, void *b) { - if (a == b) - return 1; - if (a == NULL || b == NULL) - return 0; - return !strcmp(a, b); + if (a == b) + return 1; + if (a == NULL || b == NULL) + return 0; + return !strcmp(a, b); } ulong strlithash(void *_s) { - Str *s; - ulong h, g, i; + Str *s; + ulong h, g, i; - s = _s; - h = 0; - for (i = 0; i < s->len; i++) { - h = ((h << 4) + s->buf[i]); + s = _s; + h = 0; + for (i = 0; i < s->len; i++) { + h = ((h << 4) + s->buf[i]); - if ((g = (h & 0xF0000000))) - h ^= (g >> 24); + if ((g = (h & 0xF0000000))) + h ^= (g >> 24); - h &= ~g; - } - return h; + h &= ~g; + } + return h; } int strliteq(void *_a, void *_b) { - Str *a, *b; - - a = _a; - b = _b; - if (a == b) - return 1; - if (a == NULL || b == NULL) - return 0; - if (a->len != b->len) - return 0; - return !memcmp(a, b, a->len); + Str *a, *b; + + a = _a; + b = _b; + if (a == b) + return 1; + if (a == NULL || b == NULL) + return 0; + if (a->len != b->len) + return 0; + return !memcmp(a, b, a->len); } -ulong ptrhash(void *key) -{ - return inthash((uintptr_t)key); -} +ulong ptrhash(void *key) { return inthash((uintptr_t)key); } ulong inthash(uint64_t key) { - uintptr_t h; - - h = (uintptr_t) key; - h *= 357913941; - h ^= h << 24; - h += ~357913941; - h ^= h >> 31; - h ^= h << 31; - return h; + uintptr_t h; + + h = (uintptr_t)key; + h *= 357913941; + h ^= h << 24; + h += ~357913941; + h ^= h >> 31; + h ^= h << 31; + return h; } -int inteq(uint64_t a, uint64_t b) -{ - return a == b; -} +int inteq(uint64_t a, uint64_t b) { return a == b; } -int ptreq(void *a, void *b) -{ - return a == b; -} +int ptreq(void *a, void *b) { return a == b; } diff --git a/parse/infer.c b/parse/infer.c index 7f5de51..3b5e413 100644 --- a/parse/infer.c +++ b/parse/infer.c @@ -16,36 +16,36 @@ typedef struct Inferstate Inferstate; struct Inferstate { - int ingeneric; - int inaggr; - int innamed; - int sawret; - int indentdepth; - Type *ret; - - /* bound by patterns turn into decls in the action block */ - Node **binds; - size_t nbinds; - /* nodes that need post-inference checking/unification */ - Node **postcheck; - size_t npostcheck; - Stab **postcheckscope; - size_t npostcheckscope; - /* the type params bound at the current point */ - Htab **tybindings; - size_t ntybindings; - /* generic declarations to be specialized */ - Node **genericdecls; - size_t ngenericdecls; - /* delayed unification -- we fall back to these types in a post pass if we - * haven't unifed to something more specific */ - Htab *delayed; - /* the nodes that we've specialized them to, and the scopes they - * appear in */ - Node **specializations; - size_t nspecializations; - Stab **specializationscope; - size_t nspecializationscope; + int ingeneric; + int inaggr; + int innamed; + int sawret; + int indentdepth; + Type *ret; + + /* bound by patterns turn into decls in the action block */ + Node **binds; + size_t nbinds; + /* nodes that need post-inference checking/unification */ + Node **postcheck; + size_t npostcheck; + Stab **postcheckscope; + size_t npostcheckscope; + /* the type params bound at the current point */ + Htab **tybindings; + size_t ntybindings; + /* generic declarations to be specialized */ + Node **genericdecls; + size_t ngenericdecls; + /* delayed unification -- we fall back to these types in a post pass if we + * haven't unifed to something more specific */ + Htab *delayed; + /* the nodes that we've specialized them to, and the scopes they + * appear in */ + Node **specializations; + size_t nspecializations; + Stab **specializationscope; + size_t nspecializationscope; }; static void infernode(Inferstate *st, Node **np, Type *ret, int *sawret); @@ -62,211 +62,195 @@ static Type *tf(Inferstate *st, Type *t); static void ctxstrcall(char *buf, size_t sz, Inferstate *st, Node *n) { - char *p, *end, *sep, *t; - size_t nargs, i; - Node **args; - Type *et; - - args = n->expr.args; - nargs = n->expr.nargs; - p = buf; - end = buf + sz; - sep = ""; - - if (exprop(args[0]) == Ovar) - p += bprintf(p, end - p, "%s(", namestr(args[0]->expr.args[0])); - else - p += bprintf(p, end - p, "("); - for (i = 1; i < nargs; i++) { - et = tyfix(st, NULL, exprtype(args[i]), 1); - if (et != NULL) - t = tystr(et); - else - t = strdup("?"); - - if (exprop(args[i]) == Ovar) - p += bprintf(p, end - p, "%s%s:%s", sep, namestr(args[0]->expr.args[0]), t); - else - p += bprintf(p, end - p, "%s:%s", sep, i, t); - sep = ", "; - free(t); - } - if (exprtype(args[0])->nsub) - t = tystr(tyfix(st, NULL, exprtype(args[0])->sub[0], 1)); - else - t = strdup("unknown"); - p += bprintf(p, end - p, "): %s", t); - free(t); + char *p, *end, *sep, *t; + size_t nargs, i; + Node **args; + Type *et; + + args = n->expr.args; + nargs = n->expr.nargs; + p = buf; + end = buf + sz; + sep = ""; + + if (exprop(args[0]) == Ovar) + p += bprintf(p, end - p, "%s(", namestr(args[0]->expr.args[0])); + else + p += bprintf(p, end - p, "("); + for (i = 1; i < nargs; i++) { + et = tyfix(st, NULL, exprtype(args[i]), 1); + if (et != NULL) + t = tystr(et); + else + t = strdup("?"); + + if (exprop(args[i]) == Ovar) + p += bprintf(p, end - p, "%s%s:%s", sep, namestr(args[0]->expr.args[0]), t); + else + p += bprintf(p, end - p, "%s:%s", sep, i, t); + sep = ", "; + free(t); + } + if (exprtype(args[0])->nsub) + t = tystr(tyfix(st, NULL, exprtype(args[0])->sub[0], 1)); + else + t = strdup("unknown"); + p += bprintf(p, end - p, "): %s", t); + free(t); } static char *nodetystr(Inferstate *st, Node *n) { - Type *t; + Type *t; - t = NULL; - if (n->type == Nexpr && exprtype(n) != NULL) - t = tyfix(st, NULL, exprtype(n), 1); - else if (n->type == Ndecl && decltype(n) != NULL) - t = tyfix(st, NULL, decltype(n), 1); + t = NULL; + if (n->type == Nexpr && exprtype(n) != NULL) + t = tyfix(st, NULL, exprtype(n), 1); + else if (n->type == Ndecl && decltype(n) != NULL) + t = tyfix(st, NULL, decltype(n), 1); - if (t && tybase(t)->type != Tyvar) - return tystr(t); - else - return strdup("unknown"); + if (t && tybase(t)->type != Tyvar) + return tystr(t); + else + return strdup("unknown"); } /* Tries to give a good string describing the context * for the sake of error messages. */ static char *ctxstr(Inferstate *st, Node *n) { - char *t, *t1, *t2, *t3; - char *s, *d; - size_t nargs; - Node **args; - char buf[512]; - - switch (n->type) { - default: - s = strdup(nodestr[n->type]); - break; - case Ndecl: - d = declname(n); - t = nodetystr(st, n); - bprintf(buf, sizeof buf, "%s:%s", d, t); - s = strdup(buf); - free(t); - break; - case Nname: - s = strdup(namestr(n)); - break; - case Nexpr: - args = n->expr.args; - nargs = n->expr.nargs; - t1 = NULL; - t2 = NULL; - t3 = NULL; - if (exprop(n) == Ovar) - d = namestr(args[0]); - else - d = opstr[exprop(n)]; - t = nodetystr(st, n); - if (nargs >= 1) - t1 = nodetystr(st, args[0]); - if (nargs >= 2) - t2 = nodetystr(st, args[1]); - if (nargs >= 3) - t3 = nodetystr(st, args[2]); - switch (opclass[exprop(n)]) { - case OTbin: - bprintf(buf, sizeof buf, " %s ", t1, oppretty[exprop(n)], t2); - break; - case OTpre: - bprintf(buf, sizeof buf, "%s", t1, oppretty[exprop(n)]); - break; - case OTpost: - bprintf(buf, sizeof buf, "%s", t1, oppretty[exprop(n)]); - break; - case OTzarg: - bprintf(buf, sizeof buf, "%s", oppretty[exprop(n)]); - break; - case OTmisc: - switch (exprop(n)) { - case Ovar: - bprintf(buf, sizeof buf, "%s:%s", namestr(args[0]), t); - break; - case Ocall: - ctxstrcall(buf, sizeof buf, st, n); - break; - case Oidx: - if (exprop(args[0]) == Ovar) - bprintf(buf, sizeof buf, "%s[]", namestr(args[0]->expr.args[0]), t2); - else - bprintf(buf, sizeof buf, "[]", t1, t2); - break; - case Oslice: - if (exprop(args[0]) == Ovar) - bprintf(buf, sizeof buf, "%s[:]", namestr(args[0]->expr.args[0]), t2, t3); - else - bprintf(buf, sizeof buf, "[:]", t1, t2, t3); - break; - case Omemb: - bprintf(buf, sizeof buf, "<%s>.%s", t1, namestr(args[1])); - break; - default: - bprintf(buf, sizeof buf, "%s:%s", d, t); - break; - } - break; - default: - bprintf(buf, sizeof buf, "%s", d); - break; - } - free(t); - free(t1); - free(t2); - free(t3); - s = strdup(buf); - break; - } - return s; + char *t, *t1, *t2, *t3; + char *s, *d; + size_t nargs; + Node **args; + char buf[512]; + + switch (n->type) { + default: s = strdup(nodestr[n->type]); break; + case Ndecl: + d = declname(n); + t = nodetystr(st, n); + bprintf(buf, sizeof buf, "%s:%s", d, t); + s = strdup(buf); + free(t); + break; + case Nname: s = strdup(namestr(n)); break; + case Nexpr: + args = n->expr.args; + nargs = n->expr.nargs; + t1 = NULL; + t2 = NULL; + t3 = NULL; + if (exprop(n) == Ovar) + d = namestr(args[0]); + else + d = opstr[exprop(n)]; + t = nodetystr(st, n); + if (nargs >= 1) + t1 = nodetystr(st, args[0]); + if (nargs >= 2) + t2 = nodetystr(st, args[1]); + if (nargs >= 3) + t3 = nodetystr(st, args[2]); + + switch (opclass[exprop(n)]) { + case OTpre: bprintf(buf, sizeof buf, "%s", t1, oppretty[exprop(n)]); break; + case OTpost: bprintf(buf, sizeof buf, "%s", t1, oppretty[exprop(n)]); break; + case OTzarg: bprintf(buf, sizeof buf, "%s", oppretty[exprop(n)]); break; + case OTmisc: + case OTbin: + bprintf(buf, sizeof buf, " %s ", t1, oppretty[exprop(n)], t2); + break; + switch (exprop(n)) { + case Ovar: bprintf(buf, sizeof buf, "%s:%s", namestr(args[0]), t); break; + case Ocall: ctxstrcall(buf, sizeof buf, st, n); break; + case Oidx: + if (exprop(args[0]) == Ovar) + bprintf(buf, sizeof buf, "%s[]", namestr(args[0]->expr.args[0]), t2); + else + bprintf(buf, sizeof buf, "[]", t1, t2); + break; + case Oslice: + if (exprop(args[0]) == Ovar) + bprintf(buf, sizeof buf, "%s[:]", namestr(args[0]->expr.args[0]), t2, t3); + else + bprintf( buf, sizeof buf, "[:]", t1, t2, t3); + break; + case Omemb: + bprintf(buf, sizeof buf, "<%s>.%s", t1, namestr(args[1])); + break; + default: + bprintf(buf, sizeof buf, "%s:%s", d, t); + break; + } + break; + default: bprintf(buf, sizeof buf, "%s", d); break; + } + free(t); + free(t1); + free(t2); + free(t3); + s = strdup(buf); + break; + } + return s; } static void addspecialization(Inferstate *st, Node *n, Stab *stab) { - Node *dcl; + Node *dcl; - dcl = decls[n->expr.did]; - lappend(&st->specializationscope, &st->nspecializationscope, stab); - lappend(&st->specializations, &st->nspecializations, n); - lappend(&st->genericdecls, &st->ngenericdecls, dcl); + dcl = decls[n->expr.did]; + lappend(&st->specializationscope, &st->nspecializationscope, stab); + lappend(&st->specializations, &st->nspecializations, n); + lappend(&st->genericdecls, &st->ngenericdecls, dcl); } static void delayedcheck(Inferstate *st, Node *n, Stab *s) { - lappend(&st->postcheck, &st->npostcheck, n); - lappend(&st->postcheckscope, &st->npostcheckscope, s); + lappend(&st->postcheck, &st->npostcheck, n); + lappend(&st->postcheckscope, &st->npostcheckscope, s); } static void typeerror(Inferstate *st, Type *a, Type *b, Node *ctx, char *msg) { - char *t1, *t2, *c; + char *t1, *t2, *c; - t1 = tystr(tyfix(st, NULL, a, 1)); - t2 = tystr(tyfix(st, NULL, b, 1)); - c = ctxstr(st, ctx); - if (msg) - fatal(ctx, "type \"%s\" incompatible with \"%s\" near %s: %s", t1, t2, c, msg); - else - fatal(ctx, "type \"%s\" incompatible with \"%s\" near %s", t1, t2, c); - free(t1); - free(t2); - free(c); + t1 = tystr(tyfix(st, NULL, a, 1)); + t2 = tystr(tyfix(st, NULL, b, 1)); + c = ctxstr(st, ctx); + if (msg) + fatal(ctx, "type \"%s\" incompatible with \"%s\" near %s: %s", t1, t2, c, msg); + else + fatal(ctx, "type \"%s\" incompatible with \"%s\" near %s", t1, t2, c); + free(t1); + free(t2); + free(c); } - /* Set a scope's enclosing scope up correctly. * We don't do this in the parser for some reason. */ static void setsuper(Stab *st, Stab *super) { - Stab *s; + Stab *s; - /* verify that we don't accidentally create loops */ - for (s = super; s; s = s->super) - assert(s->super != st); - st->super = super; + /* verify that we don't accidentally create loops */ + for (s = super; s; s = s->super) + assert(s->super != st); + st->super = super; } /* If the current environment binds a type, * we return true */ static int isbound(Inferstate *st, Type *t) { - ssize_t i; + ssize_t i; - for (i = st->ntybindings - 1; i >= 0; i--) { - if (htget(st->tybindings[i], t->pname)) - return 1; - } - return 0; + for (i = st->ntybindings - 1; i >= 0; i--) { + if (htget(st->tybindings[i], t->pname)) + return 1; + } + return 0; } /* Checks if a type that directly contains itself. @@ -275,451 +259,452 @@ static int isbound(Inferstate *st, Type *t) * would lead to a value of infinite size */ static int tyinfinite(Inferstate *st, Type *t, Type *sub) { - size_t i; - - assert(t != NULL); - if (t == sub) /* FIXME: is this actually right? */ - return 1; - /* if we're on the first iteration, the subtype is the type - * itself. The assignment must come after the equality check - * for obvious reasons. */ - if (!sub) - sub = t; - - switch (sub->type) { - case Tystruct: - for (i = 0; i < sub->nmemb; i++) - if (tyinfinite(st, t, decltype(sub->sdecls[i]))) - return 1; - break; - case Tyunion: - for (i = 0; i < sub->nmemb; i++) { - if (sub->udecls[i]->etype && tyinfinite(st, t, sub->udecls[i]->etype)) - return 1; - } - break; - - case Typtr: - case Tyslice: - return 0; - default: - for (i = 0; i < sub->nsub; i++) - if (tyinfinite(st, t, sub->sub[i])) - return 1; - break; - } - return 0; + size_t i; + + assert(t != NULL); + if (t == sub) /* FIXME: is this actually right? */ + return 1; + /* if we're on the first iteration, the subtype is the type + * itself. The assignment must come after the equality check + * for obvious reasons. */ + if (!sub) + sub = t; + + switch (sub->type) { + case Tystruct: + for (i = 0; i < sub->nmemb; i++) + if (tyinfinite(st, t, decltype(sub->sdecls[i]))) + return 1; + break; + case Tyunion: + for (i = 0; i < sub->nmemb; i++) { + if (sub->udecls[i]->etype && tyinfinite(st, t, sub->udecls[i]->etype)) + return 1; + } + break; + case Typtr: + case Tyslice: return 0; + default: + for (i = 0; i < sub->nsub; i++) + if (tyinfinite(st, t, sub->sub[i])) + return 1; + break; + } + return 0; } - static int needfreshenrec(Inferstate *st, Type *t, Bitset *visited) { - size_t i; - - if (bshas(visited, t->tid)) - return 0; - bsput(visited, t->tid); - switch (t->type) { - case Typaram: return 1; - case Tygeneric: return 1; - case Tyname: - for (i = 0; i < t->narg; i++) - if (needfreshenrec(st, t->arg[i], visited)) - return 1; - return needfreshenrec(st, t->sub[0], visited); - case Tystruct: - for (i = 0; i < t->nmemb; i++) - if (needfreshenrec(st, decltype(t->sdecls[i]), visited)) - return 1; - break; - case Tyunion: - for (i = 0; i < t->nmemb; i++) - if (t->udecls[i]->etype && needfreshenrec(st, t->udecls[i]->etype, visited)) - return 1; - break; - default: - for (i = 0; i < t->nsub; i++) - if (needfreshenrec(st, t->sub[i], visited)) - return 1; - break; - } - return 0; + size_t i; + + if (bshas(visited, t->tid)) + return 0; + bsput(visited, t->tid); + switch (t->type) { + case Typaram: return 1; + case Tygeneric: return 1; + case Tyname: + for (i = 0; i < t->narg; i++) + if (needfreshenrec(st, t->arg[i], visited)) + return 1; + return needfreshenrec(st, t->sub[0], visited); + case Tystruct: + for (i = 0; i < t->nmemb; i++) + if (needfreshenrec(st, decltype(t->sdecls[i]), visited)) + return 1; + break; + case Tyunion: + for (i = 0; i < t->nmemb; i++) + if (t->udecls[i]->etype && needfreshenrec(st, t->udecls[i]->etype, visited)) + return 1; + break; + default: + for (i = 0; i < t->nsub; i++) + if (needfreshenrec(st, t->sub[i], visited)) + return 1; + break; + } + return 0; } static int needfreshen(Inferstate *st, Type *t) { - Bitset *visited; - int ret; + Bitset *visited; + int ret; - visited = mkbs(); - ret = needfreshenrec(st, t, visited); - bsfree(visited); - return ret; + visited = mkbs(); + ret = needfreshenrec(st, t, visited); + bsfree(visited); + return ret; } /* Freshens the type of a declaration. */ static Type *tyfreshen(Inferstate *st, Htab *subst, Type *t) { - char *from, *to; - - if (!needfreshen(st, t)) { - if (debugopt['u']) - indentf(st->indentdepth, "%s isn't generic: skipping freshen\n", tystr(t)); - return t; - } - - from = tystr(t); - tybind(st, t); - if (!subst) { - subst = mkht(tyhash, tyeq); - t = tyspecialize(t, subst, st->delayed); - htfree(subst); - } else { - t = tyspecialize(t, subst, st->delayed); - } - tyunbind(st, t); - if (debugopt['u']) { - to = tystr(t); - indentf(st->indentdepth, "Freshen %s => %s\n", from, to); - free(from); - free(to); - } - - return t; + char *from, *to; + + if (!needfreshen(st, t)) { + if (debugopt['u']) + indentf(st->indentdepth, "%s isn't generic: skipping freshen\n", tystr(t)); + return t; + } + + from = tystr(t); + tybind(st, t); + if (!subst) { + subst = mkht(tyhash, tyeq); + t = tyspecialize(t, subst, st->delayed); + htfree(subst); + } + else { + t = tyspecialize(t, subst, st->delayed); + } + tyunbind(st, t); + if (debugopt['u']) { + to = tystr(t); + indentf(st->indentdepth, "Freshen %s => %s\n", from, to); + free(from); + free(to); + } + + return t; } /* Resolves a type and all it's subtypes recursively.*/ static void tyresolve(Inferstate *st, Type *t) { - size_t i; - Type *base; - - if (t->resolved) - return; - /* type resolution should never throw errors about non-generics - * showing up within a generic type, so we push and pop a generic - * around resolution */ - st->ingeneric++; - t->resolved = 1; - /* Walk through aggregate type members */ - if (t->type == Tystruct) { - st->inaggr++; - for (i = 0; i < t->nmemb; i++) - infernode(st, &t->sdecls[i], NULL, NULL); - st->inaggr--; - } else if (t->type == Tyunion) { - st->inaggr++; - for (i = 0; i < t->nmemb; i++) { - t->udecls[i]->utype = t; - t->udecls[i]->utype = tf(st, t->udecls[i]->utype); - if (t->udecls[i]->etype) { - tyresolve(st, t->udecls[i]->etype); - t->udecls[i]->etype = tf(st, t->udecls[i]->etype); - } - } - st->inaggr--; - } else if (t->type == Tyarray) { - if (!st->inaggr && !t->asize) - lfatal(t->loc, "unsized array type outside of struct"); - infernode(st, &t->asize, NULL, NULL); - } else if (t->type == Typaram && st->innamed) { - if (!isbound(st, t)) - lfatal(t->loc, "type parameter %s is undefined in generic context", tystr(t)); - } - - if (t->type == Tyname || t->type == Tygeneric) { - tybind(st, t); - st->innamed++; - } - for (i = 0; i < t->nsub; i++) - t->sub[i] = tf(st, t->sub[i]); - base = tybase(t); - /* no-ops if base == t */ - if (t->traits) - bsunion(t->traits, base->traits); - else - t->traits = bsdup(base->traits); - if (tyinfinite(st, t, NULL)) - lfatal(t->loc, "type %s includes itself", tystr(t)); - st->ingeneric--; - if (t->type == Tyname || t->type == Tygeneric) { - tyunbind(st, t); - st->innamed--; - } + size_t i; + Type *base; + + if (t->resolved) + return; + /* type resolution should never throw errors about non-generics + * showing up within a generic type, so we push and pop a generic + * around resolution */ + st->ingeneric++; + t->resolved = 1; + /* Walk through aggregate type members */ + if (t->type == Tystruct) { + st->inaggr++; + for (i = 0; i < t->nmemb; i++) + infernode(st, &t->sdecls[i], NULL, NULL); + st->inaggr--; + } + else if (t->type == Tyunion) { + st->inaggr++; + for (i = 0; i < t->nmemb; i++) { + t->udecls[i]->utype = t; + t->udecls[i]->utype = tf(st, t->udecls[i]->utype); + if (t->udecls[i]->etype) { + tyresolve(st, t->udecls[i]->etype); + t->udecls[i]->etype = tf(st, t->udecls[i]->etype); + } + } + st->inaggr--; + } + else if (t->type == Tyarray) { + if (!st->inaggr && !t->asize) + lfatal(t->loc, "unsized array type outside of struct"); + infernode(st, &t->asize, NULL, NULL); + } + else if (t->type == Typaram && st->innamed) { + if (!isbound(st, t)) + lfatal( + t->loc, "type parameter %s is undefined in generic context", tystr(t)); + } + + if (t->type == Tyname || t->type == Tygeneric) { + tybind(st, t); + st->innamed++; + } + for (i = 0; i < t->nsub; i++) + t->sub[i] = tf(st, t->sub[i]); + base = tybase(t); + /* no-ops if base == t */ + if (t->traits) + bsunion(t->traits, base->traits); + else + t->traits = bsdup(base->traits); + if (tyinfinite(st, t, NULL)) + lfatal(t->loc, "type %s includes itself", tystr(t)); + st->ingeneric--; + if (t->type == Tyname || t->type == Tygeneric) { + tyunbind(st, t); + st->innamed--; + } } /* Look up the best type to date in the unification table, returning it */ Type *tysearch(Type *t) { - Type *lu; - Stab *ns; - - assert(t != NULL); - lu = NULL; - while (1) { - if (!tytab[t->tid] && t->type == Tyunres) { - ns = curstab(); - if (t->name->name.ns) { - ns = getns(file, t->name->name.ns); - } - if (!ns) - fatal(t->name, "could not resolve namespace \"%s\"", t->name->name.ns); - if (!(lu = gettype(ns, t->name))) - fatal(t->name, "could not resolve type %s", tystr(t)); - tytab[t->tid] = lu; - } - - if (!tytab[t->tid]) - break; - /* compress paths: shift the link up one level */ - if (tytab[tytab[t->tid]->tid]) - tytab[t->tid] = tytab[tytab[t->tid]->tid]; - t = tytab[t->tid]; - } - return t; + Type *lu; + Stab *ns; + + assert(t != NULL); + lu = NULL; + while (1) { + if (!tytab[t->tid] && t->type == Tyunres) { + ns = curstab(); + if (t->name->name.ns) { + ns = getns(file, t->name->name.ns); + } + if (!ns) + fatal(t->name, "could not resolve namespace \"%s\"", + t->name->name.ns); + if (!(lu = gettype(ns, t->name))) + fatal(t->name, "could not resolve type %s", tystr(t)); + tytab[t->tid] = lu; + } + + if (!tytab[t->tid]) + break; + /* compress paths: shift the link up one level */ + if (tytab[tytab[t->tid]->tid]) + tytab[t->tid] = tytab[tytab[t->tid]->tid]; + t = tytab[t->tid]; + } + return t; } static Type *tysubst(Inferstate *st, Type *t, Type *orig) { - Htab *subst; - size_t i; + Htab *subst; + size_t i; - subst = mkht(tyhash, tyeq); - for (i = 0; i < t->ngparam; i++) { - htput(subst, t->gparam[i], tf(st, orig->arg[i])); - } - t = tyfreshen(st, subst, t); - htfree(subst); - return t; + subst = mkht(tyhash, tyeq); + for (i = 0; i < t->ngparam; i++) { + htput(subst, t->gparam[i], tf(st, orig->arg[i])); + } + t = tyfreshen(st, subst, t); + htfree(subst); + return t; } /* fixd the most accurate type mapping we have (ie, * the end of the unification chain */ static Type *tf(Inferstate *st, Type *orig) { - int isgeneric; - Type *t; - - assert(orig != NULL); - t = tysearch(orig); - isgeneric = t->type == Tygeneric; - st->ingeneric += isgeneric; - tyresolve(st, t); - /* If this is an instantiation of a generic type, we want the params to - * match the instantiation */ - if (orig->type == Tyunres && t->type == Tygeneric) { - if (t->ngparam != orig->narg) { - lfatal(orig->loc, "%s incompatibly specialized with %s, declared on %s:%d", - tystr(orig), tystr(t), file->file.files[t->loc.file], t->loc.line); - } - t = tysubst(st, t, orig); - } - st->ingeneric -= isgeneric; - return t; + int isgeneric; + Type *t; + + assert(orig != NULL); + t = tysearch(orig); + isgeneric = t->type == Tygeneric; + st->ingeneric += isgeneric; + tyresolve(st, t); + /* If this is an instantiation of a generic type, we want the params to + * match the instantiation */ + if (orig->type == Tyunres && t->type == Tygeneric) { + if (t->ngparam != orig->narg) { + lfatal(orig->loc, "%s incompatibly specialized with %s, declared on %s:%d", + tystr(orig), tystr(t), file->file.files[t->loc.file], t->loc.line); + } + t = tysubst(st, t, orig); + } + st->ingeneric -= isgeneric; + return t; } /* set the type of any typable node */ static void settype(Inferstate *st, Node *n, Type *t) { - t = tf(st, t); - switch (n->type) { - case Nexpr: n->expr.type = t; break; - case Ndecl: n->decl.type = t; break; - case Nlit: n->lit.type = t; break; - case Nfunc: n->func.type = t; break; - default: - die("untypable node %s", nodestr[n->type]); - break; - } + t = tf(st, t); + switch (n->type) { + case Nexpr: n->expr.type = t; break; + case Ndecl: n->decl.type = t; break; + case Nlit: n->lit.type = t; break; + case Nfunc: n->func.type = t; break; + default: die("untypable node %s", nodestr[n->type]); break; + } } /* Gets the type of a literal value */ static Type *littype(Node *n) { - Type *t; + Type *t; - t = NULL; - if (!n->lit.type) { - switch (n->lit.littype) { - case Lchr: t = mktype(n->loc, Tychar); break; - case Lbool: t = mktype(n->loc, Tybool); break; - case Lint: t = mktylike(n->loc, Tyint); break; - case Lflt: t = mktylike(n->loc, Tyflt64); break; - case Lstr: t = mktyslice(n->loc, mktype(n->loc, Tybyte)); break; - case Llbl: t = mktyptr(n->loc, mktype(n->loc, Tyvoid)); break; - case Lfunc: t = n->lit.fnval->func.type; break; - } - n->lit.type = t; - } - return n->lit.type; + t = NULL; + if (!n->lit.type) { + switch (n->lit.littype) { + case Lchr: t = mktype(n->loc, Tychar); break; + case Lbool: t = mktype(n->loc, Tybool); break; + case Lint: t = mktylike(n->loc, Tyint); break; + case Lflt: t = mktylike(n->loc, Tyflt64); break; + case Lstr: t = mktyslice(n->loc, mktype(n->loc, Tybyte)); break; + case Llbl: t = mktyptr(n->loc, mktype(n->loc, Tyvoid)); break; + case Lfunc: t = n->lit.fnval->func.type; break; + } + n->lit.type = t; + } + return n->lit.type; } static Type *delayeducon(Inferstate *st, Type *fallback) { - Type *t; - char *from, *to; + Type *t; + char *from, *to; - if (fallback->type != Tyunion) - return fallback; - t = mktylike(fallback->loc, fallback->type); - htput(st->delayed, t, fallback); - if (debugopt['u']) { - from = tystr(t); - to = tystr(fallback); - indentf(st->indentdepth, "Delay %s -> %s\n", from, to); - free(from); - free(to); - } - return t; + if (fallback->type != Tyunion) + return fallback; + t = mktylike(fallback->loc, fallback->type); + htput(st->delayed, t, fallback); + if (debugopt['u']) { + from = tystr(t); + to = tystr(fallback); + indentf(st->indentdepth, "Delay %s -> %s\n", from, to); + free(from); + free(to); + } + return t; } /* Finds the type of any typable node */ static Type *type(Inferstate *st, Node *n) { - Type *t; + Type *t; - switch (n->type) { - case Nlit: t = littype(n); break; - case Nexpr: t = n->expr.type; break; - case Ndecl: t = decltype(n); break; - case Nfunc: t = n->func.type; break; - default: - t = NULL; - die("untypeable node %s", nodestr[n->type]); - break; - }; - return tf(st, t); + switch (n->type) { + case Nlit: t = littype(n); break; + case Nexpr: t = n->expr.type; break; + case Ndecl: t = decltype(n); break; + case Nfunc: t = n->func.type; break; + default: + t = NULL; + die("untypeable node %s", nodestr[n->type]); + break; + }; + return tf(st, t); } static Ucon *uconresolve(Inferstate *st, Node *n) { - Ucon *uc; - Node **args; - Stab *ns; - - args = n->expr.args; - ns = curstab(); - if (args[0]->name.ns) - ns = getns(file, args[0]->name.ns); - if (!ns) - fatal(n, "no namespace %s\n", args[0]->name.ns); - uc = getucon(ns, args[0]); - if (!uc) - fatal(n, "no union constructor `%s", ctxstr(st, args[0])); - if (!uc->etype && n->expr.nargs > 1) - fatal(n, "nullary union constructor `%s passed arg ", ctxstr(st, args[0])); - else if (uc->etype && n->expr.nargs != 2) - fatal(n, "union constructor `%s needs arg ", ctxstr(st, args[0])); - return uc; + Ucon *uc; + Node **args; + Stab *ns; + + args = n->expr.args; + ns = curstab(); + if (args[0]->name.ns) + ns = getns(file, args[0]->name.ns); + if (!ns) + fatal(n, "no namespace %s\n", args[0]->name.ns); + uc = getucon(ns, args[0]); + if (!uc) + fatal(n, "no union constructor `%s", ctxstr(st, args[0])); + if (!uc->etype && n->expr.nargs > 1) + fatal(n, "nullary union constructor `%s passed arg ", ctxstr(st, args[0])); + else if (uc->etype && n->expr.nargs != 2) + fatal(n, "union constructor `%s needs arg ", ctxstr(st, args[0])); + return uc; } static void putbindingsrec(Inferstate *st, Htab *bt, Type *t, Bitset *visited) { - size_t i; - - if (bshas(visited, t->tid)) - return; - bsput(visited, t->tid); - switch (t->type) { - case Typaram: - if (hthas(bt, t->pname)) - unify(st, NULL, htget(bt, t->pname), t); - else if (!isbound(st, t)) - htput(bt, t->pname, t); - break; - case Tygeneric: - for (i = 0; i < t->ngparam; i++) - putbindingsrec(st, bt, t->gparam[i], visited); - break; - case Tyname: - for (i = 0; i < t->narg; i++) - putbindingsrec(st, bt, t->arg[i], visited); - break; - case Tyunres: - for (i = 0; i < t->narg; i++) - putbindingsrec(st, bt, t->arg[i], visited); - break; - case Tystruct: - for (i = 0; i < t->nmemb; i++) - putbindingsrec(st, bt, t->sdecls[i]->decl.type, visited); - break; - case Tyunion: - for (i = 0; i < t->nmemb; i++) - if (t->udecls[i]->etype) - putbindingsrec(st, bt, t->udecls[i]->etype, visited); - break; - default: - for (i = 0; i < t->nsub; i++) - putbindingsrec(st, bt, t->sub[i], visited); - break; - } + size_t i; + + if (bshas(visited, t->tid)) + return; + bsput(visited, t->tid); + switch (t->type) { + case Typaram: + if (hthas(bt, t->pname)) + unify(st, NULL, htget(bt, t->pname), t); + else if (!isbound(st, t)) + htput(bt, t->pname, t); + break; + case Tygeneric: + for (i = 0; i < t->ngparam; i++) + putbindingsrec(st, bt, t->gparam[i], visited); + break; + case Tyname: + for (i = 0; i < t->narg; i++) + putbindingsrec(st, bt, t->arg[i], visited); + break; + case Tyunres: + for (i = 0; i < t->narg; i++) + putbindingsrec(st, bt, t->arg[i], visited); + break; + case Tystruct: + for (i = 0; i < t->nmemb; i++) + putbindingsrec(st, bt, t->sdecls[i]->decl.type, visited); + break; + case Tyunion: + for (i = 0; i < t->nmemb; i++) + if (t->udecls[i]->etype) + putbindingsrec(st, bt, t->udecls[i]->etype, visited); + break; + default: + for (i = 0; i < t->nsub; i++) + putbindingsrec(st, bt, t->sub[i], visited); + break; + } } /* Binds the type parameters present in the * current type into the type environment */ static void putbindings(Inferstate *st, Htab *bt, Type *t) { - Bitset *visited; + Bitset *visited; - if (!t) - return; - visited = mkbs(); - putbindingsrec(st, bt, t, visited); - bsfree(visited); + if (!t) + return; + visited = mkbs(); + putbindingsrec(st, bt, t, visited); + bsfree(visited); } static void tybind(Inferstate *st, Type *t) { - Htab *bt; - char *s; + Htab *bt; + char *s; - if (debugopt['u']) { - s = tystr(t); - indentf(st->indentdepth, "Binding %s\n", s); - free(s); - } - bt = mkht(strhash, streq); - lappend(&st->tybindings, &st->ntybindings, bt); - putbindings(st, bt, t); + if (debugopt['u']) { + s = tystr(t); + indentf(st->indentdepth, "Binding %s\n", s); + free(s); + } + bt = mkht(strhash, streq); + lappend(&st->tybindings, &st->ntybindings, bt); + putbindings(st, bt, t); } /* Binds the type parameters in the * declaration into the type environment */ static void bind(Inferstate *st, Node *n) { - Htab *bt; + Htab *bt; - assert(n->type == Ndecl); - if (!n->decl.isgeneric) - return; - if (!n->decl.init) - fatal(n, "generic %s has no initializer", n->decl); + assert(n->type == Ndecl); + if (!n->decl.isgeneric) + return; + if (!n->decl.init) + fatal(n, "generic %s has no initializer", n->decl); - st->ingeneric++; - bt = mkht(strhash, streq); - lappend(&st->tybindings, &st->ntybindings, bt); + st->ingeneric++; + bt = mkht(strhash, streq); + lappend(&st->tybindings, &st->ntybindings, bt); - putbindings(st, bt, n->decl.type); - putbindings(st, bt, n->decl.init->expr.type); + putbindings(st, bt, n->decl.type); + putbindings(st, bt, n->decl.init->expr.type); } /* Rolls back the binding of type parameters in * the type environment */ static void unbind(Inferstate *st, Node *n) { - if (!n->decl.isgeneric) - return; - htfree(st->tybindings[st->ntybindings - 1]); - lpop(&st->tybindings, &st->ntybindings); - st->ingeneric--; + if (!n->decl.isgeneric) + return; + htfree(st->tybindings[st->ntybindings - 1]); + lpop(&st->tybindings, &st->ntybindings); + st->ingeneric--; } static void tyunbind(Inferstate *st, Type *t) { - if (t->type != Tygeneric) - return; - htfree(st->tybindings[st->ntybindings - 1]); - lpop(&st->tybindings, &st->ntybindings); + if (t->type != Tygeneric) + return; + htfree(st->tybindings[st->ntybindings - 1]); + lpop(&st->tybindings, &st->ntybindings); } /* Constrains a type to implement the required constraints. On @@ -728,87 +713,91 @@ static void tyunbind(Inferstate *st, Type *t) * if it has the required constraint */ static void constrain(Inferstate *st, Node *ctx, Type *a, Trait *c) { - if (a->type == Tyvar) { - if (!a->traits) - a->traits = mkbs(); - settrait(a, c); - } else if (!a->traits || !bshas(a->traits, c->uid)) { - fatal(ctx, "%s needs %s near %s", tystr(a), namestr(c->name), ctxstr(st, ctx)); - } + if (a->type == Tyvar) { + if (!a->traits) + a->traits = mkbs(); + settrait(a, c); + } + else if (!a->traits || !bshas(a->traits, c->uid)) { + fatal(ctx, "%s needs %s near %s", tystr(a), namestr(c->name), ctxstr(st, ctx)); + } } /* does b satisfy all the constraints of a? */ static int checktraits(Type *a, Type *b) { - /* a has no traits to satisfy */ - if (!a->traits) - return 1; - /* b satisfies no traits; only valid if a requires none */ - if (!b->traits) - return bscount(a->traits) == 0; - /* if a->traits is a subset of b->traits, all of - * a's constraints are satisfied by b. */ - return bsissubset(a->traits, b->traits); + /* a has no traits to satisfy */ + if (!a->traits) + return 1; + /* b satisfies no traits; only valid if a requires none */ + if (!b->traits) + return bscount(a->traits) == 0; + /* if a->traits is a subset of b->traits, all of + * a's constraints are satisfied by b. */ + return bsissubset(a->traits, b->traits); } static void verifytraits(Inferstate *st, Node *ctx, Type *a, Type *b) { - size_t i, n; - char *sep; - char traitbuf[1024], abuf[1024], bbuf[1024]; - - if (!checktraits(a, b)) { - sep = ""; - n = 0; - for (i = 0; bsiter(a->traits, &i); i++) { - if (!b->traits || !bshas(b->traits, i)) - n += bprintf(traitbuf + n, sizeof(traitbuf) - n, "%s%s", sep, namestr(traittab[i]->name)); - sep = ","; - } - tyfmt(abuf, sizeof abuf, a); - tyfmt(bbuf, sizeof bbuf, b); - fatal(ctx, "%s missing traits %s for %s near %s", bbuf, traitbuf, abuf, ctxstr(st, ctx)); - } + size_t i, n; + char *sep; + char traitbuf[1024], abuf[1024], bbuf[1024]; + + if (!checktraits(a, b)) { + sep = ""; + n = 0; + for (i = 0; bsiter(a->traits, &i); i++) { + if (!b->traits || !bshas(b->traits, i)) + n += bprintf(traitbuf + n, sizeof(traitbuf) - n, "%s%s", sep, + namestr(traittab[i]->name)); + sep = ","; + } + tyfmt(abuf, sizeof abuf, a); + tyfmt(bbuf, sizeof bbuf, b); + fatal(ctx, "%s missing traits %s for %s near %s", bbuf, traitbuf, abuf, + ctxstr(st, ctx)); + } } /* Merges the constraints on types */ static void mergetraits(Inferstate *st, Node *ctx, Type *a, Type *b) { - if (b->type == Tyvar) { - /* make sure that if a = b, both have same traits */ - if (a->traits && b->traits) - bsunion(b->traits, a->traits); - else if (a->traits) - b->traits = bsdup(a->traits); - else if (b->traits) - a->traits = bsdup(b->traits); - } else { - verifytraits(st, ctx, a, b); - } + if (b->type == Tyvar) { + /* make sure that if a = b, both have same traits */ + if (a->traits && b->traits) + bsunion(b->traits, a->traits); + else if (a->traits) + b->traits = bsdup(a->traits); + else if (b->traits) + a->traits = bsdup(b->traits); + } + else { + verifytraits(st, ctx, a, b); + } } /* Tells us if we have an index hack on the type */ static int idxhacked(Type *a, Type *b) { - if (a->type == Tyvar && a->nsub > 0) - return 1; - if (a->type == Tyarray || a->type == Tyslice) - return a->type == b->type; - return 0; + if (a->type == Tyvar && a->nsub > 0) + return 1; + if (a->type == Tyarray || a->type == Tyslice) + return a->type == b->type; + return 0; } /* prevents types that contain themselves in the unification; * eg @a U (@a -> foo) */ static int occurs(Type *a, Type *b) { - size_t i; + size_t i; - if (a == b) - return 1; - for (i = 0; i < b->nsub; i++) - if (occurs(a, b->sub[i])) - return 1; - return 0; + if (a == b) + return 1; + for (i = 0; i < b->nsub; i++) + if (occurs(a, b->sub[i])) + return 1; + return 0; } /* Computes the 'rank' of the type; ie, in which @@ -817,173 +806,177 @@ static int occurs(Type *a, Type *b) * specific) type. */ static int tyrank(Type *t) { - /* plain tyvar */ - if (t->type == Tyvar && t->nsub == 0) - return 0; - /* parameterized tyvar */ - if (t->type == Tyvar && t->nsub > 0) - return 1; - /* concrete type */ - return 2; + /* plain tyvar */ + if (t->type == Tyvar && t->nsub == 0) + return 0; + /* parameterized tyvar */ + if (t->type == Tyvar && t->nsub > 0) + return 1; + /* concrete type */ + return 2; } -static int hasparam(Type *t) -{ - return t->type == Tyname && t->narg > 0; -} +static int hasparam(Type *t) { return t->type == Tyname && t->narg > 0; } static void unionunify(Inferstate *st, Node *ctx, Type *u, Type *v) { - size_t i, j; - int found; - - if (u->nmemb != v->nmemb) - fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx)); - - for (i = 0; i < u->nmemb; i++) { - found = 0; - for (j = 0; j < v->nmemb; j++) { - if (strcmp(namestr(u->udecls[i]->name), namestr(v->udecls[i]->name)) != 0) - continue; - found = 1; - if (u->udecls[i]->etype == NULL && v->udecls[i]->etype == NULL) - continue; - else if (u->udecls[i]->etype && v->udecls[i]->etype) - unify(st, ctx, u->udecls[i]->etype, v->udecls[i]->etype); - else - fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx)); - } - if (!found) - fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx)); - } + size_t i, j; + int found; + + if (u->nmemb != v->nmemb) + fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx)); + + for (i = 0; i < u->nmemb; i++) { + found = 0; + for (j = 0; j < v->nmemb; j++) { + if (strcmp(namestr(u->udecls[i]->name), namestr(v->udecls[i]->name)) != 0) + continue; + found = 1; + if (u->udecls[i]->etype == NULL && v->udecls[i]->etype == NULL) + continue; + else if (u->udecls[i]->etype && v->udecls[i]->etype) + unify(st, ctx, u->udecls[i]->etype, v->udecls[i]->etype); + else + fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), + ctxstr(st, ctx)); + } + if (!found) + fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), + ctxstr(st, ctx)); + } } static void structunify(Inferstate *st, Node *ctx, Type *u, Type *v) { - size_t i, j; - int found; - - if (u->nmemb != v->nmemb) - fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx)); - - for (i = 0; i < u->nmemb; i++) { - found = 0; - for (j = 0; j < v->nmemb; j++) { - if (strcmp(namestr(u->sdecls[i]->decl.name), namestr(v->sdecls[i]->decl.name)) != 0) - continue; - found = 1; - unify(st, ctx, type(st, u->sdecls[i]), type(st, v->sdecls[i])); - } - if (!found) - fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx)); - } -} - -static void membunify(Inferstate *st, Node *ctx, Type *u, Type *v) { - if (hthas(st->delayed, u)) - u = htget(st->delayed, u); - u = tybase(u); - if (hthas(st->delayed, v)) - v = htget(st->delayed, v); - v = tybase(v); - if (u->type == Tyunion && v->type == Tyunion && u != v) - unionunify(st, ctx, u, v); - else if (u->type == Tystruct && v->type == Tystruct && u != v) - structunify(st, ctx, u, v); + size_t i, j; + int found; + + if (u->nmemb != v->nmemb) + fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx)); + + for (i = 0; i < u->nmemb; i++) { + found = 0; + for (j = 0; j < v->nmemb; j++) { + if (strcmp(namestr(u->sdecls[i]->decl.name), + namestr(v->sdecls[i]->decl.name)) != 0) + continue; + found = 1; + unify(st, ctx, type(st, u->sdecls[i]), type(st, v->sdecls[i])); + } + if (!found) + fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), + ctxstr(st, ctx)); + } +} + +static void membunify(Inferstate *st, Node *ctx, Type *u, Type *v) +{ + if (hthas(st->delayed, u)) + u = htget(st->delayed, u); + u = tybase(u); + if (hthas(st->delayed, v)) + v = htget(st->delayed, v); + v = tybase(v); + if (u->type == Tyunion && v->type == Tyunion && u != v) + unionunify(st, ctx, u, v); + else if (u->type == Tystruct && v->type == Tystruct && u != v) + structunify(st, ctx, u, v); } /* Unifies two types, or errors if the types are not unifiable. */ static Type *unify(Inferstate *st, Node *ctx, Type *u, Type *v) { - Type *t, *r; - Type *a, *b; - char *from, *to; - size_t i; - - /* a ==> b */ - a = tf(st, u); - b = tf(st, v); - if (a == b) - return a; - - /* we unify from lower to higher ranked types */ - if (tyrank(b) < tyrank(a)) { - t = a; - a = b; - b = t; - } - - if (debugopt['u']) { - from = tystr(a); - to = tystr(b); - indentf(st->indentdepth, "Unify %s => %s\n", from, to); - free(from); - free(to); - } - - r = NULL; - if (a->type == Tyvar) { - tytab[a->tid] = b; - r = b; - } - - /* Disallow recursive types */ - if (a->type == Tyvar && b->type != Tyvar) { - if (occurs(a, b)) - typeerror(st, a, b, ctx, "Infinite type\n"); - } - - /* if the tyrank of a is 0 (ie, a raw tyvar), just unify. - * Otherwise, match up subtypes. */ - if ((a->type == b->type || idxhacked(a, b)) && tyrank(a) != 0) { - if (hasparam(a) && hasparam(b)) { - /* Only Tygeneric and Tyname should be able to unify. And they - * should have the same names for this to be true. */ - if (!nameeq(a->name, b->name)) - typeerror(st, a, b, ctx, NULL); - if (a->narg != b->narg) - typeerror(st, a, b, ctx, "Incompatible parameter lists"); - for (i = 0; i < a->narg; i++) - unify(st, ctx, a->arg[i], b->arg[i]); - r = b; - } - if (a->nsub != b->nsub) { - verifytraits(st, ctx, a, b); - if (tybase(a)->type == Tyfunc) - typeerror(st, a, b, ctx, "function arity mismatch"); - else - typeerror(st, a, b, ctx, "subtype counts incompatible"); - } - for (i = 0; i < b->nsub; i++) - unify(st, ctx, a->sub[i], b->sub[i]); - r = b; - } else if (a->type != Tyvar) { - typeerror(st, a, b, ctx, NULL); - } - mergetraits(st, ctx, a, b); - if (a->isreflect || b->isreflect) - r->isreflect = a->isreflect = b->isreflect = 1; - membunify(st, ctx, a, b); - - /* if we have delayed types for a tyvar, transfer it over. */ - if (a->type == Tyvar && b->type == Tyvar) { - if (hthas(st->delayed, a) && !hthas(st->delayed, b)) - htput(st->delayed, b, htget(st->delayed, a)); - else if (hthas(st->delayed, b) && !hthas(st->delayed, a)) - htput(st->delayed, a, htget(st->delayed, b)); - } else if (hthas(st->delayed, a)) { - unify(st, ctx, htget(st->delayed, a), tybase(b)); - } - - return r; + Type *t, *r; + Type *a, *b; + char *from, *to; + size_t i; + + /* a ==> b */ + a = tf(st, u); + b = tf(st, v); + if (a == b) + return a; + + /* we unify from lower to higher ranked types */ + if (tyrank(b) < tyrank(a)) { + t = a; + a = b; + b = t; + } + + if (debugopt['u']) { + from = tystr(a); + to = tystr(b); + indentf(st->indentdepth, "Unify %s => %s\n", from, to); + free(from); + free(to); + } + + r = NULL; + if (a->type == Tyvar) { + tytab[a->tid] = b; + r = b; + } + + /* Disallow recursive types */ + if (a->type == Tyvar && b->type != Tyvar) { + if (occurs(a, b)) + typeerror(st, a, b, ctx, "Infinite type\n"); + } + + /* if the tyrank of a is 0 (ie, a raw tyvar), just unify. + * Otherwise, match up subtypes. */ + if ((a->type == b->type || idxhacked(a, b)) && tyrank(a) != 0) { + if (hasparam(a) && hasparam(b)) { + /* Only Tygeneric and Tyname should be able to unify. And they + * should have the same names for this to be true. */ + if (!nameeq(a->name, b->name)) + typeerror(st, a, b, ctx, NULL); + if (a->narg != b->narg) + typeerror(st, a, b, ctx, "Incompatible parameter lists"); + for (i = 0; i < a->narg; i++) + unify(st, ctx, a->arg[i], b->arg[i]); + r = b; + } + if (a->nsub != b->nsub) { + verifytraits(st, ctx, a, b); + if (tybase(a)->type == Tyfunc) + typeerror(st, a, b, ctx, "function arity mismatch"); + else + typeerror(st, a, b, ctx, "subtype counts incompatible"); + } + for (i = 0; i < b->nsub; i++) + unify(st, ctx, a->sub[i], b->sub[i]); + r = b; + } + else if (a->type != Tyvar) { + typeerror(st, a, b, ctx, NULL); + } + mergetraits(st, ctx, a, b); + if (a->isreflect || b->isreflect) + r->isreflect = a->isreflect = b->isreflect = 1; + membunify(st, ctx, a, b); + + /* if we have delayed types for a tyvar, transfer it over. */ + if (a->type == Tyvar && b->type == Tyvar) { + if (hthas(st->delayed, a) && !hthas(st->delayed, b)) + htput(st->delayed, b, htget(st->delayed, a)); + else if (hthas(st->delayed, b) && !hthas(st->delayed, a)) + htput(st->delayed, a, htget(st->delayed, b)); + } + else if (hthas(st->delayed, a)) { + unify(st, ctx, htget(st->delayed, a), tybase(b)); + } + + return r; } static void markvatypes(Type **types, size_t ntypes) { - size_t i; + size_t i; - for (i = 0; i < ntypes; i++) - types[i]->isreflect = 1; + for (i = 0; i < ntypes; i++) + types[i]->isreflect = 1; } /* Applies unifications to function calls. @@ -991,103 +984,107 @@ static void markvatypes(Type **types, size_t ntypes) * different approach to unification. */ static void unifycall(Inferstate *st, Node *n) { - size_t i; - Type *ft; - char *ret, *ctx; - - ft = type(st, n->expr.args[0]); - - if (ft->type == Tyvar) { - /* the first arg is the function itself, so it shouldn't be counted */ - ft = mktyfunc(n->loc, &n->expr.args[1], n->expr.nargs - 1, mktyvar(n->loc)); - unify(st, n, ft, type(st, n->expr.args[0])); - } else if (tybase(ft)->type != Tyfunc) { - fatal(n, "calling uncallable type %s", tystr(ft)); - } - /* first arg: function itself */ - for (i = 1; i < n->expr.nargs; i++) - if (exprtype(n->expr.args[i])->type == Tyvoid) - fatal(n, "void passed where value expected, near %s", ctxstr(st, n)); - for (i = 1; i < n->expr.nargs; i++) { - if (i == ft->nsub) - fatal(n, "%s arity mismatch (expected %zd args, got %zd)", - ctxstr(st, n->expr.args[0]), ft->nsub - 1, n->expr.nargs - 1); - - if (ft->sub[i]->type == Tyvalist) { - markvatypes(&ft->sub[i], ft->nsub - i); - break; - } - inferexpr(st, &n->expr.args[i], NULL, NULL); - unify(st, n->expr.args[0], ft->sub[i], type(st, n->expr.args[i])); - } - if (i < ft->nsub && ft->sub[i]->type != Tyvalist) - fatal(n, "%s arity mismatch (expected %zd args, got %zd)", - ctxstr(st, n->expr.args[0]), ft->nsub - 1, i - 1); - if (debugopt['u']) { - ret = tystr(ft->sub[0]); - ctx = ctxstr(st, n->expr.args[0]); - indentf(st->indentdepth, "Call of %s returns %s\n", ctx, ret); - free(ctx); - free(ret); - } - - settype(st, n, ft->sub[0]); + size_t i; + Type *ft; + char *ret, *ctx; + + ft = type(st, n->expr.args[0]); + + if (ft->type == Tyvar) { + /* the first arg is the function itself, so it shouldn't be counted */ + ft = mktyfunc(n->loc, &n->expr.args[1], n->expr.nargs - 1, mktyvar(n->loc)); + unify(st, n, ft, type(st, n->expr.args[0])); + } + else if (tybase(ft)->type != Tyfunc) { + fatal(n, "calling uncallable type %s", tystr(ft)); + } + /* first arg: function itself */ + for (i = 1; i < n->expr.nargs; i++) + if (exprtype(n->expr.args[i])->type == Tyvoid) + fatal(n, "void passed where value expected, near %s", ctxstr(st, n)); + for (i = 1; i < n->expr.nargs; i++) { + if (i == ft->nsub) + fatal(n, "%s arity mismatch (expected %zd args, got %zd)", + ctxstr(st, n->expr.args[0]), ft->nsub - 1, n->expr.nargs - 1); + + if (ft->sub[i]->type == Tyvalist) { + markvatypes(&ft->sub[i], ft->nsub - i); + break; + } + inferexpr(st, &n->expr.args[i], NULL, NULL); + unify(st, n->expr.args[0], ft->sub[i], type(st, n->expr.args[i])); + } + if (i < ft->nsub && ft->sub[i]->type != Tyvalist) + fatal(n, "%s arity mismatch (expected %zd args, got %zd)", + ctxstr(st, n->expr.args[0]), ft->nsub - 1, i - 1); + if (debugopt['u']) { + ret = tystr(ft->sub[0]); + ctx = ctxstr(st, n->expr.args[0]); + indentf(st->indentdepth, "Call of %s returns %s\n", ctx, ret); + free(ctx); + free(ret); + } + + settype(st, n, ft->sub[0]); } static void unifyparams(Inferstate *st, Node *ctx, Type *a, Type *b) { - size_t i; + size_t i; - /* The only types with unifiable params are Tyunres and Tyname. - * Tygeneric should always be freshened, and no other types have - * parameters attached. - * - * FIXME: Is it possible to have parameterized typarams? */ - if (a->type != Tyunres && a->type != Tyname) - return; - if (b->type != Tyunres && b->type != Tyname) - return; + /* The only types with unifiable params are Tyunres and Tyname. + * Tygeneric should always be freshened, and no other types have + * parameters attached. + * + * FIXME: Is it possible to have parameterized typarams? */ + if (a->type != Tyunres && a->type != Tyname) + return; + if (b->type != Tyunres && b->type != Tyname) + return; - if (a->narg != b->narg) - fatal(ctx, "mismatched arg list sizes: %s with %s near %s", tystr(a), tystr(b), ctxstr(st, ctx)); - for (i = 0; i < a->narg; i++) - unify(st, ctx, a->arg[i], b->arg[i]); + if (a->narg != b->narg) + fatal(ctx, "mismatched arg list sizes: %s with %s near %s", tystr(a), tystr(b), + ctxstr(st, ctx)); + for (i = 0; i < a->narg; i++) + unify(st, ctx, a->arg[i], b->arg[i]); } static void loaduses(Node *n) { - size_t i; + size_t i; - /* uses only allowed at top level. Do we want to keep it this way? */ - for (i = 0; i < n->file.nuses; i++) - readuse(n->file.uses[i], n->file.globls, Visintern); + /* uses only allowed at top level. Do we want to keep it this way? */ + for (i = 0; i < n->file.nuses; i++) + readuse(n->file.uses[i], n->file.globls, Visintern); } static Type *initvar(Inferstate *st, Node *n, Node *s) { - Type *t; - - if (s->decl.ishidden) - fatal(n, "attempting to refer to hidden decl %s", ctxstr(st, n)); - if (s->decl.isgeneric) - t = tysubst(st, tf(st, s->decl.type), s->decl.type); - else - t = s->decl.type; - n->expr.did = s->decl.did; - n->expr.isconst = s->decl.isconst; - if (s->decl.isgeneric && !st->ingeneric) { - t = tyfreshen(st, NULL, t); - addspecialization(st, n, curstab()); - if (t->type == Tyvar) { - settype(st, n, mktyvar(n->loc)); - delayedcheck(st, n, curstab()); - } else { - settype(st, n, t); - } - } else { - settype(st, n, t); - } - return t; + Type *t; + + if (s->decl.ishidden) + fatal(n, "attempting to refer to hidden decl %s", ctxstr(st, n)); + if (s->decl.isgeneric) + t = tysubst(st, tf(st, s->decl.type), s->decl.type); + else + t = s->decl.type; + n->expr.did = s->decl.did; + n->expr.isconst = s->decl.isconst; + if (s->decl.isgeneric && !st->ingeneric) { + t = tyfreshen(st, NULL, t); + addspecialization(st, n, curstab()); + if (t->type == Tyvar) { + settype(st, n, mktyvar(n->loc)); + delayedcheck(st, n, curstab()); + } + else { + settype(st, n, t); + } + } + else { + settype(st, n, t); + } + return t; } /* Finds out if the member reference is actually @@ -1097,869 +1094,900 @@ static Type *initvar(Inferstate *st, Node *n, Node *s) * that we do have */ static Node *checkns(Inferstate *st, Node *n, Node **ret) { - Node *var, *name, *nsname; - Node **args; - Stab *stab; - Node *s; - - /* check that this is a namespaced declaration */ - if (n->type != Nexpr) - return n; - if (exprop(n) != Omemb) - return n; - if (!n->expr.nargs) - return n; - args = n->expr.args; - if (args[0]->type != Nexpr || exprop(args[0]) != Ovar) - return n; - name = args[0]->expr.args[0]; - stab = getns(file, namestr(name)); - if (!stab) - return n; - - /* substitute the namespaced name */ - nsname = mknsname(n->loc, namestr(name), namestr(args[1])); - s = getdcl(stab, args[1]); - if (!s) - fatal(n, "undeclared var %s.%s", nsname->name.ns, nsname->name.name); - var = mkexpr(n->loc, Ovar, nsname, NULL); - var->expr.idx = n->expr.idx; - initvar(st, var, s); - *ret = var; - return var; + Node *var, *name, *nsname; + Node **args; + Stab *stab; + Node *s; + + /* check that this is a namespaced declaration */ + if (n->type != Nexpr) + return n; + if (exprop(n) != Omemb) + return n; + if (!n->expr.nargs) + return n; + args = n->expr.args; + if (args[0]->type != Nexpr || exprop(args[0]) != Ovar) + return n; + name = args[0]->expr.args[0]; + stab = getns(file, namestr(name)); + if (!stab) + return n; + + /* substitute the namespaced name */ + nsname = mknsname(n->loc, namestr(name), namestr(args[1])); + s = getdcl(stab, args[1]); + if (!s) + fatal(n, "undeclared var %s.%s", nsname->name.ns, nsname->name.name); + var = mkexpr(n->loc, Ovar, nsname, NULL); + var->expr.idx = n->expr.idx; + initvar(st, var, s); + *ret = var; + return var; } static void inferstruct(Inferstate *st, Node *n, int *isconst) { - size_t i; + size_t i; - *isconst = 1; - for (i = 0; i < n->expr.nargs; i++) { - infernode(st, &n->expr.args[i], NULL, NULL); - if (!n->expr.args[i]->expr.isconst) - *isconst = 0; - } - settype(st, n, mktyvar(n->loc)); - delayedcheck(st, n, curstab()); + *isconst = 1; + for (i = 0; i < n->expr.nargs; i++) { + infernode(st, &n->expr.args[i], NULL, NULL); + if (!n->expr.args[i]->expr.isconst) + *isconst = 0; + } + settype(st, n, mktyvar(n->loc)); + delayedcheck(st, n, curstab()); } static void inferarray(Inferstate *st, Node *n, int *isconst) { - size_t i; - Type *t; - Node *len; + size_t i; + Type *t; + Node *len; - *isconst = 1; - len = mkintlit(n->loc, n->expr.nargs); - t = mktyarray(n->loc, mktyvar(n->loc), len); - for (i = 0; i < n->expr.nargs; i++) { - infernode(st, &n->expr.args[i], NULL, NULL); - unify(st, n, t->sub[0], type(st, n->expr.args[i])); - if (!n->expr.args[i]->expr.isconst) - *isconst = 0; - } - settype(st, n, t); + *isconst = 1; + len = mkintlit(n->loc, n->expr.nargs); + t = mktyarray(n->loc, mktyvar(n->loc), len); + for (i = 0; i < n->expr.nargs; i++) { + infernode(st, &n->expr.args[i], NULL, NULL); + unify(st, n, t->sub[0], type(st, n->expr.args[i])); + if (!n->expr.args[i]->expr.isconst) + *isconst = 0; + } + settype(st, n, t); } static void infertuple(Inferstate *st, Node *n, int *isconst) { - Type **types; - size_t i; + Type **types; + size_t i; - *isconst = 1; - types = xalloc(sizeof(Type *)*n->expr.nargs); - for (i = 0; i < n->expr.nargs; i++) { - infernode(st, &n->expr.args[i], NULL, NULL); - n->expr.isconst = n->expr.isconst && n->expr.args[i]->expr.isconst; - types[i] = type(st, n->expr.args[i]); - } - *isconst = n->expr.isconst; - settype(st, n, mktytuple(n->loc, types, n->expr.nargs)); + *isconst = 1; + types = xalloc(sizeof(Type *) * n->expr.nargs); + for (i = 0; i < n->expr.nargs; i++) { + infernode(st, &n->expr.args[i], NULL, NULL); + n->expr.isconst = n->expr.isconst && n->expr.args[i]->expr.isconst; + types[i] = type(st, n->expr.args[i]); + } + *isconst = n->expr.isconst; + settype(st, n, mktytuple(n->loc, types, n->expr.nargs)); } static void inferucon(Inferstate *st, Node *n, int *isconst) { - Ucon *uc; - Type *t; + Ucon *uc; + Type *t; - *isconst = 1; - uc = uconresolve(st, n); - t = tysubst(st, tf(st, uc->utype), uc->utype); - uc = tybase(t)->udecls[uc->id]; - if (uc->etype) { - inferexpr(st, &n->expr.args[1], NULL, NULL); - unify(st, n, uc->etype, type(st, n->expr.args[1])); - *isconst = n->expr.args[1]->expr.isconst; - } - settype(st, n, delayeducon(st, t)); + *isconst = 1; + uc = uconresolve(st, n); + t = tysubst(st, tf(st, uc->utype), uc->utype); + uc = tybase(t)->udecls[uc->id]; + if (uc->etype) { + inferexpr(st, &n->expr.args[1], NULL, NULL); + unify(st, n, uc->etype, type(st, n->expr.args[1])); + *isconst = n->expr.args[1]->expr.isconst; + } + settype(st, n, delayeducon(st, t)); } static void inferpat(Inferstate *st, Node **np, Node *val, Node ***bind, size_t *nbind) { - size_t i; - Node **args; - Node *s, *n; - Stab *ns; - Type *t; - - n = *np; - n = checkns(st, n, np); - args = n->expr.args; - for (i = 0; i < n->expr.nargs; i++) - if (args[i]->type == Nexpr) - inferpat(st, &args[i], val, bind, nbind); - switch (exprop(n)) { - case Otup: - case Ostruct: - case Oarr: - case Olit: - case Omemb: - infernode(st, np, NULL, NULL); - break; - /* arithmetic expressions just need to be constant */ - case Oneg: - case Oadd: - case Osub: - case Omul: - case Odiv: - case Obsl: - case Obsr: - case Oband: - case Obor: - case Obxor: - case Obnot: - infernode(st, np, NULL, NULL); - if (!n->expr.isconst) - fatal(n, "matching against non-constant expression near %s", ctxstr(st, n)); - break; - case Oucon: inferucon(st, n, &n->expr.isconst); break; - case Ovar: - ns = curstab(); - if (args[0]->name.ns) - ns = getns(file, args[0]->name.ns); - s = getdcl(ns, args[0]); - if (s && !s->decl.ishidden) { - if (s->decl.isgeneric) - t = tysubst(st, s->decl.type, s->decl.type); - else if (s->decl.isconst) - t = s->decl.type; - else - fatal(n, "pattern shadows variable declared on %s:%d near %s", fname(s->loc), lnum(s->loc), ctxstr(st, s)); - } else { - t = mktyvar(n->loc); - s = mkdecl(n->loc, n->expr.args[0], t); - s->decl.init = val; - settype(st, n, t); - lappend(bind, nbind, s); - } - settype(st, n, t); - n->expr.did = s->decl.did; - break; - case Ogap: - infernode(st, np, NULL, NULL); - break; - default: - fatal(n, "invalid pattern"); - break; - } + size_t i; + Node **args; + Node *s, *n; + Stab *ns; + Type *t; + + n = *np; + n = checkns(st, n, np); + args = n->expr.args; + for (i = 0; i < n->expr.nargs; i++) + if (args[i]->type == Nexpr) + inferpat(st, &args[i], val, bind, nbind); + switch (exprop(n)) { + case Otup: + case Ostruct: + case Oarr: + case Olit: + case Omemb: + infernode(st, np, NULL, NULL); + break; + /* arithmetic expressions just need to be constant */ + case Oneg: + case Oadd: + case Osub: + case Omul: + case Odiv: + case Obsl: + case Obsr: + case Oband: + case Obor: + case Obxor: + case Obnot: + infernode(st, np, NULL, NULL); + if (!n->expr.isconst) + fatal(n, "matching against non-constant expression near %s", ctxstr(st, n)); + break; + case Oucon: + inferucon(st, n, &n->expr.isconst); + break; + case Ovar: + ns = curstab(); + if (args[0]->name.ns) + ns = getns(file, args[0]->name.ns); + s = getdcl(ns, args[0]); + if (s && !s->decl.ishidden) { + if (s->decl.isgeneric) + t = tysubst(st, s->decl.type, s->decl.type); + else if (s->decl.isconst) + t = s->decl.type; + else + fatal(n, "pattern shadows variable declared on %s:%d near %s", + fname(s->loc), lnum(s->loc), ctxstr(st, s)); + } + else { + t = mktyvar(n->loc); + s = mkdecl(n->loc, n->expr.args[0], t); + s->decl.init = val; + settype(st, n, t); + lappend(bind, nbind, s); + } + settype(st, n, t); + n->expr.did = s->decl.did; + break; + case Ogap: infernode(st, np, NULL, NULL); break; + default: fatal(n, "invalid pattern"); break; + } } void addbindings(Inferstate *st, Node *n, Node **bind, size_t nbind) { - size_t i; + size_t i; - /* order of binding shouldn't matter, so push them into the block - * in reverse order. */ - for (i = 0; i < nbind; i++) { - putdcl(n->block.scope, bind[i]); - linsert(&n->block.stmts, &n->block.nstmts, 0, bind[i]); - } + /* order of binding shouldn't matter, so push them into the block + * in reverse order. */ + for (i = 0; i < nbind; i++) { + putdcl(n->block.scope, bind[i]); + linsert(&n->block.stmts, &n->block.nstmts, 0, bind[i]); + } } static void infersub(Inferstate *st, Node *n, Type *ret, int *sawret, int *exprconst) { - Node **args; - size_t i, nargs; - int isconst; - - args = n->expr.args; - nargs = n->expr.nargs; - isconst = 1; - for (i = 0; i < nargs; i++) { - /* Nlit, Nvar, etc should not be inferred as exprs */ - if (args[i]->type == Nexpr) { - /* Omemb can sometimes resolve to a namespace. We have to check - * this. Icky. */ - checkns(st, args[i], &args[i]); - inferexpr(st, &args[i], ret, sawret); - isconst = isconst && args[i]->expr.isconst; - } - } - if (exprop(n) == Ovar) - n->expr.isconst = decls[n->expr.did]->decl.isconst; - else if (opispure[exprop(n)]) - n->expr.isconst = isconst; - *exprconst = n->expr.isconst; + Node **args; + size_t i, nargs; + int isconst; + + args = n->expr.args; + nargs = n->expr.nargs; + isconst = 1; + for (i = 0; i < nargs; i++) { + /* Nlit, Nvar, etc should not be inferred as exprs */ + if (args[i]->type == Nexpr) { + /* Omemb can sometimes resolve to a namespace. We have to check + * this. Icky. */ + checkns(st, args[i], &args[i]); + inferexpr(st, &args[i], ret, sawret); + isconst = isconst && args[i]->expr.isconst; + } + } + if (exprop(n) == Ovar) + n->expr.isconst = decls[n->expr.did]->decl.isconst; + else if (opispure[exprop(n)]) + n->expr.isconst = isconst; + *exprconst = n->expr.isconst; } static void inferexpr(Inferstate *st, Node **np, Type *ret, int *sawret) { - Node **args; - size_t i, nargs; - Node *s, *n; - Type *t; - int isconst; - - n = *np; - assert(n->type == Nexpr); - args = n->expr.args; - nargs = n->expr.nargs; - infernode(st, &n->expr.idx, NULL, NULL); - n = checkns(st, n, np); - switch (exprop(n)) { - /* all operands are same type */ - case Oadd: /* @a + @a -> @a */ - case Osub: /* @a - @a -> @a */ - case Omul: /* @a * @a -> @a */ - case Odiv: /* @a / @a -> @a */ - case Oneg: /* -@a -> @a */ - infersub(st, n, ret, sawret, &isconst); - t = type(st, args[0]); - constrain(st, n, type(st, args[0]), traittab[Tcnum]); - isconst = args[0]->expr.isconst; - for (i = 1; i < nargs; i++) { - isconst = isconst && args[i]->expr.isconst; - t = unify(st, n, t, type(st, args[i])); - } - n->expr.isconst = isconst; - settype(st, n, t); - break; - case Omod: /* @a % @a -> @a */ - case Obor: /* @a | @a -> @a */ - case Oband: /* @a & @a -> @a */ - case Obxor: /* @a ^ @a -> @a */ - case Obsl: /* @a << @a -> @a */ - case Obsr: /* @a >> @a -> @a */ - case Obnot: /* ~@a -> @a */ - case Opreinc: /* ++@a -> @a */ - case Opredec: /* --@a -> @a */ - case Opostinc: /* @a++ -> @a */ - case Opostdec: /* @a-- -> @a */ - case Oaddeq: /* @a += @a -> @a */ - case Osubeq: /* @a -= @a -> @a */ - case Omuleq: /* @a *= @a -> @a */ - case Odiveq: /* @a /= @a -> @a */ - case Omodeq: /* @a %= @a -> @a */ - case Oboreq: /* @a |= @a -> @a */ - case Obandeq: /* @a &= @a -> @a */ - case Obxoreq: /* @a ^= @a -> @a */ - case Obsleq: /* @a <<= @a -> @a */ - case Obsreq: /* @a >>= @a -> @a */ - infersub(st, n, ret, sawret, &isconst); - t = type(st, args[0]); - constrain(st, n, type(st, args[0]), traittab[Tcnum]); - constrain(st, n, type(st, args[0]), traittab[Tcint]); - isconst = args[0]->expr.isconst; - for (i = 1; i < nargs; i++) { - isconst = isconst && args[i]->expr.isconst; - t = unify(st, n, t, type(st, args[i])); - } - n->expr.isconst = isconst; - settype(st, n, t); - break; - case Oasn: /* @a = @a -> @a */ - infersub(st, n, ret, sawret, &isconst); - t = type(st, args[0]); - for (i = 1; i < nargs; i++) - t = unify(st, n, t, type(st, args[i])); - settype(st, n, t); - if (args[0]->expr.isconst) - fatal(n, "attempting to assign constant \"%s\"", ctxstr(st, args[0])); - break; - - /* operands same type, returning bool */ - case Olor: /* @a || @b -> bool */ - case Oland: /* @a && @b -> bool */ - case Oeq: /* @a == @a -> bool */ - case One: /* @a != @a -> bool */ - case Ogt: /* @a > @a -> bool */ - case Oge: /* @a >= @a -> bool */ - case Olt: /* @a < @a -> bool */ - case Ole: /* @a <= @b -> bool */ - infersub(st, n, ret, sawret, &isconst); - t = type(st, args[0]); - for (i = 1; i < nargs; i++) - unify(st, n, t, type(st, args[i])); - settype(st, n, mktype(Zloc, Tybool)); - break; - - case Olnot: /* !bool -> bool */ - infersub(st, n, ret, sawret, &isconst); - t = unify(st, n, type(st, args[0]), mktype(Zloc, Tybool)); - settype(st, n, t); - break; - - /* reach into a type and pull out subtypes */ - case Oaddr: /* &@a -> @a* */ - infersub(st, n, ret, sawret, &isconst); - settype(st, n, mktyptr(n->loc, type(st, args[0]))); - break; - case Oderef: /* *@a* -> @a */ - infersub(st, n, ret, sawret, &isconst); - t = unify(st, n, type(st, args[0]), mktyptr(n->loc, mktyvar(n->loc))); - settype(st, n, t->sub[0]); - break; - case Oidx: /* @a[@b::tcint] -> @a */ - infersub(st, n, ret, sawret, &isconst); - t = mktyidxhack(n->loc, mktyvar(n->loc)); - unify(st, n, type(st, args[0]), t); - constrain(st, n, type(st, args[0]), traittab[Tcidx]); - constrain(st, n, type(st, args[1]), traittab[Tcint]); - settype(st, n, t->sub[0]); - break; - case Oslice: /* @a[@b::tcint,@b::tcint] -> @a[,] */ - infersub(st, n, ret, sawret, &isconst); - t = mktyidxhack(n->loc, mktyvar(n->loc)); - unify(st, n, type(st, args[0]), t); - constrain(st, n, type(st, args[1]), traittab[Tcint]); - constrain(st, n, type(st, args[2]), traittab[Tcint]); - settype(st, n, mktyslice(n->loc, t->sub[0])); - break; - - /* special cases */ - case Omemb: /* @a.Ident -> @b, verify type(@a.Ident)==@b later */ - infersub(st, n, ret, sawret, &isconst); - settype(st, n, mktyvar(n->loc)); - delayedcheck(st, n, curstab()); - break; - case Osize: /* sizeof @a -> size */ - infersub(st, n, ret, sawret, &isconst); - settype(st, n, mktylike(n->loc, Tyuint)); - break; - case Ocall: /* (@a, @b, @c, ... -> @r)(@a,@b,@c, ... -> @r) -> @r */ - infersub(st, n, ret, sawret, &isconst); - unifycall(st, n); - break; - case Ocast: /* cast(@a, @b) -> @b */ - infersub(st, n, ret, sawret, &isconst); - delayedcheck(st, n, curstab()); - break; - case Oret: /* -> @a -> void */ - infersub(st, n, ret, sawret, &isconst); - if (sawret) - *sawret = 1; - if (!ret) - fatal(n, "returns are not valid near %s", ctxstr(st, n)); - if (nargs) - t = unify(st, n, ret, type(st, args[0])); - else - t = unify(st, n, mktype(Zloc, Tyvoid), ret); - settype(st, n, t); - break; - case Obreak: - case Ocontinue: - /* nullary: nothing to infer. */ - settype(st, n, mktype(Zloc, Tyvoid)); - break; - case Ojmp: /* goto void* -> void */ - infersub(st, n, ret, sawret, &isconst); - settype(st, n, mktype(Zloc, Tyvoid)); - break; - case Ovar: /* a:@a -> @a */ - infersub(st, n, ret, sawret, &isconst); - /* if we created this from a namespaced var, the type should be - * set, and the normal lookup is expected to fail. Since we're - * already done with this node, we can just return. */ - if (n->expr.type) - return; - s = getdcl(curstab(), args[0]); - if (!s) - fatal(n, "undeclared var %s", ctxstr(st, args[0])); - initvar(st, n, s); - break; - case Ogap: /* _ -> @a */ - if (n->expr.type) - return; - n->expr.type = mktyvar(n->loc); - break; - case Oucon: - inferucon(st, n, &n->expr.isconst); - break; - case Otup: - infertuple(st, n, &n->expr.isconst); - break; - case Ostruct: - inferstruct(st, n, &n->expr.isconst); - break; - case Oarr: - inferarray(st, n, &n->expr.isconst); - break; - case Olit: /* :@a::tyclass -> @a */ - infersub(st, n, ret, sawret, &isconst); - switch (args[0]->lit.littype) { - case Lfunc: - infernode(st, &args[0]->lit.fnval, NULL, NULL); - /* FIXME: env capture means this is non-const */ - n->expr.isconst = 1; - break; - default: - n->expr.isconst = 1; - break; - } - settype(st, n, type(st, args[0])); - break; - case Oundef: - infersub(st, n, ret, sawret, &isconst); - settype(st, n, mktype(n->loc, Tyvoid)); - break; - case Oidxlen: - t = mktyvar(n->loc); - constrain(st, n, t, traittab[Tcnum]); - constrain(st, n, t, traittab[Tcint]); - settype(st, n, t); - break; - case Odef: - case Odead: - n->expr.type = mktype(n->loc, Tyvoid); - break; - case Obad: case Ocjmp: case Ovjmp: case Oset: - case Oslbase: case Osllen: case Outag: case Ocallind: - case Oblit: case Oclear: case Oudata: - case Otrunc: case Oswiden: case Ozwiden: - case Oint2flt: case Oflt2int: case Oflt2flt: - case Ofadd: case Ofsub: case Ofmul: case Ofdiv: case Ofneg: - case Ofeq: case Ofne: case Ofgt: case Ofge: case Oflt: case Ofle: - case Oueq: case Oune: case Ougt: case Ouge: case Oult: case Oule: - case Otupget: - case Numops: - die("Should not see %s in fe", opstr[exprop(n)]); - break; - } + Node **args; + size_t i, nargs; + Node *s, *n; + Type *t; + int isconst; + + n = *np; + assert(n->type == Nexpr); + args = n->expr.args; + nargs = n->expr.nargs; + infernode(st, &n->expr.idx, NULL, NULL); + n = checkns(st, n, np); + switch (exprop(n)) { + /* all operands are same type */ + case Oadd: /* @a + @a -> @a */ + case Osub: /* @a - @a -> @a */ + case Omul: /* @a * @a -> @a */ + case Odiv: /* @a / @a -> @a */ + case Oneg: /* -@a -> @a */ + infersub(st, n, ret, sawret, &isconst); + t = type(st, args[0]); + constrain(st, n, type(st, args[0]), traittab[Tcnum]); + isconst = args[0]->expr.isconst; + for (i = 1; i < nargs; i++) { + isconst = isconst && args[i]->expr.isconst; + t = unify(st, n, t, type(st, args[i])); + } + n->expr.isconst = isconst; + settype(st, n, t); + break; + case Omod: /* @a % @a -> @a */ + case Obor: /* @a | @a -> @a */ + case Oband: /* @a & @a -> @a */ + case Obxor: /* @a ^ @a -> @a */ + case Obsl: /* @a << @a -> @a */ + case Obsr: /* @a >> @a -> @a */ + case Obnot: /* ~@a -> @a */ + case Opreinc: /* ++@a -> @a */ + case Opredec: /* --@a -> @a */ + case Opostinc: /* @a++ -> @a */ + case Opostdec: /* @a-- -> @a */ + case Oaddeq: /* @a += @a -> @a */ + case Osubeq: /* @a -= @a -> @a */ + case Omuleq: /* @a *= @a -> @a */ + case Odiveq: /* @a /= @a -> @a */ + case Omodeq: /* @a %= @a -> @a */ + case Oboreq: /* @a |= @a -> @a */ + case Obandeq: /* @a &= @a -> @a */ + case Obxoreq: /* @a ^= @a -> @a */ + case Obsleq: /* @a <<= @a -> @a */ + case Obsreq: /* @a >>= @a -> @a */ + infersub(st, n, ret, sawret, &isconst); + t = type(st, args[0]); + constrain(st, n, type(st, args[0]), traittab[Tcnum]); + constrain(st, n, type(st, args[0]), traittab[Tcint]); + isconst = args[0]->expr.isconst; + for (i = 1; i < nargs; i++) { + isconst = isconst && args[i]->expr.isconst; + t = unify(st, n, t, type(st, args[i])); + } + n->expr.isconst = isconst; + settype(st, n, t); + break; + case Oasn: /* @a = @a -> @a */ + infersub(st, n, ret, sawret, &isconst); + t = type(st, args[0]); + for (i = 1; i < nargs; i++) + t = unify(st, n, t, type(st, args[i])); + settype(st, n, t); + if (args[0]->expr.isconst) + fatal(n, "attempting to assign constant \"%s\"", ctxstr(st, args[0])); + break; + + /* operands same type, returning bool */ + case Olor: /* @a || @b -> bool */ + case Oland: /* @a && @b -> bool */ + case Oeq: /* @a == @a -> bool */ + case One: /* @a != @a -> bool */ + case Ogt: /* @a > @a -> bool */ + case Oge: /* @a >= @a -> bool */ + case Olt: /* @a < @a -> bool */ + case Ole: /* @a <= @b -> bool */ + infersub(st, n, ret, sawret, &isconst); + t = type(st, args[0]); + for (i = 1; i < nargs; i++) + unify(st, n, t, type(st, args[i])); + settype(st, n, mktype(Zloc, Tybool)); + break; + + case Olnot: /* !bool -> bool */ + infersub(st, n, ret, sawret, &isconst); + t = unify(st, n, type(st, args[0]), mktype(Zloc, Tybool)); + settype(st, n, t); + break; + + /* reach into a type and pull out subtypes */ + case Oaddr: /* &@a -> @a* */ + infersub(st, n, ret, sawret, &isconst); + settype(st, n, mktyptr(n->loc, type(st, args[0]))); + break; + case Oderef: /* *@a* -> @a */ + infersub(st, n, ret, sawret, &isconst); + t = unify(st, n, type(st, args[0]), mktyptr(n->loc, mktyvar(n->loc))); + settype(st, n, t->sub[0]); + break; + case Oidx: /* @a[@b::tcint] -> @a */ + infersub(st, n, ret, sawret, &isconst); + t = mktyidxhack(n->loc, mktyvar(n->loc)); + unify(st, n, type(st, args[0]), t); + constrain(st, n, type(st, args[0]), traittab[Tcidx]); + constrain(st, n, type(st, args[1]), traittab[Tcint]); + settype(st, n, t->sub[0]); + break; + case Oslice: /* @a[@b::tcint,@b::tcint] -> @a[,] */ + infersub(st, n, ret, sawret, &isconst); + t = mktyidxhack(n->loc, mktyvar(n->loc)); + unify(st, n, type(st, args[0]), t); + constrain(st, n, type(st, args[1]), traittab[Tcint]); + constrain(st, n, type(st, args[2]), traittab[Tcint]); + settype(st, n, mktyslice(n->loc, t->sub[0])); + break; + + /* special cases */ + case Omemb: /* @a.Ident -> @b, verify type(@a.Ident)==@b later */ + infersub(st, n, ret, sawret, &isconst); + settype(st, n, mktyvar(n->loc)); + delayedcheck(st, n, curstab()); + break; + case Osize: /* sizeof @a -> size */ + infersub(st, n, ret, sawret, &isconst); + settype(st, n, mktylike(n->loc, Tyuint)); + break; + case Ocall: /* (@a, @b, @c, ... -> @r)(@a,@b,@c, ... -> @r) -> @r */ + infersub(st, n, ret, sawret, &isconst); + unifycall(st, n); + break; + case Ocast: /* cast(@a, @b) -> @b */ + infersub(st, n, ret, sawret, &isconst); + delayedcheck(st, n, curstab()); + break; + case Oret: /* -> @a -> void */ + infersub(st, n, ret, sawret, &isconst); + if (sawret) + *sawret = 1; + if (!ret) + fatal(n, "returns are not valid near %s", ctxstr(st, n)); + if (nargs) + t = unify(st, n, ret, type(st, args[0])); + else + t = unify(st, n, mktype(Zloc, Tyvoid), ret); + settype(st, n, t); + break; + case Obreak: + case Ocontinue: + /* nullary: nothing to infer. */ + settype(st, n, mktype(Zloc, Tyvoid)); + break; + case Ojmp: /* goto void* -> void */ + infersub(st, n, ret, sawret, &isconst); + settype(st, n, mktype(Zloc, Tyvoid)); + break; + case Ovar: /* a:@a -> @a */ + infersub(st, n, ret, sawret, &isconst); + /* if we created this from a namespaced var, the type should be + * set, and the normal lookup is expected to fail. Since we're + * already done with this node, we can just return. */ + if (n->expr.type) + return; + s = getdcl(curstab(), args[0]); + if (!s) + fatal(n, "undeclared var %s", ctxstr(st, args[0])); + initvar(st, n, s); + break; + case Ogap: /* _ -> @a */ + if (n->expr.type) + return; + n->expr.type = mktyvar(n->loc); + break; + case Oucon: inferucon(st, n, &n->expr.isconst); break; + case Otup: infertuple(st, n, &n->expr.isconst); break; + case Ostruct: inferstruct(st, n, &n->expr.isconst); break; + case Oarr: inferarray(st, n, &n->expr.isconst); break; + case Olit: /* :@a::tyclass -> @a */ + infersub(st, n, ret, sawret, &isconst); + switch (args[0]->lit.littype) { + case Lfunc: + infernode(st, &args[0]->lit.fnval, NULL, NULL); + /* FIXME: env capture means this is non-const */ + n->expr.isconst = 1; + break; + default: n->expr.isconst = 1; break; + } + settype(st, n, type(st, args[0])); + break; + case Oundef: + infersub(st, n, ret, sawret, &isconst); + settype(st, n, mktype(n->loc, Tyvoid)); + break; + case Oidxlen: + t = mktyvar(n->loc); + constrain(st, n, t, traittab[Tcnum]); + constrain(st, n, t, traittab[Tcint]); + settype(st, n, t); + break; + case Odef: + case Odead: n->expr.type = mktype(n->loc, Tyvoid); break; + case Obad: + case Ocjmp: + case Ovjmp: + case Oset: + case Oslbase: + case Osllen: + case Outag: + case Ocallind: + case Oblit: + case Oclear: + case Oudata: + case Otrunc: + case Oswiden: + case Ozwiden: + case Oint2flt: + case Oflt2int: + case Oflt2flt: + case Ofadd: + case Ofsub: + case Ofmul: + case Ofdiv: + case Ofneg: + case Ofeq: + case Ofne: + case Ofgt: + case Ofge: + case Oflt: + case Ofle: + case Oueq: + case Oune: + case Ougt: + case Ouge: + case Oult: + case Oule: + case Otupget: + case Numops: die("Should not see %s in fe", opstr[exprop(n)]); break; + } } static void inferfunc(Inferstate *st, Node *n) { - size_t i; - int sawret; + size_t i; + int sawret; - sawret = 0; - for (i = 0; i < n->func.nargs; i++) - infernode(st, &n->func.args[i], NULL, NULL); - infernode(st, &n->func.body, n->func.type->sub[0], &sawret); - /* if there's no return stmt in the function, assume void ret */ - if (!sawret) - unify(st, n, type(st, n)->sub[0], mktype(Zloc, Tyvoid)); + sawret = 0; + for (i = 0; i < n->func.nargs; i++) + infernode(st, &n->func.args[i], NULL, NULL); + infernode(st, &n->func.body, n->func.type->sub[0], &sawret); + /* if there's no return stmt in the function, assume void ret */ + if (!sawret) + unify(st, n, type(st, n)->sub[0], mktype(Zloc, Tyvoid)); } static void specializeimpl(Inferstate *st, Node *n) { - Node *dcl, *proto, *name; - Type *ty; - Htab *ht; - Trait *t; - size_t i, j; - - t = gettrait(curstab(), n->impl.traitname); - if (!t) - fatal(n, "no trait %s\n", namestr(n->impl.traitname)); - n->impl.trait = t; - - dcl = NULL; - proto = NULL; - n->impl.type = tf(st, n->impl.type); - for (i = 0; i < n->impl.ndecls; i++) { - /* look up the prototype */ - proto = NULL; - dcl = n->impl.decls[i]; - - /* - since the decls in an impl are not installed in a namespace, their names - are not updated when we call updatens() on the symbol table. Because we need - to do namespace dependent comparisons for specializing, we need to set the - namespace here. - */ - if (file->file.globls->name) - setns(dcl->decl.name, file->file.globls->name); - for (j = 0; j < t->nfuncs; j++) { - if (nameeq(dcl->decl.name, t->funcs[j]->decl.name)) { - proto = t->funcs[j]; - break; - } - } - if (!proto) - fatal(n, "declaration %s missing in %s, near %s", - namestr(dcl->decl.name), namestr(t->name), ctxstr(st, n)); - - /* infer and unify types */ - if (n->impl.type->type == Tygeneric || n->impl.type->type == Typaram) - fatal(n, "trait specialization requires concrete type, got %s", tystr(n->impl.type)); - verifytraits(st, n, t->param, n->impl.type); - ht = mkht(tyhash, tyeq); - htput(ht, t->param, n->impl.type); - ty = tyspecialize(type(st, proto), ht, st->delayed); - htfree(ht); - - inferdecl(st, dcl); - unify(st, n, type(st, dcl), ty); - - /* and put the specialization into the global stab */ - name = genericname(proto, ty); - dcl->decl.name = name; - putdcl(file->file.globls, dcl); - if (debugopt['S']) - printf("specializing trait [%d]%s:%s => %s:%s\n", - n->loc.line, namestr(proto->decl.name), tystr(type(st, proto)), namestr(name), tystr(ty)); - dcl->decl.vis = t->vis; - lappend(&file->file.stmts, &file->file.nstmts, dcl); - } + Node *dcl, *proto, *name; + Type *ty; + Htab *ht; + Trait *t; + size_t i, j; + + t = gettrait(curstab(), n->impl.traitname); + if (!t) + fatal(n, "no trait %s\n", namestr(n->impl.traitname)); + n->impl.trait = t; + + dcl = NULL; + proto = NULL; + n->impl.type = tf(st, n->impl.type); + for (i = 0; i < n->impl.ndecls; i++) { + /* look up the prototype */ + proto = NULL; + dcl = n->impl.decls[i]; + + /* + since the decls in an impl are not installed in a namespace, their names + are not updated when we call updatens() on the symbol table. Because we + need + to do namespace dependent comparisons for specializing, we need to set + the + namespace here. + */ + if (file->file.globls->name) + setns(dcl->decl.name, file->file.globls->name); + for (j = 0; j < t->nfuncs; j++) { + if (nameeq(dcl->decl.name, t->funcs[j]->decl.name)) { + proto = t->funcs[j]; + break; + } + } + if (!proto) + fatal(n, "declaration %s missing in %s, near %s", namestr(dcl->decl.name), + namestr(t->name), ctxstr(st, n)); + + /* infer and unify types */ + if (n->impl.type->type == Tygeneric || n->impl.type->type == Typaram) + fatal(n, "trait specialization requires concrete type, got %s", + tystr(n->impl.type)); + verifytraits(st, n, t->param, n->impl.type); + ht = mkht(tyhash, tyeq); + htput(ht, t->param, n->impl.type); + ty = tyspecialize(type(st, proto), ht, st->delayed); + htfree(ht); + + inferdecl(st, dcl); + unify(st, n, type(st, dcl), ty); + + /* and put the specialization into the global stab */ + name = genericname(proto, ty); + dcl->decl.name = name; + putdcl(file->file.globls, dcl); + if (debugopt['S']) + printf("specializing trait [%d]%s:%s => %s:%s\n", n->loc.line, + namestr(proto->decl.name), tystr(type(st, proto)), namestr(name), + tystr(ty)); + dcl->decl.vis = t->vis; + lappend(&file->file.stmts, &file->file.nstmts, dcl); + } } static void inferdecl(Inferstate *st, Node *n) { - Type *t; - - t = tf(st, decltype(n)); - if (t->type == Tygeneric && !n->decl.isgeneric) { - t = tyfreshen(st, NULL, t); - unifyparams(st, n, t, decltype(n)); - } - settype(st, n, t); - if (n->decl.init) { - inferexpr(st, &n->decl.init, NULL, NULL); - unify(st, n, type(st, n), type(st, n->decl.init)); - if (n->decl.isconst && !n->decl.init->expr.isconst) - fatal(n, "non-const initializer for \"%s\"", ctxstr(st, n)); - } else { - if ((n->decl.isconst || n->decl.isgeneric) && !n->decl.isextern) - fatal(n, "non-extern \"%s\" has no initializer", ctxstr(st, n)); - } + Type *t; + + t = tf(st, decltype(n)); + if (t->type == Tygeneric && !n->decl.isgeneric) { + t = tyfreshen(st, NULL, t); + unifyparams(st, n, t, decltype(n)); + } + settype(st, n, t); + if (n->decl.init) { + inferexpr(st, &n->decl.init, NULL, NULL); + unify(st, n, type(st, n), type(st, n->decl.init)); + if (n->decl.isconst && !n->decl.init->expr.isconst) + fatal(n, "non-const initializer for \"%s\"", ctxstr(st, n)); + } + else { + if ((n->decl.isconst || n->decl.isgeneric) && !n->decl.isextern) + fatal(n, "non-extern \"%s\" has no initializer", ctxstr(st, n)); + } } static void inferstab(Inferstate *st, Stab *s) { - void **k; - size_t n, i; - Type *t; + void **k; + size_t n, i; + Type *t; - k = htkeys(s->ty, &n); - for (i = 0; i < n; i++) { - t = gettype(s, k[i]); - if (!t) - fatal(k[i], "undefined type %s", namestr(k[i])); - t = tysearch(t); - tybind(st, t); - tyresolve(st, t); - tyunbind(st, t); - updatetype(s, k[i], t); - } - free(k); + k = htkeys(s->ty, &n); + for (i = 0; i < n; i++) { + t = gettype(s, k[i]); + if (!t) + fatal(k[i], "undefined type %s", namestr(k[i])); + t = tysearch(t); + tybind(st, t); + tyresolve(st, t); + tyunbind(st, t); + updatetype(s, k[i], t); + } + free(k); } static void infernode(Inferstate *st, Node **np, Type *ret, int *sawret) { - size_t i, nbound; - Node **bound, *n, *pat; - Type *t; - - n = *np; - if (!n) - return; - switch (n->type) { - case Nfile: - pushstab(n->file.globls); - inferstab(st, n->file.globls); - for (i = 0; i < n->file.nstmts; i++) - infernode(st, &n->file.stmts[i], NULL, sawret); - popstab(); - break; - case Ndecl: - if (debugopt['u']) - indentf(st->indentdepth, "--- infer %s ---\n", declname(n)); - st->indentdepth++; - bind(st, n); - inferdecl(st, n); - if (type(st, n)->type == Typaram && !st->ingeneric) - fatal(n, "generic type %s in non-generic near %s", tystr(type(st, n)), ctxstr(st, n)); - unbind(st, n); - st->indentdepth--; - if (debugopt['u']) - indentf(st->indentdepth, "--- done ---\n"); - break; - case Nblock: - setsuper(n->block.scope, curstab()); - pushstab(n->block.scope); - inferstab(st, n->block.scope); - for (i = 0; i < n->block.nstmts; i++) { - infernode(st, &n->block.stmts[i], ret, sawret); - } - popstab(); - break; - case Nifstmt: - infernode(st, &n->ifstmt.cond, NULL, sawret); - infernode(st, &n->ifstmt.iftrue, ret, sawret); - infernode(st, &n->ifstmt.iffalse, ret, sawret); - unify(st, n, type(st, n->ifstmt.cond), mktype(n->loc, Tybool)); - break; - case Nloopstmt: - setsuper(n->loopstmt.scope, curstab()); - pushstab(n->loopstmt.scope); - infernode(st, &n->loopstmt.init, ret, sawret); - infernode(st, &n->loopstmt.cond, NULL, sawret); - infernode(st, &n->loopstmt.step, ret, sawret); - infernode(st, &n->loopstmt.body, ret, sawret); - unify(st, n, type(st, n->loopstmt.cond), mktype(n->loc, Tybool)); - popstab(); - break; - case Niterstmt: - bound = NULL; - nbound = 0; - - inferpat(st, &n->iterstmt.elt, NULL, &bound, &nbound); - addbindings(st, n->iterstmt.body, bound, nbound); - - infernode(st, &n->iterstmt.seq, NULL, sawret); - infernode(st, &n->iterstmt.body, ret, sawret); - - t = mktyidxhack(n->loc, mktyvar(n->loc)); - constrain(st, n, type(st, n->iterstmt.seq), traittab[Tcidx]); - unify(st, n, type(st, n->iterstmt.seq), t); - unify(st, n, type(st, n->iterstmt.elt), t->sub[0]); - break; - case Nmatchstmt: - infernode(st, &n->matchstmt.val, NULL, sawret); - if (tybase(type(st, n->matchstmt.val))->type == Tyvoid) - fatal(n, "can't match against a void type near %s", ctxstr(st, n->matchstmt.val)); - for (i = 0; i < n->matchstmt.nmatches; i++) { - infernode(st, &n->matchstmt.matches[i], ret, sawret); - pat = n->matchstmt.matches[i]->match.pat; - unify(st, pat, type(st, n->matchstmt.val), type(st, n->matchstmt.matches[i]->match.pat)); - } - break; - case Nmatch: - bound = NULL; - nbound = 0; - inferpat(st, &n->match.pat, NULL, &bound, &nbound); - addbindings(st, n->match.block, bound, nbound); - infernode(st, &n->match.block, ret, sawret); - break; - case Nexpr: - inferexpr(st, np, ret, sawret); - break; - case Nfunc: - setsuper(n->func.scope, curstab()); - if (st->ntybindings > 0) - for (i = 0; i < n->func.nargs; i++) - putbindings(st, st->tybindings[st->ntybindings - 1], n->func.args[i]->decl.type); - pushstab(n->func.scope); - inferstab(st, n->func.scope); - inferfunc(st, n); - popstab(); - break; - case Nimpl: - specializeimpl(st, n); - break; - case Nname: - case Nlit: - case Nuse: - break; - case Nnone: - die("Nnone should not be seen as node type!"); - break; - } + size_t i, nbound; + Node **bound, *n, *pat; + Type *t; + + n = *np; + if (!n) + return; + switch (n->type) { + case Nfile: + pushstab(n->file.globls); + inferstab(st, n->file.globls); + for (i = 0; i < n->file.nstmts; i++) + infernode(st, &n->file.stmts[i], NULL, sawret); + popstab(); + break; + case Ndecl: + if (debugopt['u']) + indentf(st->indentdepth, "--- infer %s ---\n", declname(n)); + st->indentdepth++; + bind(st, n); + inferdecl(st, n); + if (type(st, n)->type == Typaram && !st->ingeneric) + fatal(n, "generic type %s in non-generic near %s", tystr(type(st, n)), + ctxstr(st, n)); + unbind(st, n); + st->indentdepth--; + if (debugopt['u']) + indentf(st->indentdepth, "--- done ---\n"); + break; + case Nblock: + setsuper(n->block.scope, curstab()); + pushstab(n->block.scope); + inferstab(st, n->block.scope); + for (i = 0; i < n->block.nstmts; i++) { + infernode(st, &n->block.stmts[i], ret, sawret); + } + popstab(); + break; + case Nifstmt: + infernode(st, &n->ifstmt.cond, NULL, sawret); + infernode(st, &n->ifstmt.iftrue, ret, sawret); + infernode(st, &n->ifstmt.iffalse, ret, sawret); + unify(st, n, type(st, n->ifstmt.cond), mktype(n->loc, Tybool)); + break; + case Nloopstmt: + setsuper(n->loopstmt.scope, curstab()); + pushstab(n->loopstmt.scope); + infernode(st, &n->loopstmt.init, ret, sawret); + infernode(st, &n->loopstmt.cond, NULL, sawret); + infernode(st, &n->loopstmt.step, ret, sawret); + infernode(st, &n->loopstmt.body, ret, sawret); + unify(st, n, type(st, n->loopstmt.cond), mktype(n->loc, Tybool)); + popstab(); + break; + case Niterstmt: + bound = NULL; + nbound = 0; + + inferpat(st, &n->iterstmt.elt, NULL, &bound, &nbound); + addbindings(st, n->iterstmt.body, bound, nbound); + + infernode(st, &n->iterstmt.seq, NULL, sawret); + infernode(st, &n->iterstmt.body, ret, sawret); + + t = mktyidxhack(n->loc, mktyvar(n->loc)); + constrain(st, n, type(st, n->iterstmt.seq), traittab[Tcidx]); + unify(st, n, type(st, n->iterstmt.seq), t); + unify(st, n, type(st, n->iterstmt.elt), t->sub[0]); + break; + case Nmatchstmt: + infernode(st, &n->matchstmt.val, NULL, sawret); + if (tybase(type(st, n->matchstmt.val))->type == Tyvoid) + fatal(n, "can't match against a void type near %s", + ctxstr(st, n->matchstmt.val)); + for (i = 0; i < n->matchstmt.nmatches; i++) { + infernode(st, &n->matchstmt.matches[i], ret, sawret); + pat = n->matchstmt.matches[i]->match.pat; + unify(st, pat, type(st, n->matchstmt.val), + type(st, n->matchstmt.matches[i]->match.pat)); + } + break; + case Nmatch: + bound = NULL; + nbound = 0; + inferpat(st, &n->match.pat, NULL, &bound, &nbound); + addbindings(st, n->match.block, bound, nbound); + infernode(st, &n->match.block, ret, sawret); + break; + case Nexpr: + inferexpr(st, np, ret, sawret); + break; + case Nfunc: + setsuper(n->func.scope, curstab()); + if (st->ntybindings > 0) + for (i = 0; i < n->func.nargs; i++) + putbindings(st, st->tybindings[st->ntybindings - 1], + n->func.args[i]->decl.type); + pushstab(n->func.scope); + inferstab(st, n->func.scope); + inferfunc(st, n); + popstab(); + break; + case Nimpl: + specializeimpl(st, n); + break; + case Nname: + case Nlit: + case Nuse: + break; + case Nnone: + die("Nnone should not be seen as node type!"); + break; + } } /* returns the final type for t, after all unifications * and default constraint selections */ static Type *tyfix(Inferstate *st, Node *ctx, Type *orig, int noerr) { - static Type *tyint, *tyflt; - Type *t, *delayed; - char *from, *to; - size_t i; - char buf[1024]; - - if (!tyint) - tyint = mktype(Zloc, Tyint); - if (!tyflt) - tyflt = mktype(Zloc, Tyflt64); - - t = tysearch(orig); - if (orig->type == Tyvar && hthas(st->delayed, orig)) { - delayed = htget(st->delayed, orig); - if (t->type == Tyvar) - t = delayed; - else if (tybase(t)->type != delayed->type && !noerr) - fatal(ctx, "type %s not compatible with %s near %s\n", tystr(t), tystr(delayed), ctxstr(st, ctx)); - } - if (t->type == Tyvar) { - if (hastrait(t, traittab[Tcint]) && checktraits(t, tyint)) - t = tyint; - if (hastrait(t, traittab[Tcfloat]) && checktraits(t, tyflt)) - t = tyflt; - } else if (!t->fixed) { - t->fixed = 1; - if (t->type == Tyarray) { - typesub(st, t->asize, noerr); - } else if (t->type == Tystruct) { - st->inaggr++; - for (i = 0; i < t->nmemb; i++) - typesub(st, t->sdecls[i], noerr); - st->inaggr--; - } else if (t->type == Tyunion) { - for (i = 0; i < t->nmemb; i++) { - if (t->udecls[i]->etype) { - tyresolve(st, t->udecls[i]->etype); - t->udecls[i]->etype = tyfix(st, ctx, t->udecls[i]->etype, noerr); - } - } - } else if (t->type == Tyname) { - for (i = 0; i < t->narg; i++) - t->arg[i] = tyfix(st, ctx, t->arg[i], noerr); - } - for (i = 0; i < t->nsub; i++) - t->sub[i] = tyfix(st, ctx, t->sub[i], noerr); - } - - if (t->type == Tyvar && !noerr) { - if (debugopt['T']) - dump(file, stdout); - fatal(ctx, "underconstrained type %s near %s", tyfmt(buf, 1024, t), ctxstr(st, ctx)); - } - - if (debugopt['u'] && !tyeq(orig, t)) { - from = tystr(orig); - to = tystr(t); - indentf(st->indentdepth, "subst %s => %s\n", from, to); - free(from); - free(to); - } - - return t; + static Type *tyint, *tyflt; + Type *t, *delayed; + char *from, *to; + size_t i; + char buf[1024]; + + if (!tyint) + tyint = mktype(Zloc, Tyint); + if (!tyflt) + tyflt = mktype(Zloc, Tyflt64); + + t = tysearch(orig); + if (orig->type == Tyvar && hthas(st->delayed, orig)) { + delayed = htget(st->delayed, orig); + if (t->type == Tyvar) + t = delayed; + else if (tybase(t)->type != delayed->type && !noerr) + fatal(ctx, "type %s not compatible with %s near %s\n", tystr(t), + tystr(delayed), ctxstr(st, ctx)); + } + if (t->type == Tyvar) { + if (hastrait(t, traittab[Tcint]) && checktraits(t, tyint)) + t = tyint; + if (hastrait(t, traittab[Tcfloat]) && checktraits(t, tyflt)) + t = tyflt; + } + else if (!t->fixed) { + t->fixed = 1; + if (t->type == Tyarray) { + typesub(st, t->asize, noerr); + } + else if (t->type == Tystruct) { + st->inaggr++; + for (i = 0; i < t->nmemb; i++) + typesub(st, t->sdecls[i], noerr); + st->inaggr--; + } + else if (t->type == Tyunion) { + for (i = 0; i < t->nmemb; i++) { + if (t->udecls[i]->etype) { + tyresolve(st, t->udecls[i]->etype); + t->udecls[i]->etype = + tyfix(st, ctx, t->udecls[i]->etype, noerr); + } + } + } + else if (t->type == Tyname) { + for (i = 0; i < t->narg; i++) + t->arg[i] = tyfix(st, ctx, t->arg[i], noerr); + } + for (i = 0; i < t->nsub; i++) + t->sub[i] = tyfix(st, ctx, t->sub[i], noerr); + } + + if (t->type == Tyvar && !noerr) { + if (debugopt['T']) + dump(file, stdout); + fatal( + ctx, "underconstrained type %s near %s", tyfmt(buf, 1024, t), ctxstr(st, ctx)); + } + + if (debugopt['u'] && !tyeq(orig, t)) { + from = tystr(orig); + to = tystr(t); + indentf(st->indentdepth, "subst %s => %s\n", from, to); + free(from); + free(to); + } + + return t; } static void checkcast(Inferstate *st, Node *n) { - /* FIXME: actually verify the casts. Right now, it's ok to leave this - * unimplemented because bad casts get caught by the backend. */ + /* FIXME: actually verify the casts. Right now, it's ok to leave this + * unimplemented because bad casts get caught by the backend. */ } static void infercompn(Inferstate *st, Node *n) { - Node *aggr; - Node *memb; - Node **nl; - Type *t; - size_t i; - int found; - - aggr = n->expr.args[0]; - memb = n->expr.args[1]; - - found = 0; - t = tybase(tf(st, type(st, aggr))); - /* all array-like types have a fake "len" member that we emulate */ - if (t->type == Tyslice || t->type == Tyarray) { - if (!strcmp(namestr(memb), "len")) { - constrain(st, n, type(st, n), traittab[Tcnum]); - constrain(st, n, type(st, n), traittab[Tcint]); - found = 1; - } - /* otherwise, we search aggregate types for the member, and unify - * the expression with the member type; ie: - * - * x: aggrtype y : memb in aggrtype - * --------------------------------------- - * x.y : membtype - */ - } else { - if (tybase(t)->type == Typtr) - t = tybase(tf(st, t->sub[0])); - if (tybase(t)->type != Tystruct) { - if (tybase(t)->type == Tyvar) - fatal(n, "underspecified type defined on %s:%d used near %s", fname(t->loc), lnum(t->loc), ctxstr(st, n)); - else - fatal(n, "type %s does not support member operators near %s", tystr(t), ctxstr(st, n)); - } - nl = t->sdecls; - for (i = 0; i < t->nmemb; i++) { - if (!strcmp(namestr(memb), declname(nl[i]))) { - unify(st, n, type(st, n), decltype(nl[i])); - found = 1; - break; - } - } - } - if (!found) - fatal(aggr, "type %s has no member \"%s\" near %s", - tystr(type(st, aggr)), ctxstr(st, memb), ctxstr(st, aggr)); + Node *aggr; + Node *memb; + Node **nl; + Type *t; + size_t i; + int found; + + aggr = n->expr.args[0]; + memb = n->expr.args[1]; + + found = 0; + t = tybase(tf(st, type(st, aggr))); + /* all array-like types have a fake "len" member that we emulate */ + if (t->type == Tyslice || t->type == Tyarray) { + if (!strcmp(namestr(memb), "len")) { + constrain(st, n, type(st, n), traittab[Tcnum]); + constrain(st, n, type(st, n), traittab[Tcint]); + found = 1; + } + /* otherwise, we search aggregate types for the member, and unify + * the expression with the member type; ie: + * + * x: aggrtype y : memb in aggrtype + * --------------------------------------- + * x.y : membtype + */ + } + else { + if (tybase(t)->type == Typtr) + t = tybase(tf(st, t->sub[0])); + if (tybase(t)->type != Tystruct) { + if (tybase(t)->type == Tyvar) + fatal(n, "underspecified type defined on %s:%d used near %s", + fname(t->loc), lnum(t->loc), ctxstr(st, n)); + else + fatal(n, "type %s does not support member operators near %s", + tystr(t), ctxstr(st, n)); + } + nl = t->sdecls; + for (i = 0; i < t->nmemb; i++) { + if (!strcmp(namestr(memb), declname(nl[i]))) { + unify(st, n, type(st, n), decltype(nl[i])); + found = 1; + break; + } + } + } + if (!found) + fatal(aggr, "type %s has no member \"%s\" near %s", tystr(type(st, aggr)), + ctxstr(st, memb), ctxstr(st, aggr)); } static void checkstruct(Inferstate *st, Node *n) { - Type *t, *et; - Node *val, *name; - size_t i, j; - - t = tybase(tf(st, n->lit.type)); - if (t->type != Tystruct) { - /* - * If we haven't inferred the type, and it's inside another struct, - * we'll eventually get to it. - * - * If, on the other hand, it is genuinely underspecified, we'll give - * a better error on it later. - */ - return; - } - - for (i = 0; i < n->expr.nargs; i++) { - val = n->expr.args[i]; - name = val->expr.idx; - - et = NULL; - for (j = 0; j < t->nmemb; j++) { - if (!strcmp(namestr(t->sdecls[j]->decl.name), namestr(name))) { - et = type(st, t->sdecls[j]); - break; - } - } - - if (!et) - fatal(n, "could not find member %s in struct %s, near %s", - namestr(name), tystr(t), ctxstr(st, n)); - - unify(st, val, et, type(st, val)); - } + Type *t, *et; + Node *val, *name; + size_t i, j; + + t = tybase(tf(st, n->lit.type)); + if (t->type != Tystruct) { + /* + * If we haven't inferred the type, and it's inside another struct, + * we'll eventually get to it. + * + * If, on the other hand, it is genuinely underspecified, we'll give + * a better error on it later. + */ + return; + } + + for (i = 0; i < n->expr.nargs; i++) { + val = n->expr.args[i]; + name = val->expr.idx; + + et = NULL; + for (j = 0; j < t->nmemb; j++) { + if (!strcmp(namestr(t->sdecls[j]->decl.name), namestr(name))) { + et = type(st, t->sdecls[j]); + break; + } + } + + if (!et) + fatal(n, "could not find member %s in struct %s, near %s", namestr(name), + tystr(t), ctxstr(st, n)); + + unify(st, val, et, type(st, val)); + } } static void checkvar(Inferstate *st, Node *n) { - Node *dcl; + Node *dcl; - dcl = decls[n->expr.did]; - unify(st, n, type(st, n), tyfreshen(st, NULL, type(st, dcl))); + dcl = decls[n->expr.did]; + unify(st, n, type(st, n), tyfreshen(st, NULL, type(st, dcl))); } static void postcheck(Inferstate *st, Node *file) { - size_t i; - Node *n; - - for (i = 0; i < st->npostcheck; i++) { - n = st->postcheck[i]; - pushstab(st->postcheckscope[i]); - if (n->type == Nexpr && exprop(n) == Omemb) - infercompn(st, n); - else if (n->type == Nexpr && exprop(n) == Ocast) - checkcast(st, n); - else if (n->type == Nexpr && exprop(n) == Ostruct) - checkstruct(st, n); - else if (n->type == Nexpr && exprop(n) == Ovar) - checkvar(st, n); - else - die("Thing we shouldn't be checking in postcheck\n"); - popstab(); - } + size_t i; + Node *n; + + for (i = 0; i < st->npostcheck; i++) { + n = st->postcheck[i]; + pushstab(st->postcheckscope[i]); + if (n->type == Nexpr && exprop(n) == Omemb) + infercompn(st, n); + else if (n->type == Nexpr && exprop(n) == Ocast) + checkcast(st, n); + else if (n->type == Nexpr && exprop(n) == Ostruct) + checkstruct(st, n); + else if (n->type == Nexpr && exprop(n) == Ovar) + checkvar(st, n); + else + die("Thing we shouldn't be checking in postcheck\n"); + popstab(); + } } /* After inference, replace all @@ -1967,390 +1995,384 @@ static void postcheck(Inferstate *st, Node *file) * the final computed types */ static void stabsub(Inferstate *st, Stab *s) { - void **k; - size_t n, i; - Type *t; - Node *d; + void **k; + size_t n, i; + Type *t; + Node *d; - k = htkeys(s->ty, &n); - for (i = 0; i < n; i++) { - t = tysearch(gettype(s, k[i])); - updatetype(s, k[i], t); - tyfix(st, k[i], t, 0); - } - free(k); + k = htkeys(s->ty, &n); + for (i = 0; i < n; i++) { + t = tysearch(gettype(s, k[i])); + updatetype(s, k[i], t); + tyfix(st, k[i], t, 0); + } + free(k); - k = htkeys(s->dcl, &n); - for (i = 0; i < n; i++) { - d = getdcl(s, k[i]); - if (d) - d->decl.type = tyfix(st, d, d->decl.type, 0); - } - free(k); + k = htkeys(s->dcl, &n); + for (i = 0; i < n; i++) { + d = getdcl(s, k[i]); + if (d) + d->decl.type = tyfix(st, d, d->decl.type, 0); + } + free(k); } static void checkrange(Inferstate *st, Node *n) { - Type *t; - int64_t sval; - uint64_t uval; - static const int64_t svranges[][2] = { - /* signed ints */ - [Tyint8] = {-128LL, 127LL}, - [Tyint16] = {-32768LL, 32767LL}, - [Tyint32] = {-2147483648LL, 2*2147483647LL}, /* FIXME: this has been doubled allow for uints... */ - [Tyint] = {-2147483648LL, 2*2147483647LL}, - [Tyint64] = {-9223372036854775808ULL, 9223372036854775807LL}, - }; - - static const uint64_t uvranges[][2] = { - [Tybyte] = {0, 255ULL}, - [Tyuint8] = {0, 255ULL}, - [Tyuint16] = {0, 65535ULL}, - [Tyuint32] = {0, 4294967295ULL}, - [Tyuint64] = {0, 18446744073709551615ULL}, - [Tychar] = {0, 4294967295ULL}, - }; - - /* signed types */ - t = type(st, n); - if (t->type >= Tyint8 && t->type <= Tyint64) { - sval = n->lit.intval; - if (sval < svranges[t->type][0] || sval > svranges[t->type][1]) - fatal(n, "literal value %lld out of range for type \"%s\"", sval, tystr(t)); - } else if ((t->type >= Tybyte && t->type <= Tyint64) || t->type == Tychar) { - uval = n->lit.intval; - if (uval < uvranges[t->type][0] || uval > uvranges[t->type][1]) - fatal(n, "literal value %llu out of range for type \"%s\"", uval, tystr(t)); - } + Type *t; + int64_t sval; + uint64_t uval; + static const int64_t svranges[][2] = { + /* signed ints */ + [Tyint8] = {-128LL, 127LL}, [Tyint16] = {-32768LL, 32767LL}, + /* FIXME: this has been doubled allow for uints... */ + [Tyint32] = {-2147483648LL, 2 * 2147483647LL}, + [Tyint] = {-2147483648LL, 2 * 2147483647LL}, + [Tyint64] = {-9223372036854775808ULL, 9223372036854775807LL}, + }; + + static const uint64_t uvranges[][2] = { + [Tybyte] = {0, 255ULL}, [Tyuint8] = {0, 255ULL}, [Tyuint16] = {0, 65535ULL}, + [Tyuint32] = {0, 4294967295ULL}, [Tyuint64] = {0, 18446744073709551615ULL}, + [Tychar] = {0, 4294967295ULL}, + }; + + /* signed types */ + t = type(st, n); + if (t->type >= Tyint8 && t->type <= Tyint64) { + sval = n->lit.intval; + if (sval < svranges[t->type][0] || sval > svranges[t->type][1]) + fatal(n, "literal value %lld out of range for type \"%s\"", sval, tystr(t)); + } + else if ((t->type >= Tybyte && t->type <= Tyint64) || t->type == Tychar) { + uval = n->lit.intval; + if (uval < uvranges[t->type][0] || uval > uvranges[t->type][1]) + fatal(n, "literal value %llu out of range for type \"%s\"", uval, tystr(t)); + } } static int initcompatible(Type *t) { - if (t->type != Tyfunc) - return 0; - if (t->nsub != 1) - return 0; - if (tybase(t->sub[0])->type != Tyvoid) - return 0; - return 1; + if (t->type != Tyfunc) + return 0; + if (t->nsub != 1) + return 0; + if (tybase(t->sub[0])->type != Tyvoid) + return 0; + return 1; } static int maincompatible(Type *t) { - if (t->nsub > 2) - return 0; - if (tybase(t->sub[0])->type != Tyvoid) - return 0; - if (t->nsub == 2) { - t = tybase(t->sub[1]); - if (t->type != Tyslice) - return 0; - t = tybase(t->sub[0]); - if (t->type != Tyslice) - return 0; - t = tybase(t->sub[0]); - if (t->type != Tybyte) - return 0; - } - return 1; + if (t->nsub > 2) + return 0; + if (tybase(t->sub[0])->type != Tyvoid) + return 0; + if (t->nsub == 2) { + t = tybase(t->sub[1]); + if (t->type != Tyslice) + return 0; + t = tybase(t->sub[0]); + if (t->type != Tyslice) + return 0; + t = tybase(t->sub[0]); + if (t->type != Tybyte) + return 0; + } + return 1; } /* After type inference, replace all types * with the final computed type */ static void typesub(Inferstate *st, Node *n, int noerr) { - size_t i; - - if (!n) - return; - switch (n->type) { - case Nfile: - pushstab(n->file.globls); - stabsub(st, n->file.globls); - for (i = 0; i < n->file.nstmts; i++) - typesub(st, n->file.stmts[i], noerr); - popstab(); - break; - case Ndecl: - settype(st, n, tyfix(st, n, type(st, n), noerr)); - if (n->decl.init) - typesub(st, n->decl.init, noerr); - if (streq(declname(n), "main")) - if (!maincompatible(tybase(decltype(n)))) - fatal(n, "main must be (->void) or (byte[:][:] -> void), got %s", tystr(decltype(n))); - if (streq(declname(n), "__init__")) - if (!initcompatible(tybase(decltype(n)))) - fatal(n, "__init__ must be (->void), got %s", tystr(decltype(n))); - break; - case Nblock: - pushstab(n->block.scope); - for (i = 0; i < n->block.nstmts; i++) - typesub(st, n->block.stmts[i], noerr); - popstab(); - break; - case Nifstmt: - typesub(st, n->ifstmt.cond, noerr); - typesub(st, n->ifstmt.iftrue, noerr); - typesub(st, n->ifstmt.iffalse, noerr); - break; - case Nloopstmt: - typesub(st, n->loopstmt.cond, noerr); - typesub(st, n->loopstmt.init, noerr); - typesub(st, n->loopstmt.step, noerr); - typesub(st, n->loopstmt.body, noerr); - break; - case Niterstmt: - typesub(st, n->iterstmt.elt, noerr); - typesub(st, n->iterstmt.seq, noerr); - typesub(st, n->iterstmt.body, noerr); - break; - case Nmatchstmt: - typesub(st, n->matchstmt.val, noerr); - for (i = 0; i < n->matchstmt.nmatches; i++) { - typesub(st, n->matchstmt.matches[i], noerr); - } - break; - case Nmatch: - typesub(st, n->match.pat, noerr); - typesub(st, n->match.block, noerr); - break; - case Nexpr: - settype(st, n, tyfix(st, n, type(st, n), 0)); - typesub(st, n->expr.idx, noerr); - if (exprop(n) == Ocast && exprop(n->expr.args[0]) == Olit && n->expr.args[0]->expr.args[0]->lit.littype == Lint) { - settype(st, n->expr.args[0], exprtype(n)); - settype(st, n->expr.args[0]->expr.args[0], exprtype(n)); - } - for (i = 0; i < n->expr.nargs; i++) - typesub(st, n->expr.args[i], noerr); - break; - case Nfunc: - pushstab(n->func.scope); - settype(st, n, tyfix(st, n, n->func.type, 0)); - for (i = 0; i < n->func.nargs; i++) - typesub(st, n->func.args[i], noerr); - typesub(st, n->func.body, noerr); - popstab(); - break; - case Nlit: - settype(st, n, tyfix(st, n, type(st, n), 0)); - switch (n->lit.littype) { - case Lfunc: - typesub(st, n->lit.fnval, noerr); break; - case Lint: - checkrange(st, n); - default: break; - } - break; - case Nimpl: - putimpl(curstab(), n); - break; - case Nname: - case Nuse: - break; - case Nnone: - die("Nnone should not be seen as node type!"); - break; - } + size_t i; + + if (!n) + return; + switch (n->type) { + case Nfile: + pushstab(n->file.globls); + stabsub(st, n->file.globls); + for (i = 0; i < n->file.nstmts; i++) + typesub(st, n->file.stmts[i], noerr); + popstab(); + break; + case Ndecl: + settype(st, n, tyfix(st, n, type(st, n), noerr)); + if (n->decl.init) + typesub(st, n->decl.init, noerr); + if (streq(declname(n), "main")) + if (!maincompatible(tybase(decltype(n)))) + fatal(n, "main must be (->void) or (byte[:][:] -> void), got %s", + tystr(decltype(n))); + if (streq(declname(n), "__init__")) + if (!initcompatible(tybase(decltype(n)))) + fatal(n, "__init__ must be (->void), got %s", tystr(decltype(n))); + break; + case Nblock: + pushstab(n->block.scope); + for (i = 0; i < n->block.nstmts; i++) + typesub(st, n->block.stmts[i], noerr); + popstab(); + break; + case Nifstmt: + typesub(st, n->ifstmt.cond, noerr); + typesub(st, n->ifstmt.iftrue, noerr); + typesub(st, n->ifstmt.iffalse, noerr); + break; + case Nloopstmt: + typesub(st, n->loopstmt.cond, noerr); + typesub(st, n->loopstmt.init, noerr); + typesub(st, n->loopstmt.step, noerr); + typesub(st, n->loopstmt.body, noerr); + break; + case Niterstmt: + typesub(st, n->iterstmt.elt, noerr); + typesub(st, n->iterstmt.seq, noerr); + typesub(st, n->iterstmt.body, noerr); + break; + case Nmatchstmt: + typesub(st, n->matchstmt.val, noerr); + for (i = 0; i < n->matchstmt.nmatches; i++) { + typesub(st, n->matchstmt.matches[i], noerr); + } + break; + case Nmatch: + typesub(st, n->match.pat, noerr); + typesub(st, n->match.block, noerr); + break; + case Nexpr: + settype(st, n, tyfix(st, n, type(st, n), 0)); + typesub(st, n->expr.idx, noerr); + if (exprop(n) == Ocast && exprop(n->expr.args[0]) == Olit && + n->expr.args[0]->expr.args[0]->lit.littype == Lint) { + settype(st, n->expr.args[0], exprtype(n)); + settype(st, n->expr.args[0]->expr.args[0], exprtype(n)); + } + for (i = 0; i < n->expr.nargs; i++) + typesub(st, n->expr.args[i], noerr); + break; + case Nfunc: + pushstab(n->func.scope); + settype(st, n, tyfix(st, n, n->func.type, 0)); + for (i = 0; i < n->func.nargs; i++) + typesub(st, n->func.args[i], noerr); + typesub(st, n->func.body, noerr); + popstab(); + break; + case Nlit: + settype(st, n, tyfix(st, n, type(st, n), 0)); + switch (n->lit.littype) { + case Lfunc: typesub(st, n->lit.fnval, noerr); break; + case Lint: checkrange(st, n); + default: break; + } + break; + case Nimpl: putimpl(curstab(), n); break; + case Nname: + case Nuse: break; + case Nnone: die("Nnone should not be seen as node type!"); break; + } } static void taghidden(Type *t) { - size_t i; - - if (t->vis != Visintern) - return; - t->vis = Vishidden; - for (i = 0; i < t->nsub; i++) - taghidden(t->sub[i]); - switch (t->type) { - case Tystruct: - for (i = 0; i < t->nmemb; i++) - taghidden(decltype(t->sdecls[i])); - break; - case Tyunion: - for (i = 0; i < t->nmemb; i++) - if (t->udecls[i]->etype) - taghidden(t->udecls[i]->etype); - break; - case Tyname: - t->isreflect = 1; - for (i = 0; i < t->narg; i++) - taghidden(t->arg[i]); - case Tygeneric: - for (i = 0; i < t->ngparam; i++) - taghidden(t->gparam[i]); - break; - default: - break; - } + size_t i; + + if (t->vis != Visintern) + return; + t->vis = Vishidden; + for (i = 0; i < t->nsub; i++) + taghidden(t->sub[i]); + switch (t->type) { + case Tystruct: + for (i = 0; i < t->nmemb; i++) + taghidden(decltype(t->sdecls[i])); + break; + case Tyunion: + for (i = 0; i < t->nmemb; i++) + if (t->udecls[i]->etype) + taghidden(t->udecls[i]->etype); + break; + case Tyname: + t->isreflect = 1; + for (i = 0; i < t->narg; i++) + taghidden(t->arg[i]); + case Tygeneric: + for (i = 0; i < t->ngparam; i++) + taghidden(t->gparam[i]); + break; + default: break; + } } int isexportinit(Node *n) { - if (n->decl.isgeneric && !n->decl.trait) - return 1; - /* we want to inline small values, which means we need to export them */ - if (istyprimitive(n->decl.type)) - return 1; - return 0; + if (n->decl.isgeneric && !n->decl.trait) + return 1; + /* we want to inline small values, which means we need to export them */ + if (istyprimitive(n->decl.type)) + return 1; + return 0; } static void nodetag(Stab *st, Node *n, int ingeneric, int hidelocal) { - size_t i; - Node *d; - - if (!n) - return; - switch (n->type) { - case Nblock: - for (i = 0; i < n->block.nstmts; i++) - nodetag(st, n->block.stmts[i], ingeneric, hidelocal); - break; - case Nifstmt: - nodetag(st, n->ifstmt.cond, ingeneric, hidelocal); - nodetag(st, n->ifstmt.iftrue, ingeneric, hidelocal); - nodetag(st, n->ifstmt.iffalse, ingeneric, hidelocal); - break; - case Nloopstmt: - nodetag(st, n->loopstmt.init, ingeneric, hidelocal); - nodetag(st, n->loopstmt.cond, ingeneric, hidelocal); - nodetag(st, n->loopstmt.step, ingeneric, hidelocal); - nodetag(st, n->loopstmt.body, ingeneric, hidelocal); - break; - case Niterstmt: - nodetag(st, n->iterstmt.elt, ingeneric, hidelocal); - nodetag(st, n->iterstmt.seq, ingeneric, hidelocal); - nodetag(st, n->iterstmt.body, ingeneric, hidelocal); - break; - case Nmatchstmt: - nodetag(st, n->matchstmt.val, ingeneric, hidelocal); - for (i = 0; i < n->matchstmt.nmatches; i++) - nodetag(st, n->matchstmt.matches[i], ingeneric, hidelocal); - break; - case Nmatch: - nodetag(st, n->match.pat, ingeneric, hidelocal); - nodetag(st, n->match.block, ingeneric, hidelocal); - break; - case Nexpr: - nodetag(st, n->expr.idx, ingeneric, hidelocal); - taghidden(n->expr.type); - for (i = 0; i < n->expr.nargs; i++) - nodetag(st, n->expr.args[i], ingeneric, hidelocal); - /* generics need to have the decls they refer to exported. */ - if (ingeneric && exprop(n) == Ovar) { - d = decls[n->expr.did]; - if (d->decl.isglobl && d->decl.vis == Visintern) { - d->decl.vis = Vishidden; - nodetag(st, d, ingeneric, hidelocal); - } - } - break; - case Nlit: - taghidden(n->lit.type); - if (n->lit.littype == Lfunc) - nodetag(st, n->lit.fnval, ingeneric, hidelocal); - break; - case Ndecl: - taghidden(n->decl.type); - if (hidelocal && n->decl.ispkglocal) - n->decl.vis = Vishidden; - n->decl.isexportinit = isexportinit(n); - if (n->decl.isexportinit) - nodetag(st, n->decl.init, n->decl.isgeneric, hidelocal); - break; - case Nfunc: - taghidden(n->func.type); - for (i = 0; i < n->func.nargs; i++) - nodetag(st, n->func.args[i], ingeneric, hidelocal); - nodetag(st, n->func.body, ingeneric, hidelocal); - break; - case Nimpl: - for (i = 0; i < n->impl.ndecls; i++) { - n->impl.decls[i]->decl.vis = Vishidden; - nodetag(st, n->impl.decls[i], 0, hidelocal); - } - break; - case Nuse: case Nname: - break; - case Nfile: case Nnone: - die("Invalid node for type export\n"); - break; - } + size_t i; + Node *d; + + if (!n) + return; + switch (n->type) { + case Nblock: + for (i = 0; i < n->block.nstmts; i++) + nodetag(st, n->block.stmts[i], ingeneric, hidelocal); + break; + case Nifstmt: + nodetag(st, n->ifstmt.cond, ingeneric, hidelocal); + nodetag(st, n->ifstmt.iftrue, ingeneric, hidelocal); + nodetag(st, n->ifstmt.iffalse, ingeneric, hidelocal); + break; + case Nloopstmt: + nodetag(st, n->loopstmt.init, ingeneric, hidelocal); + nodetag(st, n->loopstmt.cond, ingeneric, hidelocal); + nodetag(st, n->loopstmt.step, ingeneric, hidelocal); + nodetag(st, n->loopstmt.body, ingeneric, hidelocal); + break; + case Niterstmt: + nodetag(st, n->iterstmt.elt, ingeneric, hidelocal); + nodetag(st, n->iterstmt.seq, ingeneric, hidelocal); + nodetag(st, n->iterstmt.body, ingeneric, hidelocal); + break; + case Nmatchstmt: + nodetag(st, n->matchstmt.val, ingeneric, hidelocal); + for (i = 0; i < n->matchstmt.nmatches; i++) + nodetag(st, n->matchstmt.matches[i], ingeneric, hidelocal); + break; + case Nmatch: + nodetag(st, n->match.pat, ingeneric, hidelocal); + nodetag(st, n->match.block, ingeneric, hidelocal); + break; + case Nexpr: + nodetag(st, n->expr.idx, ingeneric, hidelocal); + taghidden(n->expr.type); + for (i = 0; i < n->expr.nargs; i++) + nodetag(st, n->expr.args[i], ingeneric, hidelocal); + /* generics need to have the decls they refer to exported. */ + if (ingeneric && exprop(n) == Ovar) { + d = decls[n->expr.did]; + if (d->decl.isglobl && d->decl.vis == Visintern) { + d->decl.vis = Vishidden; + nodetag(st, d, ingeneric, hidelocal); + } + } + break; + case Nlit: + taghidden(n->lit.type); + if (n->lit.littype == Lfunc) + nodetag(st, n->lit.fnval, ingeneric, hidelocal); + break; + case Ndecl: + taghidden(n->decl.type); + if (hidelocal && n->decl.ispkglocal) + n->decl.vis = Vishidden; + n->decl.isexportinit = isexportinit(n); + if (n->decl.isexportinit) + nodetag(st, n->decl.init, n->decl.isgeneric, hidelocal); + break; + case Nfunc: + taghidden(n->func.type); + for (i = 0; i < n->func.nargs; i++) + nodetag(st, n->func.args[i], ingeneric, hidelocal); + nodetag(st, n->func.body, ingeneric, hidelocal); + break; + case Nimpl: + for (i = 0; i < n->impl.ndecls; i++) { + n->impl.decls[i]->decl.vis = Vishidden; + nodetag(st, n->impl.decls[i], 0, hidelocal); + } + break; + case Nuse: + case Nname: + break; + case Nfile: + case Nnone: + die("Invalid node for type export\n"); + break; + } } void tagexports(Node *file, int hidelocal) { - size_t i, j, n; - Trait *tr; - Stab *st; - void **k; - Node *s; - Type *t; - - st = file->file.globls; - k = htkeys(st->dcl, &n); - for (i = 0; i < n; i++) { - s = getdcl(st, k[i]); - if (s->decl.vis == Visexport) - nodetag(st, s, 0, hidelocal); - } - free(k); - - k = htkeys(st->impl, &n); - for (i = 0; i < n; i++) { - s = getimpl(st, k[i]); - if (s->impl.vis == Visexport) - nodetag(st, s, 0, hidelocal); - } - free(k); - - for (i = 0; i < file->file.ninit; i++) - nodetag(st, file->file.init[i], 0, hidelocal); - if (file->file.localinit) - nodetag(st, file->file.localinit, 0, hidelocal); - - k = htkeys(st->tr, &n); - for (i = 0; i < n; i++) { - tr = gettrait(st, k[i]); - if (tr->vis == Visexport) { - tr->param->vis = Visexport; - for (i = 0; i < tr->nmemb; i++) { - tr->memb[i]->decl.vis = Visexport; - nodetag(st, tr->memb[i], 0, hidelocal); - } - for (i = 0; i < tr->nfuncs; i++) { - tr->funcs[i]->decl.vis = Visexport; - nodetag(st, tr->funcs[i], 0, hidelocal); - } - } - } - free(k); - - /* get the explicitly exported symbols */ - k = htkeys(st->ty, &n); - for (i = 0; i < n; i++) { - t = gettype(st, k[i]); - if (!t->isreflect && t->vis != Visexport) - continue; - if (hidelocal && t->ispkglocal) - t->vis = Vishidden; - taghidden(t); - for (j = 0; j < t->nsub; j++) - taghidden(t->sub[j]); - if (t->type == Tyname) { - t->isreflect = 1; - for (j = 0; j < t->narg; j++) - taghidden(t->arg[j]); - } else if (t->type == Tygeneric) { - for (j = 0; j < t->ngparam; j++) - taghidden(t->gparam[j]); - } - } - free(k); - + size_t i, j, n; + Trait *tr; + Stab *st; + void **k; + Node *s; + Type *t; + + st = file->file.globls; + k = htkeys(st->dcl, &n); + for (i = 0; i < n; i++) { + s = getdcl(st, k[i]); + if (s->decl.vis == Visexport) + nodetag(st, s, 0, hidelocal); + } + free(k); + + k = htkeys(st->impl, &n); + for (i = 0; i < n; i++) { + s = getimpl(st, k[i]); + if (s->impl.vis == Visexport) + nodetag(st, s, 0, hidelocal); + } + free(k); + + for (i = 0; i < file->file.ninit; i++) + nodetag(st, file->file.init[i], 0, hidelocal); + if (file->file.localinit) + nodetag(st, file->file.localinit, 0, hidelocal); + + k = htkeys(st->tr, &n); + for (i = 0; i < n; i++) { + tr = gettrait(st, k[i]); + if (tr->vis == Visexport) { + tr->param->vis = Visexport; + for (i = 0; i < tr->nmemb; i++) { + tr->memb[i]->decl.vis = Visexport; + nodetag(st, tr->memb[i], 0, hidelocal); + } + for (i = 0; i < tr->nfuncs; i++) { + tr->funcs[i]->decl.vis = Visexport; + nodetag(st, tr->funcs[i], 0, hidelocal); + } + } + } + free(k); + + /* get the explicitly exported symbols */ + k = htkeys(st->ty, &n); + for (i = 0; i < n; i++) { + t = gettype(st, k[i]); + if (!t->isreflect && t->vis != Visexport) + continue; + if (hidelocal && t->ispkglocal) + t->vis = Vishidden; + taghidden(t); + for (j = 0; j < t->nsub; j++) + taghidden(t->sub[j]); + if (t->type == Tyname) { + t->isreflect = 1; + for (j = 0; j < t->narg; j++) + taghidden(t->arg[j]); + } + else if (t->type == Tygeneric) { + for (j = 0; j < t->ngparam; j++) + taghidden(t->gparam[j]); + } + } + free(k); } /* Take generics and build new versions of them @@ -2358,80 +2380,82 @@ void tagexports(Node *file, int hidelocal) * specialized types */ static void specialize(Inferstate *st, Node *f) { - Node *d, *name; - size_t i; + Node *d, *name; + size_t i; - for (i = 0; i < st->nspecializations; i++) { - pushstab(st->specializationscope[i]); - d = specializedcl(st->genericdecls[i], st->specializations[i]->expr.type, &name); - st->specializations[i]->expr.args[0] = name; - st->specializations[i]->expr.did = d->decl.did; + for (i = 0; i < st->nspecializations; i++) { + pushstab(st->specializationscope[i]); + d = specializedcl(st->genericdecls[i], st->specializations[i]->expr.type, &name); + st->specializations[i]->expr.args[0] = name; + st->specializations[i]->expr.did = d->decl.did; - /* we need to sub in default types in the specialization, so call - * typesub on the specialized function */ - typesub(st, d, 0); - popstab(); - } + /* we need to sub in default types in the specialization, so call + * typesub on the specialized function */ + typesub(st, d, 0); + popstab(); + } } void applytraits(Inferstate *st, Node *f) { - size_t i; - Node *n; - Trait *trait; - Type *ty; - - pushstab(f->file.globls); - /* for now, traits can only be declared globally */ - for (i = 0; i < f->file.nstmts; i++) { - if (f->file.stmts[i]->type == Nimpl) { - n = f->file.stmts[i]; - trait = gettrait(f->file.globls, n->impl.traitname); - if (!trait) - fatal(n, "trait %s does not exist near %s", namestr(n->impl.traitname), ctxstr(st, n)); - ty = tf(st, n->impl.type); - settrait(ty, trait); - } - } - popstab(); + size_t i; + Node *n; + Trait *trait; + Type *ty; + + pushstab(f->file.globls); + /* for now, traits can only be declared globally */ + for (i = 0; i < f->file.nstmts; i++) { + if (f->file.stmts[i]->type == Nimpl) { + n = f->file.stmts[i]; + trait = gettrait(f->file.globls, n->impl.traitname); + if (!trait) + fatal(n, "trait %s does not exist near %s", + namestr(n->impl.traitname), ctxstr(st, n)); + ty = tf(st, n->impl.type); + settrait(ty, trait); + } + } + popstab(); } void verify(Inferstate *st, Node *f) { - Node *n; - size_t i; + Node *n; + size_t i; - pushstab(f->file.globls); - /* for now, traits can only be declared globally */ - for (i = 0; i < f->file.nstmts; i++) { - if (f->file.stmts[i]->type == Nimpl) { - n = f->file.stmts[i]; - /* we merge, so we need to get it back again when error checking */ - if (n->impl.isproto) - fatal(n, "missing implementation for prototype '%s %s'", - namestr(n->impl.traitname), tystr(n->impl.type)); - } - } + pushstab(f->file.globls); + /* for now, traits can only be declared globally */ + for (i = 0; i < f->file.nstmts; i++) { + if (f->file.stmts[i]->type == Nimpl) { + n = f->file.stmts[i]; + /* we merge, so we need to get it back again when error checking */ + if (n->impl.isproto) + fatal(n, "missing implementation for prototype '%s %s'", + namestr(n->impl.traitname), tystr(n->impl.type)); + } + } } void infer(Node *file) { - Inferstate st = {0,}; + Inferstate st = { + 0, + }; - assert(file->type == Nfile); - st.delayed = mkht(tyhash, tyeq); - /* set up the symtabs */ - loaduses(file); - //mergeexports(&st, file); + assert(file->type == Nfile); + st.delayed = mkht(tyhash, tyeq); + /* set up the symtabs */ + loaduses(file); + // mergeexports(&st, file); - /* do the inference */ - applytraits(&st, file); - infernode(&st, &file, NULL, NULL); - postcheck(&st, file); + /* do the inference */ + applytraits(&st, file); + infernode(&st, &file, NULL, NULL); + postcheck(&st, file); - /* and replace type vars with actual types */ - typesub(&st, file, 0); - specialize(&st, file); - verify(&st, file); + /* and replace type vars with actual types */ + typesub(&st, file, 0); + specialize(&st, file); + verify(&st, file); } - diff --git a/parse/names.c b/parse/names.c index 6fe76b8..31f2b4d 100644 --- a/parse/names.c +++ b/parse/names.c @@ -12,19 +12,18 @@ #include "parse.h" -char *opstr[] = { +char *opstr[] = { #define O(op, pure, class, pretty) #op, #include "ops.def" #undef O }; -char * oppretty[] = { +char *oppretty[] = { #define O(op, pure, class, pretty) pretty, #include "ops.def" #undef O }; - int opispure[] = { #define O(op, pure, class, pretty) pure, #include "ops.def" @@ -37,19 +36,19 @@ int opclass[] = { #undef O }; -char *nodestr[] = { +char *nodestr[] = { #define N(nt) #nt, #include "nodes.def" #undef N }; -char *litstr[] = { +char *litstr[] = { #define L(lt) #lt, #include "lits.def" #undef L }; -char *tidstr[] = { +char *tidstr[] = { #define Ty(t, n, stk) n, #include "types.def" #undef Ty diff --git a/parse/node.c b/parse/node.c index 6555ccf..62be764 100644 --- a/parse/node.c +++ b/parse/node.c @@ -17,15 +17,9 @@ size_t nnodes; Node **decls; size_t ndecls; -char *fname(Srcloc l) -{ - return file->file.files[l.file]; -} +char *fname(Srcloc l) { return file->file.files[l.file]; } -int lnum(Srcloc l) -{ - return l.line; -} +int lnum(Srcloc l) { return l.line; } /* * Bah, this is going to need to know how to fold things. @@ -33,487 +27,473 @@ int lnum(Srcloc l) */ uint64_t arraysz(Node *sz) { - Node *n; + Node *n; - n = sz; - if (exprop(n) != Olit) - fatal(sz, "too many layers of indirection when finding intializer. (initialization loop?)"); + n = sz; + if (exprop(n) != Olit) + fatal(sz, "too much indirection when finding intializer. (initialization loop?)"); - n = n->expr.args[0]; - if (n->lit.littype != Lint) - fatal(sz, "initializer is not an integer"); - return n->lit.intval; + n = n->expr.args[0]; + if (n->lit.littype != Lint) + fatal(sz, "initializer is not an integer"); + return n->lit.intval; } Node *mknode(Srcloc loc, Ntype nt) { - Node *n; + Node *n; - n = zalloc(sizeof(Node)); - n->nid = nnodes; - n->type = nt; - n->loc = loc; - lappend(&nodes, &nnodes, n); - return n; + n = zalloc(sizeof(Node)); + n->nid = nnodes; + n->type = nt; + n->loc = loc; + lappend(&nodes, &nnodes, n); + return n; } Node *mkfile(char *name) { - Node *n; + Node *n; - n = mknode(Zloc, Nfile); - n->file.ns = mkht(strhash, streq); - lappend(&n->file.files, &n->file.nfiles, strdup(name)); - return n; + n = mknode(Zloc, Nfile); + n->file.ns = mkht(strhash, streq); + lappend(&n->file.files, &n->file.nfiles, strdup(name)); + return n; } Node *mkuse(Srcloc loc, char *use, int islocal) { - Node *n; + Node *n; - n = mknode(loc, Nuse); - n->use.name = strdup(use); - n->use.islocal = islocal; + n = mknode(loc, Nuse); + n->use.name = strdup(use); + n->use.islocal = islocal; - return n; + return n; } Node *mksliceexpr(Srcloc loc, Node *sl, Node *base, Node *off) { - if (!base) - base = mkintlit(loc, 0); - if (!off) - off = mkexpr(loc, Omemb, sl, mkname(loc, "len"), NULL); - return mkexpr(loc, Oslice, sl, base, off, NULL); + if (!base) + base = mkintlit(loc, 0); + if (!off) + off = mkexpr(loc, Omemb, sl, mkname(loc, "len"), NULL); + return mkexpr(loc, Oslice, sl, base, off, NULL); } Node *mkexprl(Srcloc loc, Op op, Node **args, size_t nargs) { - Node *n; + Node *n; - n = mknode(loc, Nexpr); - n->expr.op = op; - n->expr.args = args; - n->expr.nargs = nargs; - return n; + n = mknode(loc, Nexpr); + n->expr.op = op; + n->expr.args = args; + n->expr.nargs = nargs; + return n; } Node *mkexpr(Srcloc loc, Op op, ...) { - Node *n; - va_list ap; - Node *arg; + Node *n; + va_list ap; + Node *arg; - n = mknode(loc, Nexpr); - n->expr.op = op; - va_start(ap, op); - while ((arg = va_arg(ap, Node*)) != NULL) - lappend(&n->expr.args, &n->expr.nargs, arg); - va_end(ap); + n = mknode(loc, Nexpr); + n->expr.op = op; + va_start(ap, op); + while ((arg = va_arg(ap, Node *)) != NULL) + lappend(&n->expr.args, &n->expr.nargs, arg); + va_end(ap); - return n; + return n; } -Node *mkcall(Srcloc loc, Node *fn, Node **args, size_t nargs) +Node *mkcall(Srcloc loc, Node *fn, Node **args, size_t nargs) { - Node *n; - size_t i; + Node *n; + size_t i; - n = mkexpr(loc, Ocall, fn, NULL); - for (i = 0; i < nargs; i++) - lappend(&n->expr.args, &n->expr.nargs, args[i]); - return n; + n = mkexpr(loc, Ocall, fn, NULL); + for (i = 0; i < nargs; i++) + lappend(&n->expr.args, &n->expr.nargs, args[i]); + return n; } Node *mkifstmt(Srcloc loc, Node *cond, Node *iftrue, Node *iffalse) { - Node *n; + Node *n; - n = mknode(loc, Nifstmt); - n->ifstmt.cond = cond; - n->ifstmt.iftrue = iftrue; - n->ifstmt.iffalse = iffalse; + n = mknode(loc, Nifstmt); + n->ifstmt.cond = cond; + n->ifstmt.iftrue = iftrue; + n->ifstmt.iffalse = iffalse; - return n; + return n; } Node *mkloopstmt(Srcloc loc, Node *init, Node *cond, Node *incr, Node *body) { - Node *n; + Node *n; - n = mknode(loc, Nloopstmt); - n->loopstmt.init = init; - n->loopstmt.cond = cond; - n->loopstmt.step = incr; - n->loopstmt.body = body; - n->loopstmt.scope = mkstab(0); + n = mknode(loc, Nloopstmt); + n->loopstmt.init = init; + n->loopstmt.cond = cond; + n->loopstmt.step = incr; + n->loopstmt.body = body; + n->loopstmt.scope = mkstab(0); - return n; + return n; } Node *mkiterstmt(Srcloc loc, Node *elt, Node *seq, Node *body) { - Node *n; + Node *n; - n = mknode(loc, Niterstmt); - n->iterstmt.elt = elt; - n->iterstmt.seq = seq; - n->iterstmt.body = body; + n = mknode(loc, Niterstmt); + n->iterstmt.elt = elt; + n->iterstmt.seq = seq; + n->iterstmt.body = body; - return n; + return n; } Node *mkmatchstmt(Srcloc loc, Node *val, Node **matches, size_t nmatches) { - Node *n; + Node *n; - n = mknode(loc, Nmatchstmt); - n->matchstmt.val = val; - n->matchstmt.matches = matches; - n->matchstmt.nmatches = nmatches; - return n; + n = mknode(loc, Nmatchstmt); + n->matchstmt.val = val; + n->matchstmt.matches = matches; + n->matchstmt.nmatches = nmatches; + return n; } Node *mkmatch(Srcloc loc, Node *pat, Node *body) { - Node *n; + Node *n; - n = mknode(loc, Nmatch); - n->match.pat = pat; - n->match.block = body; - return n; + n = mknode(loc, Nmatch); + n->match.pat = pat; + n->match.block = body; + return n; } Node *mkfunc(Srcloc loc, Node **args, size_t nargs, Type *ret, Node *body) { - Node *n; - Node *f; - size_t i; + Node *n; + Node *f; + size_t i; - f = mknode(loc, Nfunc); - f->func.args = args; - f->func.nargs = nargs; - f->func.body = body; - f->func.scope = mkstab(1); - f->func.type = mktyfunc(loc, args, nargs, ret); + f = mknode(loc, Nfunc); + f->func.args = args; + f->func.nargs = nargs; + f->func.body = body; + f->func.scope = mkstab(1); + f->func.type = mktyfunc(loc, args, nargs, ret); - for (i = 0; i < nargs; i++) - putdcl(f->func.scope, args[i]); + for (i = 0; i < nargs; i++) + putdcl(f->func.scope, args[i]); - n = mknode(loc, Nlit); - n->lit.littype = Lfunc; - n->lit.fnval = f; - return n; + n = mknode(loc, Nlit); + n->lit.littype = Lfunc; + n->lit.fnval = f; + return n; } Node *mkblock(Srcloc loc, Stab *scope) { - Node *n; + Node *n; - n = mknode(loc, Nblock); - n->block.scope = scope; - return n; + n = mknode(loc, Nblock); + n->block.scope = scope; + return n; } - Node *mkimplstmt(Srcloc loc, Node *name, Type *t, Node **decls, size_t ndecls) { - Node *n; + Node *n; - n = mknode(loc, Nimpl); - n->impl.traitname = name; - n->impl.type = t; - n->impl.decls = decls; - n->impl.ndecls = ndecls; - return n; + n = mknode(loc, Nimpl); + n->impl.traitname = name; + n->impl.type = t; + n->impl.decls = decls; + n->impl.ndecls = ndecls; + return n; } - -Node *mkintlit(Srcloc loc, uvlong val) -{ - return mkexpr(loc, Olit, mkint(loc, val), NULL); -} +Node *mkintlit(Srcloc loc, uvlong val) { return mkexpr(loc, Olit, mkint(loc, val), NULL); } Node *mklbl(Srcloc loc, char *lbl) { - Node *n; + Node *n; - assert(lbl != NULL); - n = mknode(loc, Nlit); - n->lit.littype = Llbl; - n->lit.lblval = strdup(lbl); - return mkexpr(loc, Olit, n, NULL); + assert(lbl != NULL); + n = mknode(loc, Nlit); + n->lit.littype = Llbl; + n->lit.lblval = strdup(lbl); + return mkexpr(loc, Olit, n, NULL); } char *genlblstr(char *buf, size_t sz, char *suffix) { - static int nextlbl; - bprintf(buf, 128, ".L%d%s", nextlbl++, suffix); - return buf; + static int nextlbl; + bprintf(buf, 128, ".L%d%s", nextlbl++, suffix); + return buf; } Node *genlbl(Srcloc loc) { - char buf[128]; + char buf[128]; - genlblstr(buf, 128, ""); - return mklbl(loc, buf); + genlblstr(buf, 128, ""); + return mklbl(loc, buf); } Node *mkstr(Srcloc loc, Str val) { - Node *n; + Node *n; - n = mknode(loc, Nlit); - n->lit.littype = Lstr; - n->lit.strval.len = val.len; - n->lit.strval.buf = malloc(val.len); - memcpy(n->lit.strval.buf, val.buf, val.len); + n = mknode(loc, Nlit); + n->lit.littype = Lstr; + n->lit.strval.len = val.len; + n->lit.strval.buf = malloc(val.len); + memcpy(n->lit.strval.buf, val.buf, val.len); - return n; + return n; } Node *mkint(Srcloc loc, uint64_t val) { - Node *n; + Node *n; - n = mknode(loc, Nlit); - n->lit.littype = Lint; - n->lit.intval = val; + n = mknode(loc, Nlit); + n->lit.littype = Lint; + n->lit.intval = val; - return n; + return n; } Node *mkchar(Srcloc loc, uint32_t val) { - Node *n; + Node *n; - n = mknode(loc, Nlit); - n->lit.littype = Lchr; - n->lit.chrval = val; + n = mknode(loc, Nlit); + n->lit.littype = Lchr; + n->lit.chrval = val; - return n; + return n; } Node *mkfloat(Srcloc loc, double val) { - Node *n; + Node *n; - n = mknode(loc, Nlit); - n->lit.littype = Lflt; - n->lit.fltval = val; + n = mknode(loc, Nlit); + n->lit.littype = Lflt; + n->lit.fltval = val; - return n; + return n; } Node *mkidxinit(Srcloc loc, Node *idx, Node *init) { - init->expr.idx = idx; - return init; + init->expr.idx = idx; + return init; } Node *mkname(Srcloc loc, char *name) { - Node *n; + Node *n; - n = mknode(loc, Nname); - n->name.name = strdup(name); + n = mknode(loc, Nname); + n->name.name = strdup(name); - return n; + return n; } Node *mknsname(Srcloc loc, char *ns, char *name) { - Node *n; + Node *n; - n = mknode(loc, Nname); - n->name.ns = strdup(ns); - n->name.name = strdup(name); + n = mknode(loc, Nname); + n->name.ns = strdup(ns); + n->name.name = strdup(name); - return n; + return n; } Node *mkdecl(Srcloc loc, Node *name, Type *ty) { - Node *n; + Node *n; - n = mknode(loc, Ndecl); - n->decl.did = ndecls; - n->decl.name = name; - n->decl.type = ty; - lappend(&decls, &ndecls, n); - return n; + n = mknode(loc, Ndecl); + n->decl.did = ndecls; + n->decl.name = name; + n->decl.type = ty; + lappend(&decls, &ndecls, n); + return n; } Node *gentemp(Srcloc loc, Type *ty, Node **dcl) { - char buf[128]; - static int nexttmp; - Node *t, *r, *n; + char buf[128]; + static int nexttmp; + Node *t, *r, *n; - bprintf(buf, 128, ".t%d", nexttmp++); - n = mkname(loc, buf); - t = mkdecl(loc, n, ty); - r = mkexpr(loc, Ovar, n, NULL); - r->expr.type = t->decl.type; - r->expr.did = t->decl.did; - if (dcl) - *dcl = t; - return r; + bprintf(buf, 128, ".t%d", nexttmp++); + n = mkname(loc, buf); + t = mkdecl(loc, n, ty); + r = mkexpr(loc, Ovar, n, NULL); + r->expr.type = t->decl.type; + r->expr.did = t->decl.did; + if (dcl) + *dcl = t; + return r; } Ucon *mkucon(Srcloc loc, Node *name, Type *ut, Type *et) { - Ucon *uc; + Ucon *uc; - uc = zalloc(sizeof(Ucon)); - uc->loc = loc; - uc->name = name; - uc->utype = ut; - uc->etype = et; - return uc; + uc = zalloc(sizeof(Ucon)); + uc->loc = loc; + uc->name = name; + uc->utype = ut; + uc->etype = et; + return uc; } Node *mkbool(Srcloc loc, int val) { - Node *n; + Node *n; - n = mknode(loc, Nlit); - n->lit.littype = Lbool; - n->lit.boolval = val; + n = mknode(loc, Nlit); + n->lit.littype = Lbool; + n->lit.boolval = val; - return n; + return n; } char *declname(Node *n) { - Node *name; - assert(n->type == Ndecl); - name = n->decl.name; - return name->name.name; + Node *name; + assert(n->type == Ndecl); + name = n->decl.name; + return name->name.name; } -Type *decltype(Node *n) +Type *decltype(Node * n) { - assert(n->type == Ndecl); - return nodetype(n); + assert(n->type == Ndecl); + return nodetype(n); } Type *exprtype(Node *n) { - assert(n->type == Nexpr); - return nodetype(n); + assert(n->type == Nexpr); + return nodetype(n); } Type *nodetype(Node *n) { - switch (n->type) { - case Ndecl: return n->decl.type; break; - case Nexpr: return n->expr.type; break; - case Nlit: return n->lit.type; break; - default: die("Node %s has no type", nodestr[n->type]); break; - } - return NULL; + switch (n->type) { + case Ndecl: return n->decl.type; break; + case Nexpr: return n->expr.type; break; + case Nlit: return n->lit.type; break; + default: die("Node %s has no type", nodestr[n->type]); break; + } + return NULL; } int liteq(Node *a, Node *b) { - assert(a->type == Nlit && b->type == Nlit); - if (a->lit.littype != b->lit.littype) - return 0; - if (!tyeq(a->lit.type, b->lit.type)) - return 0; - switch (a->lit.littype) { - case Lchr: - return a->lit.chrval == b->lit.chrval; - case Lbool: - return a->lit.boolval == b->lit.boolval; - case Lint: - return a->lit.intval == b->lit.intval; - case Lflt: - return a->lit.fltval == b->lit.fltval; - case Lstr: - return a->lit.strval.len == b->lit.strval.len && - !memcmp(a->lit.strval.buf, b->lit.strval.buf, a->lit.strval.len); - case Lfunc: - return a->lit.fnval == b->lit.fnval; - case Llbl: - return !strcmp(a->lit.lblval, b->lit.lblval); - break; - } - return 0; + assert(a->type == Nlit && b->type == Nlit); + if (a->lit.littype != b->lit.littype) + return 0; + if (!tyeq(a->lit.type, b->lit.type)) + return 0; + switch (a->lit.littype) { + case Lchr: return a->lit.chrval == b->lit.chrval; + case Lbool: return a->lit.boolval == b->lit.boolval; + case Lint: return a->lit.intval == b->lit.intval; + case Lflt: return a->lit.fltval == b->lit.fltval; + case Lstr: + return a->lit.strval.len == b->lit.strval.len && + !memcmp(a->lit.strval.buf, b->lit.strval.buf, a->lit.strval.len); + case Lfunc: return a->lit.fnval == b->lit.fnval; + case Llbl: return !strcmp(a->lit.lblval, b->lit.lblval); break; + } + return 0; } /* name hashing */ ulong namehash(void *p) { - Node *n; + Node *n; - n = p; - return strhash(namestr(n)) ^ strhash(n->name.ns); + n = p; + return strhash(namestr(n)) ^ strhash(n->name.ns); } int nameeq(void *p1, void *p2) { - Node *a, *b; - a = p1; - b = p2; - if (a == b) - return 1; + Node *a, *b; + a = p1; + b = p2; + if (a == b) + return 1; - return streq(namestr(a), namestr(b)) && streq(a->name.ns, b->name.ns); + return streq(namestr(a), namestr(b)) && streq(a->name.ns, b->name.ns); } void setns(Node *n, char *ns) { - assert(!n->name.ns || !strcmp(n->name.ns, ns)); - n->name.ns = strdup(ns); + assert(!n->name.ns || !strcmp(n->name.ns, ns)); + n->name.ns = strdup(ns); } Op exprop(Node *e) { - assert(e->type == Nexpr); - return e->expr.op; + assert(e->type == Nexpr); + return e->expr.op; } char *namestr(Node *name) { - if (!name) - return ""; - assert(name->type == Nname); - return name->name.name; + if (!name) + return ""; + assert(name->type == Nname); + return name->name.name; } char *lblstr(Node *n) { - assert(exprop(n) == Olit); - assert(n->expr.args[0]->type == Nlit); - assert(n->expr.args[0]->lit.littype == Llbl); - return n->expr.args[0]->lit.lblval; + assert(exprop(n) == Olit); + assert(n->expr.args[0]->type == Nlit); + assert(n->expr.args[0]->lit.littype == Llbl); + return n->expr.args[0]->lit.lblval; } static size_t did(Node *n) { - if (n->type == Ndecl) { - return n->decl.did; - } else if (n->type == Nexpr) { - assert(exprop(n) == Ovar); - return n->expr.did; - } - dump(n, stderr); - die("Can't get did"); - return 0; + if (n->type == Ndecl) { + return n->decl.did; + } + else if (n->type == Nexpr) { + assert(exprop(n) == Ovar); + return n->expr.did; + } + dump(n, stderr); + die("Can't get did"); + return 0; } /* Hashes a Ovar expr or an Ndecl */ ulong varhash(void *dcl) { - /* large-prime hash. meh. */ - return did(dcl) * 366787; + /* large-prime hash. meh. */ + return did(dcl) * 366787; } /* Checks if the did of two vars are equal */ -int vareq(void *a, void *b) -{ - return did(a) == did(b); -} +int vareq(void *a, void *b) { return did(a) == did(b); } diff --git a/parse/parse.h b/parse/parse.h index fcfb34f..ab71500 100644 --- a/parse/parse.h +++ b/parse/parse.h @@ -1,15 +1,15 @@ #ifdef __GNUC__ -# define FATAL __attribute__((noreturn)) +#define FATAL __attribute__((noreturn)) #else -# define FATAL +#define FATAL #endif #define Abiversion 8 -typedef uint8_t byte; -typedef unsigned int uint; -typedef unsigned long ulong; -typedef long long vlong; +typedef uint8_t byte; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef long long vlong; typedef unsigned long long uvlong; typedef struct Srcloc Srcloc; @@ -28,17 +28,17 @@ typedef struct Type Type; typedef struct Trait Trait; typedef enum { - OTmisc, - OTpre, - OTpost, - OTbin, - OTzarg, + OTmisc, + OTpre, + OTpost, + OTbin, + OTzarg, } Optype; typedef enum { #define O(op, pure, type, pretty) op, #include "ops.def" - Numops, + Numops, #undef O } Op; @@ -58,342 +58,344 @@ typedef enum { #define Ty(t, n, stk) t, #include "types.def" #undef Ty - Ntypes + Ntypes } Ty; typedef enum { #define Tc(c, n) c, #include "trait.def" #undef Tc - Ntraits + Ntraits } Tc; #define Zloc ((Srcloc){-1, 0}) struct Strbuf { - char *buf; - size_t sz; - size_t len; + char *buf; + size_t sz; + size_t len; }; struct Srcloc { - int line; - int file; + int line; + int file; }; struct Str { - size_t len; - char *buf; + size_t len; + char *buf; }; typedef enum { - Visintern, - Visexport, - Vishidden, - Visbuiltin, + Visintern, + Visexport, + Vishidden, + Visbuiltin, } Vis; typedef enum { - Dclconst = 1 << 0, - Dclextern = 1 << 1, + Dclconst = 1 << 0, + Dclextern = 1 << 1, } Dclflags; struct Bitset { - size_t nchunks; - size_t *chunks; + size_t nchunks; + size_t *chunks; }; struct Htab { - size_t nelt; - size_t ndead; - size_t sz; - ulong (*hash)(void *k); - int (*cmp)(void *a, void *b); - void **keys; - void **vals; - ulong *hashes; - char *dead; + size_t nelt; + size_t ndead; + size_t sz; + ulong (*hash)(void *k); + int (*cmp)(void *a, void *b); + void **keys; + void **vals; + ulong *hashes; + char *dead; }; struct Tok { - int type; - Srcloc loc; - char *id; - - /* values parsed out */ - vlong intval; - Ty inttype; /* for explicitly specified suffixes */ - double fltval; - uint32_t chrval; - Str strval; + int type; + Srcloc loc; + char *id; + + /* values parsed out */ + vlong intval; + Ty inttype; /* for explicitly specified suffixes */ + double fltval; + uint32_t chrval; + Str strval; }; struct Stab { - Stab *super; - char *name; - char isfunc; - - /* Contents of stab. - * types and values are in separate namespaces. */ - Htab *dcl; - Htab *env; /* the syms we close over, if we're a function */ - Htab *ty; /* types */ - Htab *tr; /* traits */ - Htab *uc; /* union constructors */ - Htab *impl; /* trait implementations: really a set of implemented traits. */ + Stab *super; + char *name; + char isfunc; + + /* Contents of stab. + * types and values are in separate namespaces. */ + Htab *dcl; + Htab *env; /* the syms we close over, if we're a function */ + Htab *ty; /* types */ + Htab *tr; /* traits */ + Htab *uc; /* union constructors */ + Htab *impl; /* trait implementations: really a set of implemented traits. */ }; struct Type { - Ty type; - int tid; - Srcloc loc; - Vis vis; - - int resolved; /* Have we resolved the subtypes? Prevents infinite recursion. */ - int fixed; /* Have we fixed the subtypes? Prevents infinite recursion. */ - - Bitset *traits; /* the type constraints matched on this type */ - Node **traitlist; /* The names of the constraints on the type. Used to fill the bitset */ - size_t ntraitlist; /* The length of the constraint list above */ - - Type **gparam; /* Tygeneric: type parameters that match the type args */ - size_t ngparam; /* Tygeneric: count of type parameters */ - Type **arg; /* Tyname: type arguments instantiated */ - size_t narg; /* Tyname: count of type arguments */ - Type **inst; /* Tyname: instances created */ - size_t ninst; /* Tyname: count of instances created */ - - Type **sub; /* sub-types; shared by all composite types */ - size_t nsub; /* For compound types */ - size_t nmemb; /* for aggregate types (struct, union) */ - union { - Node *name; /* Tyname: unresolved name. Tyalias: alias name */ - Node *asize; /* array size */ - char *pname; /* Typaram: name of type parameter */ - Node **sdecls; /* Tystruct: decls in struct */ - Ucon **udecls; /* Tyunion: decls in union */ - }; - - char issynth; /* Tyname: whether this is synthesized or not */ - char ishidden; /* Tyname: whether this is hidden or not */ - char ispkglocal; /* Tyname: whether this is package local or not */ - char isimport; /* Tyname: whether tyis type was imported. */ - char isreflect; /* Tyname: whether this type has reflection info */ + Ty type; + int tid; + Srcloc loc; + Vis vis; + + int resolved; /* Have we resolved the subtypes? Prevents infinite recursion. */ + int fixed; /* Have we fixed the subtypes? Prevents infinite recursion. */ + + Bitset *traits; /* the type constraints matched on this type */ + Node **traitlist; /* The names of the constraints on the type. Used to fill the bitset */ + size_t ntraitlist; /* The length of the constraint list above */ + + Type **gparam; /* Tygeneric: type parameters that match the type args */ + size_t ngparam; /* Tygeneric: count of type parameters */ + Type **arg; /* Tyname: type arguments instantiated */ + size_t narg; /* Tyname: count of type arguments */ + Type **inst; /* Tyname: instances created */ + size_t ninst; /* Tyname: count of instances created */ + + Type **sub; /* sub-types; shared by all composite types */ + size_t nsub; /* For compound types */ + size_t nmemb; /* for aggregate types (struct, union) */ + union { + Node *name; /* Tyname: unresolved name. Tyalias: alias name */ + Node *asize; /* array size */ + char *pname; /* Typaram: name of type parameter */ + Node **sdecls; /* Tystruct: decls in struct */ + Ucon **udecls; /* Tyunion: decls in union */ + }; + + char issynth; /* Tyname: whether this is synthesized or not */ + char ishidden; /* Tyname: whether this is hidden or not */ + char ispkglocal; /* Tyname: whether this is package local or not */ + char isimport; /* Tyname: whether tyis type was imported. */ + char isreflect; /* Tyname: whether this type has reflection info */ }; struct Ucon { - Srcloc loc; - size_t id; /* unique id */ - int synth; /* is it generated? */ - Node *name; /* ucon name */ - Type *utype; /* type of the union this is an element of */ - Type *etype; /* type for the element */ + Srcloc loc; + size_t id; /* unique id */ + int synth; /* is it generated? */ + Node *name; /* ucon name */ + Type *utype; /* type of the union this is an element of */ + Type *etype; /* type for the element */ }; struct Trait { - int uid; /* unique id */ - Srcloc loc; - Vis vis; - - Node *name; /* the name of the trait */ - Type *param; /* the type parameter */ - Node **memb; /* type must have these members */ - size_t nmemb; - Node **funcs; /* and declare these funcs */ - size_t nfuncs; - - char isproto; /* is it a prototype (for exporting purposes) */ - char ishidden; /* should user code be able to use this? */ + int uid; /* unique id */ + Srcloc loc; + Vis vis; + + Node *name; /* the name of the trait */ + Type *param; /* the type parameter */ + Node **memb; /* type must have these members */ + size_t nmemb; + Node **funcs; /* and declare these funcs */ + size_t nfuncs; + + char isproto; /* is it a prototype (for exporting purposes) */ + char ishidden; /* should user code be able to use this? */ }; struct Node { - Srcloc loc; - Ntype type; - int nid; - union { - struct { - size_t nfiles; /* file names for location mapping */ - char **files; - Node **uses; /* use files that we loaded */ - size_t nuses; - char **libdeps; /* library dependencies */ - size_t nlibdeps; - char **extlibs; /* non-myrddin libraries */ - size_t nextlibs; - Node **stmts; /* all top level statements */ - size_t nstmts; - Node **init; /* a list of all __init__ function names of our deps. NB, this is a Nname, not an Ndecl */ - size_t ninit; - Node *localinit; /* and the local one, if any */ - Stab *globls; /* global symtab */ - Htab *ns; /* namespaces */ - } file; - - struct { - Op op; - Type *type; - int isconst; - size_t did; /* for Ovar, we want a mapping to the decl id */ - size_t nargs; - Node *idx; /* used when this is in an indexed initializer */ - Node **args; - } expr; - - struct { - char *ns; - char *name; - } name; - - struct { - int islocal; - char *name; - } use; - - struct { - Littype littype; - Type *type; - size_t nelt; - union { - uvlong intval; - double fltval; - uint32_t chrval; - Str strval; - char *lblval; - int boolval; - Node *fnval; - }; - } lit; - - struct { - Node *init; - Node *cond; - Node *step; - Node *body; - Stab *scope; - } loopstmt; - - struct { - Node *elt; - Node *seq; - Node *body; - } iterstmt; - - struct { - Node *cond; - Node *iftrue; - Node *iffalse; - } ifstmt; - - struct { - Node *val; - size_t nmatches; - Node **matches; - } matchstmt; - - struct { - Node *pat; - Node *block; - } match; - - struct { - Stab *scope; - size_t nstmts; - Node **stmts; - } block; - - struct { - size_t did; - Node *name; - Type *type; - Node *init; - /* - If we have a link to a trait, we should only look it up - when specializing, but we should not create a new decl - node for it. That will be done when specializing the - impl. - */ - Trait *trait; - char vis; - - /* flags */ - char isglobl; - char isconst; - char isgeneric; - char isextern; - char ispkglocal; - char ishidden; - char isimport; - char isnoret; - char isexportinit; - char isinit; - } decl; - - struct { - long uid; - Node *name; - Type *elt; - Type *alt; - } uelt; - - struct { - Stab *scope; - Type *type; - size_t nargs; - Node **args; - Node *body; - } func; - - struct { - Node *name; - size_t traitid; - - Node **funcs; - size_t nfuncs; - Node **membs; - size_t nmembs; - } trait; - - struct { - Node *traitname; - Trait *trait; - Type *type; - Node **decls; - size_t ndecls; - Vis vis; - char isproto; - } impl; - }; + Srcloc loc; + Ntype type; + int nid; + union { + struct { + size_t nfiles; /* file names for location mapping */ + char **files; + Node **uses; /* use files that we loaded */ + size_t nuses; + char **libdeps; /* library dependencies */ + size_t nlibdeps; + char **extlibs; /* non-myrddin libraries */ + size_t nextlibs; + Node **stmts; /* all top level statements */ + size_t nstmts; + Node + **init; /* a list of all __init__ function names of our deps. NB, this + is a Nname, not an Ndecl */ + size_t ninit; + Node *localinit; /* and the local one, if any */ + Stab *globls; /* global symtab */ + Htab *ns; /* namespaces */ + } file; + + struct { + Op op; + Type *type; + int isconst; + size_t did; /* for Ovar, we want a mapping to the decl id */ + size_t nargs; + Node *idx; /* used when this is in an indexed initializer */ + Node **args; + } expr; + + struct { + char *ns; + char *name; + } name; + + struct { + int islocal; + char *name; + } use; + + struct { + Littype littype; + Type *type; + size_t nelt; + union { + uvlong intval; + double fltval; + uint32_t chrval; + Str strval; + char *lblval; + int boolval; + Node *fnval; + }; + } lit; + + struct { + Node *init; + Node *cond; + Node *step; + Node *body; + Stab *scope; + } loopstmt; + + struct { + Node *elt; + Node *seq; + Node *body; + } iterstmt; + + struct { + Node *cond; + Node *iftrue; + Node *iffalse; + } ifstmt; + + struct { + Node *val; + size_t nmatches; + Node **matches; + } matchstmt; + + struct { + Node *pat; + Node *block; + } match; + + struct { + Stab *scope; + size_t nstmts; + Node **stmts; + } block; + + struct { + size_t did; + Node *name; + Type *type; + Node *init; + /* + If we have a link to a trait, we should only look it up + when specializing, but we should not create a new decl + node for it. That will be done when specializing the + impl. + */ + Trait *trait; + char vis; + + /* flags */ + char isglobl; + char isconst; + char isgeneric; + char isextern; + char ispkglocal; + char ishidden; + char isimport; + char isnoret; + char isexportinit; + char isinit; + } decl; + + struct { + long uid; + Node *name; + Type *elt; + Type *alt; + } uelt; + + struct { + Stab *scope; + Type *type; + size_t nargs; + Node **args; + Node *body; + } func; + + struct { + Node *name; + size_t traitid; + + Node **funcs; + size_t nfuncs; + Node **membs; + size_t nmembs; + } trait; + + struct { + Node *traitname; + Trait *trait; + Type *type; + Node **decls; + size_t ndecls; + Vis vis; + char isproto; + } impl; + }; }; struct Optctx { - /* public exports */ - char *optarg; - char **args; - size_t nargs; - - /* internal state */ - char *optstr; - char **optargs; - size_t noptargs; - size_t argidx; - int optdone; /* seen -- */ - int finished; - char *curarg; + /* public exports */ + char *optarg; + char **args; + size_t nargs; + + /* internal state */ + char *optstr; + char **optargs; + size_t noptargs; + size_t argidx; + int optdone; /* seen -- */ + int finished; + char *curarg; }; /* globals */ extern Srcloc curloc; extern char *filename; -extern Tok *curtok; /* the last token we tokenized */ -extern Node *file; /* the current file we're compiling */ -extern Type **tytab; /* type -> type map used by inference. size maintained by type creation code */ +extern Tok *curtok; /* the last token we tokenized */ +extern Node *file; /* the current file we're compiling */ +extern Type **tytab; /* type -> type map used by inference. size maintained by type creation code */ extern Type **types; extern size_t ntypes; -extern Trait **traittab; /* int -> trait map */ +extern Trait **traittab; /* int -> trait map */ extern size_t ntraittab; -extern Node **decls; /* decl id -> decl map */ +extern Node **decls; /* decl id -> decl map */ extern size_t nnodes; -extern Node **nodes; /* node id -> node map */ +extern Node **nodes; /* node id -> node map */ extern size_t ndecls; extern Node **exportimpls; extern size_t nexportimpls; @@ -409,7 +411,7 @@ extern char *tidstr[]; /* data structures */ Bitset *mkbs(void); -void bsfree(Bitset *bs); +void bsfree(Bitset *bs); Bitset *bsdup(Bitset *bs); Bitset *bsclear(Bitset *bs); void delbs(Bitset *bs); @@ -418,18 +420,19 @@ void bsdel(Bitset *bs, size_t elt); void bsunion(Bitset *a, Bitset *b); void bsintersect(Bitset *a, Bitset *b); void bsdiff(Bitset *a, Bitset *b); -int bseq(Bitset *a, Bitset *b); -int bsissubset(Bitset *set, Bitset *sub); -int bsisempty(Bitset *set); -int bsiter(Bitset *bs, size_t *elt); +int bseq(Bitset *a, Bitset *b); +int bsissubset(Bitset *set, Bitset *sub); +int bsisempty(Bitset *set); +int bsiter(Bitset *bs, size_t *elt); size_t bsmax(Bitset *bs); size_t bscount(Bitset *bs); /* inline for speed */ static inline int bshas(Bitset *bs, size_t elt) { - if (elt >= bs->nchunks*8*sizeof(size_t)) - return 0; - return (bs->chunks[elt/(8*sizeof(size_t))] & (1ULL << (elt % (8*sizeof(size_t))))) != 0; + if (elt >= bs->nchunks * 8 * sizeof(size_t)) + return 0; + return (bs->chunks[elt / (8 * sizeof(size_t))] & (1ULL << (elt % (8 * sizeof(size_t))))) != + 0; } Htab *mkht(ulong (*hash)(void *key), int (*cmp)(void *k1, void *k2)); @@ -519,15 +522,16 @@ Type *mktytuple(Srcloc l, Type **sub, size_t nsub); Type *mktyfunc(Srcloc l, Node **args, size_t nargs, Type *ret); Type *mktystruct(Srcloc l, Node **decls, size_t ndecls); Type *mktyunion(Srcloc l, Ucon **decls, size_t ndecls); -Trait *mktrait(Srcloc l, Node *name, Type *param, Node **memb, size_t nmemb, Node **funcs, size_t nfuncs, int isproto); +Trait *mktrait(Srcloc l, Node *name, Type *param, Node **memb, size_t nmemb, Node **funcs, + size_t nfuncs, int isproto); Type *mktylike(Srcloc l, Ty ty); /* constrains tyvar t like it was builtin ty */ Ucon *finducon(Type *t, Node *name); -int isstacktype(Type *t); -int istysigned(Type *t); -int istyunsigned(Type *t); -int istyfloat(Type *t); -int istyprimitive(Type *t); -int hasparams(Type *t); +int isstacktype(Type *t); +int istysigned(Type *t); +int istyunsigned(Type *t); +int istyfloat(Type *t); +int istyprimitive(Type *t); +int hasparams(Type *t); /* type manipulation */ Type *tybase(Type *t); @@ -580,7 +584,7 @@ uint64_t arraysz(Node *sz); char *namestr(Node *name); char *lblstr(Node *n); char *declname(Node *n); -Type *decltype(Node *n); +Type *decltype(Node * n); Type *exprtype(Node *n); Type *nodetype(Node *n); void addstmt(Node *file, Node *stmt); @@ -597,7 +601,7 @@ Node *genericname(Node *n, Type *t); void geninit(Node *file); /* usefiles */ -int loaduse(char *path, FILE *f, Stab *into, Vis vis); +int loaduse(char *path, FILE *f, Stab *into, Vis vis); void readuse(Node *use, Stab *into, Vis vis); void writeuse(FILE *fd, Node *file); void tagexports(Node *file, int hidelocal); @@ -618,7 +622,8 @@ int optnext(Optctx *c); int optdone(Optctx *c); /* convenience funcs */ -void lappend(void *l, size_t *len, void *n); /* hack; nl is void* b/c void*** is incompatible with T*** */ +/* hack; nl is void* b/c void*** is incompatible with T*** */ +void lappend( void *l, size_t *len, void *n); void lcat(void *dst, size_t *ndst, void *src, size_t nsrc); void linsert(void *l, size_t *len, size_t idx, void *n); void *lpop(void *l, size_t *len); @@ -630,8 +635,8 @@ void be64(vlong v, byte buf[8]); vlong host64(byte buf[8]); void be32(long v, byte buf[4]); long host32(byte buf[4]); -static inline intptr_t ptoi(void *p) {return (intptr_t)p;} -static inline void* itop(intptr_t i) {return (void*)i;} +static inline intptr_t ptoi(void *p) { return (intptr_t)p; } +static inline void *itop(intptr_t i) { return (void *)i; } void wrbuf(FILE *fd, void *buf, size_t sz); void rdbuf(FILE *fd, void *buf, size_t sz); @@ -665,7 +670,7 @@ char *swapsuffix(char *buf, size_t sz, char *s, char *suf, char *swap); /* indented printf */ void indentf(int depth, char *fmt, ...); void findentf(FILE *fd, int depth, char *fmt, ...); -void vfindentf(FILE *fd, int depth, char *fmt, va_list ap); +void vfindentf(FILE *fd, int depth, char *fmt, va_list ap); /* Options to control the compilation */ extern char debugopt[128]; diff --git a/parse/specialize.c b/parse/specialize.c index de884de..1414119 100644 --- a/parse/specialize.c +++ b/parse/specialize.c @@ -16,11 +16,11 @@ static Node *specializenode(Node *g, Htab *tsmap); void addtraits(Type *t, Bitset *traits) { - size_t b; + size_t b; - if (traits) - for (b = 0; bsiter(traits, &b); b++) - settrait(t, traittab[b]); + if (traits) + for (b = 0; bsiter(traits, &b); b++) + settrait(t, traittab[b]); } /* @@ -34,78 +34,80 @@ void addtraits(Type *t, Bitset *traits) * against */ Type *tyspecialize(Type *t, Htab *tsmap, Htab *delayed) { - Type *ret, *tmp, **arg; - size_t i, narg; - - t = tysearch(t); - if (hthas(tsmap, t)) - return htget(tsmap, t); - arg = NULL; - narg = 0; - switch (t->type) { - case Typaram: - ret = mktyvar(t->loc); - addtraits(ret, t->traits); - htput(tsmap, t, ret); - break; - case Tygeneric: - ret = mktyname(t->loc, t->name, tyspecialize(t->sub[0], tsmap, delayed)); - ret->issynth = 1; - htput(tsmap, t, ret); - for (i = 0; i < t->ngparam; i++) - lappend(&ret->arg, &ret->narg, tyspecialize(t->gparam[i], tsmap, delayed)); - break; - case Tyname: - if (!hasparams(t)) - return t; - for (i = 0; i < t->narg; i++) - lappend(&arg, &narg, tyspecialize(t->arg[i], tsmap, delayed)); - ret = mktyname(t->loc, t->name, tyspecialize(t->sub[0], tsmap, delayed)); - ret->arg = arg; - ret->narg = narg; - break; - case Tystruct: - ret = tydup(t); - htput(tsmap, t, ret); - pushstab(NULL); - for (i = 0; i < t->nmemb; i++) - ret->sdecls[i] = specializenode(t->sdecls[i], tsmap); - popstab(); - break; - case Tyunion: - ret = tydup(t); - htput(tsmap, t, ret); - for (i = 0; i < t->nmemb; i++) { - tmp = NULL; - if (ret->udecls[i]->etype) - tmp = tyspecialize(t->udecls[i]->etype, tsmap, delayed); - ret->udecls[i] = mkucon(t->loc, t->udecls[i]->name, ret, tmp); - ret->udecls[i]->utype = ret; - ret->udecls[i]->id = i; - ret->udecls[i]->synth = 1; - } - break; - case Tyvar: - if (delayed && hthas(delayed, t)) { - ret = tydup(t); - tmp = htget(delayed, t); - htput(delayed, ret, tyspecialize(tmp, tsmap, delayed)); - } else { - ret = t; - } - break; - default: - if (t->nsub > 0) { - ret = tydup(t); - htput(tsmap, t, ret); - for (i = 0; i < t->nsub; i++) - ret->sub[i] = tyspecialize(t->sub[i], tsmap, delayed); - } else { - ret = t; - } - break; - } - return ret; + Type *ret, *tmp, **arg; + size_t i, narg; + + t = tysearch(t); + if (hthas(tsmap, t)) + return htget(tsmap, t); + arg = NULL; + narg = 0; + switch (t->type) { + case Typaram: + ret = mktyvar(t->loc); + addtraits(ret, t->traits); + htput(tsmap, t, ret); + break; + case Tygeneric: + ret = mktyname(t->loc, t->name, tyspecialize(t->sub[0], tsmap, delayed)); + ret->issynth = 1; + htput(tsmap, t, ret); + for (i = 0; i < t->ngparam; i++) + lappend(&ret->arg, &ret->narg, tyspecialize(t->gparam[i], tsmap, delayed)); + break; + case Tyname: + if (!hasparams(t)) + return t; + for (i = 0; i < t->narg; i++) + lappend(&arg, &narg, tyspecialize(t->arg[i], tsmap, delayed)); + ret = mktyname(t->loc, t->name, tyspecialize(t->sub[0], tsmap, delayed)); + ret->arg = arg; + ret->narg = narg; + break; + case Tystruct: + ret = tydup(t); + htput(tsmap, t, ret); + pushstab(NULL); + for (i = 0; i < t->nmemb; i++) + ret->sdecls[i] = specializenode(t->sdecls[i], tsmap); + popstab(); + break; + case Tyunion: + ret = tydup(t); + htput(tsmap, t, ret); + for (i = 0; i < t->nmemb; i++) { + tmp = NULL; + if (ret->udecls[i]->etype) + tmp = tyspecialize(t->udecls[i]->etype, tsmap, delayed); + ret->udecls[i] = mkucon(t->loc, t->udecls[i]->name, ret, tmp); + ret->udecls[i]->utype = ret; + ret->udecls[i]->id = i; + ret->udecls[i]->synth = 1; + } + break; + case Tyvar: + if (delayed && hthas(delayed, t)) { + ret = tydup(t); + tmp = htget(delayed, t); + htput(delayed, ret, tyspecialize(tmp, tsmap, delayed)); + } + else { + ret = t; + } + break; + default: + if (t->nsub > 0) { + ret = tydup(t); + htput(tsmap, t, ret); + for (i = 0; i < t->nsub; i++) + ret->sub[i] = tyspecialize(t->sub[i], tsmap, delayed); + } + else { + ret = t; + } + break; + } + return ret; } /* Checks if the type 't' is generic, and if it is @@ -113,33 +115,33 @@ Type *tyspecialize(Type *t, Htab *tsmap, Htab *delayed) * so we don't gratuitously duplicate types */ static Type *tysubst(Type *t, Htab *tsmap) { - if (hasparams(t)) - return tyspecialize(t, tsmap, NULL); - else - return t; + if (hasparams(t)) + return tyspecialize(t, tsmap, NULL); + else + return t; } -/* +/* * Fills the substitution map with a mapping from * the type parameter 'from' to it's substititon 'to' */ static void fillsubst(Htab *tsmap, Type *to, Type *from) { - size_t i; - - if (from->type == Typaram) { - if (debugopt['S']) - printf("mapping %s => %s\n", tystr(from), tystr(to)); - htput(tsmap, from, to); - return; - } - assert(to->nsub == from->nsub); - for (i = 0; i < to->nsub; i++) - fillsubst(tsmap, to->sub[i], from->sub[i]); - if (to->type == Tyname && to->narg > 0) { - for (i = 0; i < to->narg; i++) - fillsubst(tsmap, to->arg[i], from->arg[i]); - } + size_t i; + + if (from->type == Typaram) { + if (debugopt['S']) + printf("mapping %s => %s\n", tystr(from), tystr(to)); + htput(tsmap, from, to); + return; + } + assert(to->nsub == from->nsub); + for (i = 0; i < to->nsub; i++) + fillsubst(tsmap, to->sub[i], from->sub[i]); + if (to->type == Tyname && to->narg > 0) { + for (i = 0; i < to->narg; i++) + fillsubst(tsmap, to->arg[i], from->arg[i]); + } } /* @@ -148,98 +150,94 @@ static void fillsubst(Htab *tsmap, Type *to, Type *from) */ static void fixup(Node *n) { - size_t i; - Node *d; - Stab *ns; - - if (!n) - return; - switch (n->type) { - case Nfile: - case Nuse: - die("Node %s not allowed here\n", nodestr[n->type]); - break; - case Nexpr: - fixup(n->expr.idx); - for (i = 0; i < n->expr.nargs; i++) - fixup(n->expr.args[i]); - if (n->expr.op == Ovar) { - ns = curstab(); - if (n->expr.args[0]->name.ns) - ns = getns(file, n->expr.args[0]->name.ns); - if (!ns) - fatal(n, "No namespace %s\n", n->expr.args[0]->name.ns); - d = getdcl(ns, n->expr.args[0]); - if (!d) - die("Missing decl %s", namestr(n->expr.args[0])); - if (d->decl.isgeneric) - d = specializedcl(d, n->expr.type, &n->expr.args[0]); - n->expr.did = d->decl.did; - } - break; - case Nlit: - switch (n->lit.littype) { - case Lfunc: fixup(n->lit.fnval); break; - case Lchr: case Lint: case Lflt: - case Lstr: case Llbl: case Lbool: - break; - } - break; - case Nifstmt: - fixup(n->ifstmt.cond); - fixup(n->ifstmt.iftrue); - fixup(n->ifstmt.iffalse); - break; - case Nloopstmt: - pushstab(n->loopstmt.scope); - fixup(n->loopstmt.init); - fixup(n->loopstmt.cond); - fixup(n->loopstmt.step); - fixup(n->loopstmt.body); - popstab(); - break; - case Niterstmt: - pushstab(n->iterstmt.body->block.scope); - fixup(n->iterstmt.elt); - popstab(); - fixup(n->iterstmt.seq); - fixup(n->iterstmt.body); - break; - case Nmatchstmt: - fixup(n->matchstmt.val); - for (i = 0; i < n->matchstmt.nmatches; i++) - fixup(n->matchstmt.matches[i]); - break; - case Nmatch: - /* patterns are evaluated in their block's scope */ - pushstab(n->match.block->block.scope); - fixup(n->match.pat); - popstab(); - fixup(n->match.block); - break; - case Nblock: - pushstab(n->block.scope); - for (i = 0; i < n->block.nstmts; i++) - fixup(n->block.stmts[i]); - popstab(); - break; - case Ndecl: - fixup(n->decl.init); - break; - case Nfunc: - pushstab(n->func.scope); - fixup(n->func.body); - popstab(); - break; - case Nnone: case Nname: - break; - case Nimpl: - die("trait/impl not implemented"); - break; - } + size_t i; + Node *d; + Stab *ns; + + if (!n) + return; + switch (n->type) { + case Nfile: + case Nuse: die("Node %s not allowed here\n", nodestr[n->type]); break; + case Nexpr: + fixup(n->expr.idx); + for (i = 0; i < n->expr.nargs; i++) + fixup(n->expr.args[i]); + if (n->expr.op == Ovar) { + ns = curstab(); + if (n->expr.args[0]->name.ns) + ns = getns(file, n->expr.args[0]->name.ns); + if (!ns) + fatal(n, "No namespace %s\n", n->expr.args[0]->name.ns); + d = getdcl(ns, n->expr.args[0]); + if (!d) + die("Missing decl %s", namestr(n->expr.args[0])); + if (d->decl.isgeneric) + d = specializedcl(d, n->expr.type, &n->expr.args[0]); + n->expr.did = d->decl.did; + } + break; + case Nlit: + switch (n->lit.littype) { + case Lfunc: fixup(n->lit.fnval); break; + case Lchr: + case Lint: + case Lflt: + case Lstr: + case Llbl: + case Lbool: break; + } + break; + case Nifstmt: + fixup(n->ifstmt.cond); + fixup(n->ifstmt.iftrue); + fixup(n->ifstmt.iffalse); + break; + case Nloopstmt: + pushstab(n->loopstmt.scope); + fixup(n->loopstmt.init); + fixup(n->loopstmt.cond); + fixup(n->loopstmt.step); + fixup(n->loopstmt.body); + popstab(); + break; + case Niterstmt: + pushstab(n->iterstmt.body->block.scope); + fixup(n->iterstmt.elt); + popstab(); + fixup(n->iterstmt.seq); + fixup(n->iterstmt.body); + break; + case Nmatchstmt: + fixup(n->matchstmt.val); + for (i = 0; i < n->matchstmt.nmatches; i++) + fixup(n->matchstmt.matches[i]); + break; + case Nmatch: + /* patterns are evaluated in their block's scope */ + pushstab(n->match.block->block.scope); + fixup(n->match.pat); + popstab(); + fixup(n->match.block); + break; + case Nblock: + pushstab(n->block.scope); + for (i = 0; i < n->block.nstmts; i++) + fixup(n->block.stmts[i]); + popstab(); + break; + case Ndecl: fixup(n->decl.init); break; + case Nfunc: + pushstab(n->func.scope); + fixup(n->func.body); + popstab(); + break; + case Nnone: + case Nname: break; + case Nimpl: die("trait/impl not implemented"); break; + } } - /* * Duplicates a node, replacing all things that * need to be specialized to make it concrete @@ -247,142 +245,141 @@ static void fixup(Node *n) */ static Node *specializenode(Node *n, Htab *tsmap) { - Node *r; - size_t i; - - if (!n) - return NULL; - r = mknode(n->loc, n->type); - switch (n->type) { - case Nfile: - case Nuse: - die("Node %s not allowed here\n", nodestr[n->type]); - break; - case Nexpr: - r->expr.op = n->expr.op; - r->expr.type = tysubst(n->expr.type, tsmap); - r->expr.isconst = n->expr.isconst; - r->expr.nargs = n->expr.nargs; - r->expr.idx = specializenode(n->expr.idx, tsmap); - r->expr.args = xalloc(n->expr.nargs * sizeof(Node*)); - for (i = 0; i < n->expr.nargs; i++) - r->expr.args[i] = specializenode(n->expr.args[i], tsmap); - break; - case Nname: - if (n->name.ns) - r->name.ns = strdup(n->name.ns); - r->name.name = strdup(n->name.name); - break; - case Nlit: - r->lit.littype = n->lit.littype; - r->lit.type = tysubst(n->expr.type, tsmap); - switch (n->lit.littype) { - case Lchr: r->lit.chrval = n->lit.chrval; break; - case Lint: r->lit.intval = n->lit.intval; break; - case Lflt: r->lit.fltval = n->lit.fltval; break; - case Lstr: r->lit.strval = n->lit.strval; break; - case Llbl: r->lit.lblval = n->lit.lblval; break; - case Lbool: r->lit.boolval = n->lit.boolval; break; - case Lfunc: r->lit.fnval = specializenode(n->lit.fnval, tsmap); break; - } - break; - case Nifstmt: - r->ifstmt.cond = specializenode(n->ifstmt.cond, tsmap); - r->ifstmt.iftrue = specializenode(n->ifstmt.iftrue, tsmap); - r->ifstmt.iffalse = specializenode(n->ifstmt.iffalse, tsmap); - break; - case Nloopstmt: - r->loopstmt.scope = mkstab(0); - r->loopstmt.scope->super = curstab(); - pushstab(r->loopstmt.scope); - r->loopstmt.init = specializenode(n->loopstmt.init, tsmap); - r->loopstmt.cond = specializenode(n->loopstmt.cond, tsmap); - r->loopstmt.step = specializenode(n->loopstmt.step, tsmap); - r->loopstmt.body = specializenode(n->loopstmt.body, tsmap); - popstab(); - break; - case Niterstmt: - r->iterstmt.elt = specializenode(n->iterstmt.elt, tsmap); - r->iterstmt.seq = specializenode(n->iterstmt.seq, tsmap); - r->iterstmt.body = specializenode(n->iterstmt.body, tsmap); - break; - case Nmatchstmt: - r->matchstmt.val = specializenode(n->matchstmt.val, tsmap); - r->matchstmt.nmatches = n->matchstmt.nmatches; - r->matchstmt.matches = xalloc(n->matchstmt.nmatches * sizeof(Node*)); - for (i = 0; i < n->matchstmt.nmatches; i++) - r->matchstmt.matches[i] = specializenode(n->matchstmt.matches[i], tsmap); - break; - case Nmatch: - r->match.pat = specializenode(n->match.pat, tsmap); - r->match.block = specializenode(n->match.block, tsmap); - break; - case Nblock: - r->block.scope = mkstab(0); - r->block.scope->super = curstab(); - pushstab(r->block.scope); - r->block.nstmts = n->block.nstmts; - r->block.stmts = xalloc(sizeof(Node *)*n->block.nstmts); - for (i = 0; i < n->block.nstmts; i++) - r->block.stmts[i] = specializenode(n->block.stmts[i], tsmap); - popstab(); - break; - case Ndecl: - r->decl.did = ndecls; - /* sym */ - r->decl.name = specializenode(n->decl.name, tsmap); - r->decl.type = tysubst(n->decl.type, tsmap); - - /* symflags */ - r->decl.isconst = n->decl.isconst; - r->decl.isgeneric = n->decl.isgeneric; - r->decl.isextern = n->decl.isextern; - r->decl.isglobl = n->decl.isglobl; - if (curstab()) - putdcl(curstab(), r); - - /* init */ - r->decl.init = specializenode(n->decl.init, tsmap); - lappend(&decls, &ndecls, r); - break; - case Nfunc: - r->func.scope = mkstab(0); - r->func.scope->super = curstab(); - pushstab(r->func.scope); - r->func.type = tysubst(n->func.type, tsmap); - r->func.nargs = n->func.nargs; - r->func.args = xalloc(sizeof(Node *)*n->func.nargs); - for (i = 0; i < n->func.nargs; i++) - r->func.args[i] = specializenode(n->func.args[i], tsmap); - r->func.body = specializenode(n->func.body, tsmap); - popstab(); - break; - case Nimpl: - die("trait/impl not implemented"); - case Nnone: - die("Nnone should not be seen as node type!"); - break; - } - return r; + Node *r; + size_t i; + + if (!n) + return NULL; + r = mknode(n->loc, n->type); + switch (n->type) { + case Nfile: + case Nuse: die("Node %s not allowed here\n", nodestr[n->type]); break; + case Nexpr: + r->expr.op = n->expr.op; + r->expr.type = tysubst(n->expr.type, tsmap); + r->expr.isconst = n->expr.isconst; + r->expr.nargs = n->expr.nargs; + r->expr.idx = specializenode(n->expr.idx, tsmap); + r->expr.args = xalloc(n->expr.nargs * sizeof(Node *)); + for (i = 0; i < n->expr.nargs; i++) + r->expr.args[i] = specializenode(n->expr.args[i], tsmap); + break; + case Nname: + if (n->name.ns) + r->name.ns = strdup(n->name.ns); + r->name.name = strdup(n->name.name); + break; + case Nlit: + r->lit.littype = n->lit.littype; + r->lit.type = tysubst(n->expr.type, tsmap); + switch (n->lit.littype) { + case Lchr: r->lit.chrval = n->lit.chrval; break; + case Lint: r->lit.intval = n->lit.intval; break; + case Lflt: r->lit.fltval = n->lit.fltval; break; + case Lstr: r->lit.strval = n->lit.strval; break; + case Llbl: r->lit.lblval = n->lit.lblval; break; + case Lbool: r->lit.boolval = n->lit.boolval; break; + case Lfunc: r->lit.fnval = specializenode(n->lit.fnval, tsmap); break; + } + break; + case Nifstmt: + r->ifstmt.cond = specializenode(n->ifstmt.cond, tsmap); + r->ifstmt.iftrue = specializenode(n->ifstmt.iftrue, tsmap); + r->ifstmt.iffalse = specializenode(n->ifstmt.iffalse, tsmap); + break; + case Nloopstmt: + r->loopstmt.scope = mkstab(0); + r->loopstmt.scope->super = curstab(); + pushstab(r->loopstmt.scope); + r->loopstmt.init = specializenode(n->loopstmt.init, tsmap); + r->loopstmt.cond = specializenode(n->loopstmt.cond, tsmap); + r->loopstmt.step = specializenode(n->loopstmt.step, tsmap); + r->loopstmt.body = specializenode(n->loopstmt.body, tsmap); + popstab(); + break; + case Niterstmt: + r->iterstmt.elt = specializenode(n->iterstmt.elt, tsmap); + r->iterstmt.seq = specializenode(n->iterstmt.seq, tsmap); + r->iterstmt.body = specializenode(n->iterstmt.body, tsmap); + break; + case Nmatchstmt: + r->matchstmt.val = specializenode(n->matchstmt.val, tsmap); + r->matchstmt.nmatches = n->matchstmt.nmatches; + r->matchstmt.matches = xalloc(n->matchstmt.nmatches * sizeof(Node *)); + for (i = 0; i < n->matchstmt.nmatches; i++) + r->matchstmt.matches[i] = specializenode(n->matchstmt.matches[i], tsmap); + break; + case Nmatch: + r->match.pat = specializenode(n->match.pat, tsmap); + r->match.block = specializenode(n->match.block, tsmap); + break; + case Nblock: + r->block.scope = mkstab(0); + r->block.scope->super = curstab(); + pushstab(r->block.scope); + r->block.nstmts = n->block.nstmts; + r->block.stmts = xalloc(sizeof(Node *) * n->block.nstmts); + for (i = 0; i < n->block.nstmts; i++) + r->block.stmts[i] = specializenode(n->block.stmts[i], tsmap); + popstab(); + break; + case Ndecl: + r->decl.did = ndecls; + /* sym */ + r->decl.name = specializenode(n->decl.name, tsmap); + r->decl.type = tysubst(n->decl.type, tsmap); + + /* symflags */ + r->decl.isconst = n->decl.isconst; + r->decl.isgeneric = n->decl.isgeneric; + r->decl.isextern = n->decl.isextern; + r->decl.isglobl = n->decl.isglobl; + if (curstab()) + putdcl(curstab(), r); + + /* init */ + r->decl.init = specializenode(n->decl.init, tsmap); + lappend(&decls, &ndecls, r); + break; + case Nfunc: + r->func.scope = mkstab(0); + r->func.scope->super = curstab(); + pushstab(r->func.scope); + r->func.type = tysubst(n->func.type, tsmap); + r->func.nargs = n->func.nargs; + r->func.args = xalloc(sizeof(Node *) * n->func.nargs); + for (i = 0; i < n->func.nargs; i++) + r->func.args[i] = specializenode(n->func.args[i], tsmap); + r->func.body = specializenode(n->func.body, tsmap); + popstab(); + break; + case Nimpl: + die("trait/impl not implemented"); + break; + case Nnone: + die("Nnone should not be seen as node type!"); + break; + } + return r; } Node *genericname(Node *n, Type *t) { - char buf[1024]; - char *p; - char *end; - Node *name; - - if (!n->decl.isgeneric) - return n->decl.name; - p = buf; - end = buf + sizeof buf; - p += bprintf(p, end - p, "%s", n->decl.name->name.name); - p += bprintf(p, end - p, "$"); - p += tyidfmt(p, end - p, t); - name = mkname(n->loc, buf); - if (n->decl.name->name.ns) - setns(name, n->decl.name->name.ns); - return name; + char buf[1024]; + char *p; + char *end; + Node *name; + + if (!n->decl.isgeneric) + return n->decl.name; + p = buf; + end = buf + sizeof buf; + p += bprintf(p, end - p, "%s", n->decl.name->name.name); + p += bprintf(p, end - p, "$"); + p += tyidfmt(p, end - p, t); + name = mkname(n->loc, buf); + if (n->decl.name->name.ns) + setns(name, n->decl.name->name.ns); + return name; } /* @@ -392,53 +389,54 @@ Node *genericname(Node *n, Type *t) */ Node *specializedcl(Node *g, Type *to, Node **name) { - extern int stabstkoff; - Node *d, *n; - Htab *tsmap; - Stab *st; - - assert(g->type == Ndecl); - assert(g->decl.isgeneric); - - n = genericname(g, to); - *name = n; - if (n->name.ns) - st = getns(file, n->name.ns); - else - st = file->file.globls; - if (!st) - fatal(n, "Can't find symbol table for %s.%s", n->name.ns, n->name.name); - d = getdcl(st, n); - if (debugopt['S']) - printf("depth[%d] specializing [%d]%s => %s\n", stabstkoff, g->loc.line, namestr(g->decl.name), namestr(n)); - if (d) - return d; - if (g->decl.trait) { - printf("%s\n", namestr(n)); - fatal(g, "No trait implemented for for %s:%s", namestr(g->decl.name), tystr(to)); - } - /* namespaced names need to be looked up in their correct - * context. */ - if (n->name.ns) - pushstab(st); - - /* specialize */ - tsmap = mkht(tyhash, tyeq); - fillsubst(tsmap, to, g->decl.type); - - d = mkdecl(g->loc, n, tysubst(g->decl.type, tsmap)); - d->decl.isconst = g->decl.isconst; - d->decl.isextern = g->decl.isextern; - d->decl.isglobl = g->decl.isglobl; - d->decl.init = specializenode(g->decl.init, tsmap); - putdcl(st, d); - - fixup(d); - - lappend(&file->file.stmts, &file->file.nstmts, d); - if (d->decl.name->name.ns) - popstab(); - return d; + extern int stabstkoff; + Node *d, *n; + Htab *tsmap; + Stab *st; + + assert(g->type == Ndecl); + assert(g->decl.isgeneric); + + n = genericname(g, to); + *name = n; + if (n->name.ns) + st = getns(file, n->name.ns); + else + st = file->file.globls; + if (!st) + fatal(n, "Can't find symbol table for %s.%s", n->name.ns, n->name.name); + d = getdcl(st, n); + if (debugopt['S']) + printf("depth[%d] specializing [%d]%s => %s\n", stabstkoff, g->loc.line, + namestr(g->decl.name), namestr(n)); + if (d) + return d; + if (g->decl.trait) { + printf("%s\n", namestr(n)); + fatal(g, "No trait implemented for for %s:%s", namestr(g->decl.name), tystr(to)); + } + /* namespaced names need to be looked up in their correct + * context. */ + if (n->name.ns) + pushstab(st); + + /* specialize */ + tsmap = mkht(tyhash, tyeq); + fillsubst(tsmap, to, g->decl.type); + + d = mkdecl(g->loc, n, tysubst(g->decl.type, tsmap)); + d->decl.isconst = g->decl.isconst; + d->decl.isextern = g->decl.isextern; + d->decl.isglobl = g->decl.isglobl; + d->decl.init = specializenode(g->decl.init, tsmap); + putdcl(st, d); + + fixup(d); + + lappend(&file->file.stmts, &file->file.nstmts, d); + if (d->decl.name->name.ns) + popstab(); + return d; } /* @@ -455,65 +453,65 @@ Node *specializedcl(Node *g, Type *to, Node **name) */ static Node *initdecl(Node *file, Node *name, Type *tyvoidfn) { - Node *dcl; - - dcl = getdcl(file->file.globls, name); - if (!dcl) { - dcl = mkdecl(Zloc, name, tyvoidfn); - dcl->decl.isconst = 1; - dcl->decl.isglobl = 1; - dcl->decl.isinit = 1; - dcl->decl.isextern = 1; - dcl->decl.ishidden = 1; - putdcl(file->file.globls, dcl); - } - return dcl; + Node *dcl; + + dcl = getdcl(file->file.globls, name); + if (!dcl) { + dcl = mkdecl(Zloc, name, tyvoidfn); + dcl->decl.isconst = 1; + dcl->decl.isglobl = 1; + dcl->decl.isinit = 1; + dcl->decl.isextern = 1; + dcl->decl.ishidden = 1; + putdcl(file->file.globls, dcl); + } + return dcl; } static void callinit(Node *block, Node *init, Type *tyvoid, Type *tyvoidfn) { - Node *call, *var; + Node *call, *var; - var = mkexpr(Zloc, Ovar, init->decl.name, NULL); - call = mkexpr(Zloc, Ocall, var, NULL); + var = mkexpr(Zloc, Ovar, init->decl.name, NULL); + call = mkexpr(Zloc, Ocall, var, NULL); - var->expr.type = tyvoidfn; - call->expr.type = tyvoid; - var->expr.did = init->decl.did; - var->expr.isconst = 1; - lappend(&block->block.stmts, &block->block.nstmts, call); + var->expr.type = tyvoidfn; + call->expr.type = tyvoid; + var->expr.did = init->decl.did; + var->expr.isconst = 1; + lappend(&block->block.stmts, &block->block.nstmts, call); } void geninit(Node *file) { - Node *name, *decl, *func, *block, *init; - Type *tyvoid, *tyvoidfn; - size_t i; - - name = mkname(Zloc, "__init__"); - decl = mkdecl(Zloc, name, mktyvar(Zloc)); - block = mkblock(Zloc, mkstab(0)); - block->block.scope->super = file->file.globls; - tyvoid = mktype(Zloc, Tyvoid); - tyvoidfn = mktyfunc(Zloc, NULL, 0, tyvoid); - - for (i = 0; i < file->file.ninit; i++) { - init = initdecl(file, file->file.init[i], tyvoidfn); - callinit(block, init, tyvoid, tyvoidfn); - } - if (file->file.localinit) - callinit(block, file->file.localinit, tyvoid, tyvoidfn); - - func = mkfunc(Zloc, NULL, 0, mktype(Zloc, Tyvoid), block); - func->expr.type = tyvoidfn; - init = mkexpr(Zloc, Olit, func, NULL); - init->expr.type = tyvoidfn; - - decl->decl.init = init; - decl->decl.isconst = 1; - decl->decl.isglobl = 1; - decl->decl.type = tyvoidfn; - decl->decl.vis = Vishidden; - - lappend(&file->file.stmts, &file->file.nstmts, decl); + Node *name, *decl, *func, *block, *init; + Type *tyvoid, *tyvoidfn; + size_t i; + + name = mkname(Zloc, "__init__"); + decl = mkdecl(Zloc, name, mktyvar(Zloc)); + block = mkblock(Zloc, mkstab(0)); + block->block.scope->super = file->file.globls; + tyvoid = mktype(Zloc, Tyvoid); + tyvoidfn = mktyfunc(Zloc, NULL, 0, tyvoid); + + for (i = 0; i < file->file.ninit; i++) { + init = initdecl(file, file->file.init[i], tyvoidfn); + callinit(block, init, tyvoid, tyvoidfn); + } + if (file->file.localinit) + callinit(block, file->file.localinit, tyvoid, tyvoidfn); + + func = mkfunc(Zloc, NULL, 0, mktype(Zloc, Tyvoid), block); + func->expr.type = tyvoidfn; + init = mkexpr(Zloc, Olit, func, NULL); + init->expr.type = tyvoidfn; + + decl->decl.init = init; + decl->decl.isconst = 1; + decl->decl.isglobl = 1; + decl->decl.type = tyvoidfn; + decl->decl.vis = Vishidden; + + lappend(&file->file.stmts, &file->file.nstmts, decl); } diff --git a/parse/stab.c b/parse/stab.c index 47e06af..f1db002 100644 --- a/parse/stab.c +++ b/parse/stab.c @@ -16,15 +16,15 @@ typedef struct Tydefn Tydefn; typedef struct Traitdefn Traitdefn; struct Tydefn { - Srcloc loc; - Node *name; - Type *type; + Srcloc loc; + Node *name; + Type *type; }; struct Traitdefn { - Srcloc loc; - Node *name; - Trait *trait; + Srcloc loc; + Node *name; + Trait *trait; }; #define Maxstabdepth 128 @@ -34,105 +34,99 @@ int stabstkoff; /* scope management */ Stab *curstab() { - assert(stabstkoff > 0); - return stabstk[stabstkoff - 1]; + assert(stabstkoff > 0); + return stabstk[stabstkoff - 1]; } void pushstab(Stab *st) { - assert(stabstkoff < Maxstabdepth); - stabstk[stabstkoff++] = st; + assert(stabstkoff < Maxstabdepth); + stabstk[stabstkoff++] = st; } void popstab(void) { - assert(stabstkoff > 0); - stabstkoff--; + assert(stabstkoff > 0); + stabstkoff--; } /* name hashing: we want namespaced lookups to find the * name even if we haven't set the namespace up, since * we can update it after the fact. */ -static ulong nsnamehash(void *n) -{ - return strhash(namestr(n)); -} +static ulong nsnamehash(void *n) { return strhash(namestr(n)); } -static int nsnameeq(void *a, void *b) -{ - return a == b || !strcmp(namestr(a), namestr(b)); -} +static int nsnameeq(void *a, void *b) { return a == b || !strcmp(namestr(a), namestr(b)); } static ulong implhash(void *p) { - Node *n; - ulong h; + Node *n; + ulong h; - n = p; - h = nsnamehash(n->impl.traitname); - h *= tyhash(n->impl.type); - return h; + n = p; + h = nsnamehash(n->impl.traitname); + h *= tyhash(n->impl.type); + return h; } static int impleq(void *pa, void *pb) { - Node *a, *b; + Node *a, *b; - a = pa; - b = pb; - if (nsnameeq(a->impl.traitname, b->impl.traitname)) - return tyeq(a->impl.type, b->impl.type); - return 0; + a = pa; + b = pb; + if (nsnameeq(a->impl.traitname, b->impl.traitname)) + return tyeq(a->impl.type, b->impl.type); + return 0; } Stab *mkstab(int isfunc) { - Stab *st; - - st = zalloc(sizeof(Stab)); - st->dcl = mkht(nsnamehash, nsnameeq); - st->ty = mkht(nsnamehash, nsnameeq); - st->tr = mkht(nsnamehash, nsnameeq); - st->uc = mkht(nsnamehash, nsnameeq); - if (isfunc) - st->env = mkht(nsnamehash, nsnameeq); - st->impl = mkht(implhash, impleq); - return st; + Stab *st; + + st = zalloc(sizeof(Stab)); + st->dcl = mkht(nsnamehash, nsnameeq); + st->ty = mkht(nsnamehash, nsnameeq); + st->tr = mkht(nsnamehash, nsnameeq); + st->uc = mkht(nsnamehash, nsnameeq); + if (isfunc) + st->env = mkht(nsnamehash, nsnameeq); + st->impl = mkht(implhash, impleq); + return st; } Node *getclosed(Stab *st, Node *n) { - while (st && !st->env) - st = st->super; - if (st) - return htget(st->env, n); - return NULL; + while (st && !st->env) + st = st->super; + if (st) + return htget(st->env, n); + return NULL; } Node **getclosure(Stab *st, size_t *n) { - size_t nkeys, i; - void **keys; - Node **vals; - - while (st && !st->env) - st = st->super; - - if (!st) { - *n = 0; - return NULL; - } - - vals = NULL; - *n = 0; - keys = htkeys(st->env, &nkeys); - for (i = 0; i < nkeys; i++) - lappend(&vals, n, htget(st->env, keys[i])); - free(keys); - return vals; + size_t nkeys, i; + void **keys; + Node **vals; + + while (st && !st->env) + st = st->super; + + if (!st) { + *n = 0; + return NULL; + } + + vals = NULL; + *n = 0; + keys = htkeys(st->env, &nkeys); + for (i = 0; i < nkeys; i++) + lappend(&vals, n, htget(st->env, keys[i])); + free(keys); + return vals; } -/* +/* * Searches for declarations from current * scope, and all enclosing scopes. Does * not resolve namespaces -- that is the job @@ -144,312 +138,322 @@ Node **getclosure(Stab *st, size_t *n) */ Node *getdcl(Stab *st, Node *n) { - Node *s; - Stab *fn; - - fn = NULL; - do { - s = htget(st->dcl, n); - if (s) { - /* record that this is in the closure of this scope */ - if (fn && !s->decl.isglobl) - htput(fn->env, s->decl.name, s); - return s; - } - if (!fn && st->env) - fn = st; - st = st->super; - } while (st); - return NULL; + Node *s; + Stab *fn; + + fn = NULL; + do { + s = htget(st->dcl, n); + if (s) { + /* record that this is in the closure of this scope */ + if (fn && !s->decl.isglobl) + htput(fn->env, s->decl.name, s); + return s; + } + if (!fn && st->env) + fn = st; + st = st->super; + } while (st); + return NULL; } Type *gettype_l(Stab *st, Node *n) { - Tydefn *t; + Tydefn *t; - if ((t = htget(st->ty, n))) - return t->type; - return NULL; + if ((t = htget(st->ty, n))) + return t->type; + return NULL; } - Type *gettype(Stab *st, Node *n) { - Tydefn *t; - - do { - if ((t = htget(st->ty, n))) - return t->type; - st = st->super; - } while (st); - return NULL; + Tydefn *t; + + do { + if ((t = htget(st->ty, n))) + return t->type; + st = st->super; + } while (st); + return NULL; } int hastype(Stab *st, Node *n) { - do { - if (hthas(st->ty, n)) - return 1; - st = st->super; - } while(st); - return 0; + do { + if (hthas(st->ty, n)) + return 1; + st = st->super; + } while (st); + return 0; } Ucon *getucon(Stab *st, Node *n) { - Ucon *uc; - - do { - if ((uc = htget(st->uc, n))) - return uc; - st = st->super; - } while (st); - return NULL; + Ucon *uc; + + do { + if ((uc = htget(st->uc, n))) + return uc; + st = st->super; + } while (st); + return NULL; } Trait *gettrait(Stab *st, Node *n) { - Traitdefn *c; - - do { - if ((c = htget(st->tr, n))) - return c->trait; - st = st->super; - } while (st); - return NULL; + Traitdefn *c; + + do { + if ((c = htget(st->tr, n))) + return c->trait; + st = st->super; + } while (st); + return NULL; } -Stab *getns(Node *file, char *name) -{ - return htget(file->file.ns, name); -} +Stab *getns(Node *file, char *name) { return htget(file->file.ns, name); } static int mergedecl(Node *old, Node *new) { - Node *e, *g; - - if (old->decl.ishidden || new->decl.ishidden) { - old->decl.ishidden = old->decl.ishidden && new->decl.ishidden; - return 1; - } - if (old->decl.isextern || new->decl.isextern) { - old->decl.isextern = old->decl.isextern && new->decl.isextern; - return 1; - } - if (old->decl.vis == Visexport && new->decl.vis != Visexport) { - e = old; - g = new; - } else if (new->decl.vis == Visexport && old->decl.vis != Visexport) { - e = new; - g = old; - } else { - return 0; - } - old->decl.vis = Visexport; - - if (e->decl.init && g->decl.init) - fatal(e, "export %s double initialized on %s:%d", declname(e), fname(g->loc), lnum(g->loc)); - if (e->decl.isgeneric != g->decl.isgeneric) - fatal(e, "export %s declared with different genericness on %s:%d", declname(e), fname(g->loc), lnum(g->loc)); - if (e->decl.isconst != g->decl.isconst) - fatal(e, "export %s declared with different constness on %s:%d", declname(e), fname(g->loc), lnum(g->loc)); - if (e->decl.isconst != g->decl.isconst) - fatal(e, "export %s declared with different externness on %s:%d", declname(e), fname(g->loc), lnum(g->loc)); - - if (new->decl.name->name.ns) - setns(old->decl.name, new->decl.name->name.ns); - if (e->decl.type->type == Tyvar) - e->decl.type = g->decl.type; - else if (g->decl.type->type == Tyvar) - g->decl.type = e->decl.type; - - if (!e->decl.init) - e->decl.init = g->decl.init; - else if (!g->decl.init) - g->decl.init = e->decl.init; - - /* FIXME: check compatible typing */ - old->decl.ishidden = e->decl.ishidden || g->decl.ishidden; - old->decl.isimport = e->decl.isimport || g->decl.isimport; - old->decl.isnoret = e->decl.isnoret || g->decl.isnoret; - old->decl.isexportinit = e->decl.isexportinit || g->decl.isexportinit; - old->decl.isglobl = e->decl.isglobl || g->decl.isglobl; - old->decl.ispkglocal = e->decl.ispkglocal || g->decl.ispkglocal; - old->decl.isextern = e->decl.isextern || g->decl.isextern; - return 1; + Node *e, *g; + + if (old->decl.ishidden || new->decl.ishidden) { + old->decl.ishidden = old->decl.ishidden && new->decl.ishidden; + return 1; + } + if (old->decl.isextern || new->decl.isextern) { + old->decl.isextern = old->decl.isextern && new->decl.isextern; + return 1; + } + if (old->decl.vis == Visexport && new->decl.vis != Visexport) { + e = old; + g = new; + } + else if (new->decl.vis == Visexport && old->decl.vis != Visexport) { + e = new; + g = old; + } + else { + return 0; + } + old->decl.vis = Visexport; + + if (e->decl.init && g->decl.init) + fatal(e, "export %s double initialized on %s:%d", declname(e), fname(g->loc), + lnum(g->loc)); + if (e->decl.isgeneric != g->decl.isgeneric) + fatal(e, "export %s declared with different genericness on %s:%d", declname(e), + fname(g->loc), lnum(g->loc)); + if (e->decl.isconst != g->decl.isconst) + fatal(e, "export %s declared with different constness on %s:%d", declname(e), + fname(g->loc), lnum(g->loc)); + if (e->decl.isconst != g->decl.isconst) + fatal(e, "export %s declared with different externness on %s:%d", declname(e), + fname(g->loc), lnum(g->loc)); + + if (new->decl.name->name.ns) + setns(old->decl.name, new->decl.name->name.ns); + if (e->decl.type->type == Tyvar) + e->decl.type = g->decl.type; + else if (g->decl.type->type == Tyvar) + g->decl.type = e->decl.type; + + if (!e->decl.init) + e->decl.init = g->decl.init; + else if (!g->decl.init) + g->decl.init = e->decl.init; + + /* FIXME: check compatible typing */ + old->decl.ishidden = e->decl.ishidden || g->decl.ishidden; + old->decl.isimport = e->decl.isimport || g->decl.isimport; + old->decl.isnoret = e->decl.isnoret || g->decl.isnoret; + old->decl.isexportinit = e->decl.isexportinit || g->decl.isexportinit; + old->decl.isglobl = e->decl.isglobl || g->decl.isglobl; + old->decl.ispkglocal = e->decl.ispkglocal || g->decl.ispkglocal; + old->decl.isextern = e->decl.isextern || g->decl.isextern; + return 1; } -void forcedcl (Stab *st, Node *s) { - if (st->name) - setns(s->decl.name, st->name); - htput(st->dcl, s->decl.name, s); - assert(htget(st->dcl, s->decl.name) != NULL); +void forcedcl(Stab *st, Node *s) +{ + if (st->name) + setns(s->decl.name, st->name); + htput(st->dcl, s->decl.name, s); + assert(htget(st->dcl, s->decl.name) != NULL); } void putdcl(Stab *st, Node *s) { - Node *name, *old; - Stab *ns; - - name = s->decl.name; - if (name->name.ns) { - ns = getns(file, name->name.ns); - if (!ns) { - ns = mkstab(0); - updatens(ns, name->name.ns); - } - st = ns; - } - old = htget(st->dcl, s->decl.name); - if (!old) - forcedcl(st, s); - else if (!mergedecl(old, s)) - fatal(old, "%s already declared on %s:%d", namestr(s->decl.name), fname(s->loc), lnum(s->loc)); + Node *name, *old; + Stab *ns; + + name = s->decl.name; + if (name->name.ns) { + ns = getns(file, name->name.ns); + if (!ns) { + ns = mkstab(0); + updatens(ns, name->name.ns); + } + st = ns; + } + old = htget(st->dcl, s->decl.name); + if (!old) + forcedcl(st, s); + else if (!mergedecl(old, s)) + fatal(old, "%s already declared on %s:%d", namestr(s->decl.name), fname(s->loc), + lnum(s->loc)); } void updatetype(Stab *st, Node *n, Type *t) { - Tydefn *td; + Tydefn *td; - td = htget(st->ty, n); - if (!td) - die("No type %s to update", namestr(n)); - td->type = t; + td = htget(st->ty, n); + if (!td) + die("No type %s to update", namestr(n)); + td->type = t; } int mergetype(Type *old, Type *new) { - if (!new) { - lfatal(new->loc, "double prototyping of %s", tystr(new)); - } else if (old->vis == Visexport && new->vis != Visexport) { - if (!old->sub && new->sub) { - old->sub = new->sub; - old->nsub = new->nsub; - return 1; - } - } else if (new->vis == Visexport && old->vis != Visexport) { - if (!new->sub && old->sub) { - new->sub = old->sub; - new->nsub = old->nsub; - return 1; - } - } - return 0; + if (!new) { + lfatal(new->loc, "double prototyping of %s", tystr(new)); + } + else if (old->vis == Visexport && new->vis != Visexport) { + if (!old->sub && new->sub) { + old->sub = new->sub; + old->nsub = new->nsub; + return 1; + } + } + else if (new->vis == Visexport && old->vis != Visexport) { + if (!new->sub && old->sub) { + new->sub = old->sub; + new->nsub = old->nsub; + return 1; + } + } + return 0; } void puttype(Stab *st, Node *n, Type *t) { - Tydefn *td; - Type *ty; - - if (st->name) - setns(n, st->name); - if (st->name && t && t->name) - setns(t->name, st->name); - - ty = gettype(st, n); - if (!ty) { - if (t && hastype(st, n)) { - t->vis = Visexport; - updatetype(st, n, t); - } else { - td = xalloc(sizeof(Tydefn)); - td->loc = n->loc; - td->name = n; - td->type = t; - htput(st->ty, td->name, td); - } - } else if (!mergetype(ty, t)) { - fatal(n, "Type %s already declared on %s:%d", tystr(ty), fname(ty->loc), lnum(ty->loc)); - } + Tydefn *td; + Type *ty; + + if (st->name) + setns(n, st->name); + if (st->name && t && t->name) + setns(t->name, st->name); + + ty = gettype(st, n); + if (!ty) { + if (t && hastype(st, n)) { + t->vis = Visexport; + updatetype(st, n, t); + } + else { + td = xalloc(sizeof(Tydefn)); + td->loc = n->loc; + td->name = n; + td->type = t; + htput(st->ty, td->name, td); + } + } + else if (!mergetype(ty, t)) { + fatal(n, "Type %s already declared on %s:%d", tystr(ty), fname(ty->loc), + lnum(ty->loc)); + } } void putucon(Stab *st, Ucon *uc) { - Ucon *old; - + Ucon *old; - old = getucon(st, uc->name); - if (old) - lfatal(old->loc, "`%s already defined on %s:%d", namestr(uc->name), fname(uc->loc), lnum(uc->loc)); - htput(st->uc, uc->name, uc); + old = getucon(st, uc->name); + if (old) + lfatal(old->loc, "`%s already defined on %s:%d", namestr(uc->name), fname(uc->loc), + lnum(uc->loc)); + htput(st->uc, uc->name, uc); } static int mergetrait(Trait *old, Trait *new) { - if (old->isproto && !new->isproto) - *old = *new; - else if (new->isproto && !old->isproto) - *new = *old; - else - return 0; - return 1; + if (old->isproto && !new->isproto) + *old = *new; + else if (new->isproto && !old->isproto) + *new = *old; + else + return 0; + return 1; } void puttrait(Stab *st, Node *n, Trait *c) { - Traitdefn *td; - Trait *t; - Type *ty; - - t = gettrait(st, n); - if (t && !mergetrait(t, c)) - fatal(n, "Trait %s already defined on %s:%d", namestr(n), fname(t->loc), lnum(t->loc)); - ty = gettype(st, n); - if (ty) - fatal(n, "Trait %s defined as a type on %s:%d", namestr(n), fname(ty->loc), lnum(ty->loc)); - td = xalloc(sizeof(Traitdefn)); - td->loc = n->loc; - td->name = n; - td->trait = c; - htput(st->tr, td->name, td); + Traitdefn *td; + Trait *t; + Type *ty; + + t = gettrait(st, n); + if (t && !mergetrait(t, c)) + fatal(n, "Trait %s already defined on %s:%d", namestr(n), fname(t->loc), + lnum(t->loc)); + ty = gettype(st, n); + if (ty) + fatal(n, "Trait %s defined as a type on %s:%d", namestr(n), fname(ty->loc), + lnum(ty->loc)); + td = xalloc(sizeof(Traitdefn)); + td->loc = n->loc; + td->name = n; + td->trait = c; + htput(st->tr, td->name, td); } static int mergeimpl(Node *old, Node *new) { - if (old->impl.isproto && !new->impl.isproto) - *old = *new; - else if (new->impl.isproto && !old->impl.isproto) - *new = *old; - else - return 0; - return 1; + if (old->impl.isproto && !new->impl.isproto) + *old = *new; + else if (new->impl.isproto && !old->impl.isproto) + *new = *old; + else + return 0; + return 1; } void putimpl(Stab *st, Node *n) { - Node *impl; - - impl = getimpl(st, n); - if (impl && !mergeimpl(impl, n)) - fatal(n, "Trait %s already implemented over %s at %s:%d", - namestr(n->impl.traitname), tystr(n->impl.type), - fname(n->loc), lnum(n->loc)); - if (st->name) - setns(n->impl.traitname, st->name); - htput(st->impl, n, n); + Node *impl; + + impl = getimpl(st, n); + if (impl && !mergeimpl(impl, n)) + fatal(n, "Trait %s already implemented over %s at %s:%d", + namestr(n->impl.traitname), tystr(n->impl.type), fname(n->loc), lnum(n->loc)); + if (st->name) + setns(n->impl.traitname, st->name); + htput(st->impl, n, n); } Node *getimpl(Stab *st, Node *n) { - Node *imp; - - do { - if ((imp = htget(st->impl, n))) - return imp; - st = st->super; - } while (st); - return NULL; + Node *imp; + + do { + if ((imp = htget(st->impl, n))) + return imp; + st = st->super; + } while (st); + return NULL; } void putns(Node *file, Stab *scope) { - Stab *s; + Stab *s; - s = getns(file, scope->name); - if (s) - lfatal(Zloc, "Namespace %s already defined", scope->name); - htput(file->file.ns, scope->name, scope); + s = getns(file, scope->name); + if (s) + lfatal(Zloc, "Namespace %s already defined", scope->name); + htput(file->file.ns, scope->name, scope); } /* @@ -459,25 +463,25 @@ void putns(Node *file, Stab *scope) */ void updatens(Stab *st, char *name) { - void **k; - size_t i, nk; - Tydefn *td; - - if (st->name) - die("Stab %s already has namespace; Can't set to %s", st->name, name); - st->name = strdup(name); - htput(file->file.ns, st->name, st); - k = htkeys(st->dcl, &nk); - for (i = 0; i < nk; i++) - setns(k[i], name); - free(k); - k = htkeys(st->ty, &nk); - for (i = 0; i < nk; i++) - setns(k[i], name); - for (i = 0; i < nk; i++) { - td = htget(st->ty, k[i]); - if (td->type && (td->type->type == Tyname || td->type->type == Tygeneric)) - setns(td->type->name, name); - } - free(k); + void **k; + size_t i, nk; + Tydefn *td; + + if (st->name) + die("Stab %s already has namespace; Can't set to %s", st->name, name); + st->name = strdup(name); + htput(file->file.ns, st->name, st); + k = htkeys(st->dcl, &nk); + for (i = 0; i < nk; i++) + setns(k[i], name); + free(k); + k = htkeys(st->ty, &nk); + for (i = 0; i < nk; i++) + setns(k[i], name); + for (i = 0; i < nk; i++) { + td = htget(st->ty, k[i]); + if (td->type && (td->type->type == Tyname || td->type->type == Tygeneric)) + setns(td->type->name, name); + } + free(k); } diff --git a/parse/tok.c b/parse/tok.c index 9cb6716..6facbf0 100644 --- a/parse/tok.c +++ b/parse/tok.c @@ -22,36 +22,33 @@ Srcloc curloc; Tok *curtok; /* the file contents are stored globally */ -static int fidx; -static int fbufsz; +static int fidx; +static int fbufsz; static char *fbuf; static int peekn(int n) { - if (fidx + n >= fbufsz) - return End; - else - return fbuf[fidx + n]; + if (fidx + n >= fbufsz) + return End; + else + return fbuf[fidx + n]; } -static int peek(void) -{ - return peekn(0); -} +static int peek(void) { return peekn(0); } static int next(void) { - int c; + int c; - c = peek(); - fidx++; - return c; + c = peek(); + fidx++; + return c; } static void unget(void) { - fidx--; - assert(fidx >= 0); + fidx--; + assert(fidx >= 0); } /* @@ -62,61 +59,57 @@ static void unget(void) */ static int match(char c) { - if (peek() == c) { - next(); - return 1; - } else { - return 0; - } + if (peek() == c) { + next(); + return 1; + } + else { + return 0; + } } static Tok *mktok(int tt) { - Tok *t; + Tok *t; - t = zalloc(sizeof(Tok)); - t->type = tt; - t->loc = curloc; - return t; + t = zalloc(sizeof(Tok)); + t->type = tt; + t->loc = curloc; + return t; } -static int identchar(int c) -{ - return isalnum(c) || c == '_' || c == '$'; -} +static int identchar(int c) { return isalnum(c) || c == '_' || c == '$'; } static void eatcomment(void) { - int depth; - int startln; - int c; - - depth = 0; - startln = curloc.line; - while (1) { - c = next(); - switch (c) { - /* enter level of nesting */ - case '/': - if (match('*')) - depth++; - break; - /* leave level of nesting */ - case '*': - if (match('/')) - depth--; - break; - /* have to keep line numbers synced */ - case '\n': - curloc.line++; - break; - case End: - lfatal(curloc, "File ended within comment starting at line %d", startln); - break; - } - if (depth == 0) - break; - } + int depth; + int startln; + int c; + + depth = 0; + startln = curloc.line; + while (1) { + c = next(); + switch (c) { + /* enter level of nesting */ + case '/': + if (match('*')) + depth++; + break; + /* leave level of nesting */ + case '*': + if (match('/')) + depth--; + break; + /* have to keep line numbers synced */ + case '\n': curloc.line++; break; + case End: + lfatal(curloc, "File ended within comment starting at line %d", startln); + break; + } + if (depth == 0) + break; + } } /* @@ -128,29 +121,34 @@ static void eatcomment(void) */ static void eatspace(void) { - int c; - int ignorenl; - - ignorenl = 0; - while (1) { - c = peek(); - if (!ignorenl && c == '\n') { - break; - } else if (c == '\\') { - ignorenl = 1; - next(); - } else if (ignorenl && c == '\n') { - next(); - curloc.line++; - ignorenl = 0; - } else if (isspace(c)) { - next(); - } else if (c == '/' && peekn(1) == '*') { - eatcomment(); - } else { - break; - } - } + int c; + int ignorenl; + + ignorenl = 0; + while (1) { + c = peek(); + if (!ignorenl && c == '\n') { + break; + } + else if (c == '\\') { + ignorenl = 1; + next(); + } + else if (ignorenl && c == '\n') { + next(); + curloc.line++; + ignorenl = 0; + } + else if (isspace(c)) { + next(); + } + else if (c == '/' && peekn(1) == '*') { + eatcomment(); + } + else { + break; + } + } } /* @@ -161,116 +159,93 @@ static void eatspace(void) */ static int kwd(char *s) { - static const struct {char* kw; int tt;} kwmap[] = { - {"$", Tidxlen}, - {"$noret", Tattr}, - {"_", Tgap}, - {"break", Tbreak}, - {"castto", Tcast}, - {"const", Tconst}, - {"continue", Tcontinue}, - {"elif", Telif}, - {"else", Telse}, - {"export", Texport}, - {"extern", Tattr}, - {"false", Tboollit}, - {"for", Tfor}, - {"generic", Tgeneric}, - {"goto", Tgoto}, - {"if", Tif}, - {"impl", Timpl}, - {"in", Tin}, - {"match", Tmatch}, - {"pkg", Tpkg}, - {"pkglocal", Tattr}, - {"protect", Tprotect}, - {"sizeof", Tsizeof}, - {"struct", Tstruct}, - {"trait", Ttrait}, - {"true", Tboollit}, - {"type", Ttype}, - {"union", Tunion}, - {"use", Tuse}, - {"var", Tvar}, - {"while", Twhile}, - }; - - size_t min, max, mid; - int cmp; - - - min = 0; - max = sizeof(kwmap)/sizeof(kwmap[0]); - while (max > min) { - mid = (max + min) / 2; - cmp = strcmp(s, kwmap[mid].kw); - if (cmp == 0) - return kwmap[mid].tt; - else if (cmp > 0) - min = mid + 1; - else if (cmp < 0) - max = mid; - } - return Tident; + static const struct { + char *kw; + int tt; + } kwmap[] = { + {"$", Tidxlen}, {"$noret", Tattr}, {"_", Tgap}, {"break", Tbreak}, {"castto", Tcast}, + {"const", Tconst}, {"continue", Tcontinue}, {"elif", Telif}, {"else", Telse}, + {"export", Texport}, {"extern", Tattr}, {"false", Tboollit}, {"for", Tfor}, + {"generic", Tgeneric}, {"goto", Tgoto}, {"if", Tif}, {"impl", Timpl}, {"in", Tin}, + {"match", Tmatch}, {"pkg", Tpkg}, {"pkglocal", Tattr}, {"protect", Tprotect}, + {"sizeof", Tsizeof}, {"struct", Tstruct}, {"trait", Ttrait}, {"true", Tboollit}, + {"type", Ttype}, {"union", Tunion}, {"use", Tuse}, {"var", Tvar}, {"while", Twhile}, + }; + + size_t min, max, mid; + int cmp; + + min = 0; + max = sizeof(kwmap) / sizeof(kwmap[0]); + while (max > min) { + mid = (max + min) / 2; + cmp = strcmp(s, kwmap[mid].kw); + if (cmp == 0) + return kwmap[mid].tt; + else if (cmp > 0) + min = mid + 1; + else if (cmp < 0) + max = mid; + } + return Tident; } static int identstr(char *buf, size_t sz) { - size_t i; - char c; - - i = 0; - for (c = peek(); i < sz && identchar(c); c = peek()) { - next(); - buf[i++] = c; - } - buf[i] = '\0'; - return i; + size_t i; + char c; + + i = 0; + for (c = peek(); i < sz && identchar(c); c = peek()) { + next(); + buf[i++] = c; + } + buf[i] = '\0'; + return i; } static Tok *kwident(void) { - char buf[1024]; - Tok *t; - - if (!identstr(buf, sizeof buf)) - return NULL; - t = mktok(kwd(buf)); - t->id = strdup(buf); - return t; + char buf[1024]; + Tok *t; + + if (!identstr(buf, sizeof buf)) + return NULL; + t = mktok(kwd(buf)); + t->id = strdup(buf); + return t; } static void append(char **buf, size_t *len, size_t *sz, int c) { - if (!*sz) { - *sz = 16; - *buf = malloc(*sz); - } - if (*len == *sz - 1) { - *sz = *sz * 2; - *buf = realloc(*buf, *sz); - } - - buf[0][*len] = c; - (*len)++; + if (!*sz) { + *sz = 16; + *buf = malloc(*sz); + } + if (*len == *sz - 1) { + *sz = *sz * 2; + *buf = realloc(*buf, *sz); + } + + buf[0][*len] = c; + (*len)++; } - static void encode(char *buf, size_t len, uint32_t c) { - int mark; - size_t i; - - assert(len > 0 && len < 5); - if (len == 1) - mark = 0; - else - mark = (((1 << (8 - len)) - 1) ^ 0xff); - for (i = len - 1; i > 0; i--) { - buf[i] = (c & 0x3f) | 0x80; - c >>= 6; - } - buf[0] = (c | mark); + int mark; + size_t i; + + assert(len > 0 && len < 5); + if (len == 1) + mark = 0; + else + mark = (((1 << (8 - len)) - 1) ^ 0xff); + for (i = len - 1; i > 0; i--) { + buf[i] = (c & 0x3f) | 0x80; + c >>= 6; + } + buf[0] = (c | mark); } /* @@ -279,34 +254,34 @@ static void encode(char *buf, size_t len, uint32_t c) */ static void appendc(char **buf, size_t *len, size_t *sz, uint32_t c) { - size_t i, charlen; - char charbuf[5] = {0}; - - if (c < 0x80) - charlen = 1; - else if (c < 0x800) - charlen = 2; - else if (c < 0x10000) - charlen = 3; - else if (c < 0x200000) - charlen = 4; - else - lfatal(curloc, "invalid utf character '\\u{%x}'", c); - - encode(charbuf, charlen, c); - for (i = 0; i < charlen; i++) - append(buf, len, sz, charbuf[i]); + size_t i, charlen; + char charbuf[5] = {0}; + + if (c < 0x80) + charlen = 1; + else if (c < 0x800) + charlen = 2; + else if (c < 0x10000) + charlen = 3; + else if (c < 0x200000) + charlen = 4; + else + lfatal(curloc, "invalid utf character '\\u{%x}'", c); + + encode(charbuf, charlen, c); + for (i = 0; i < charlen; i++) + append(buf, len, sz, charbuf[i]); } static int ishexval(char c) { - if (c >= 'a' && c <= 'f') - return 1; - else if (c >= 'A' && c <= 'F') - return 1; - else if (c >= '0' && c <= '9') - return 1; - return 0; + if (c >= 'a' && c <= 'f') + return 1; + else if (c >= 'A' && c <= 'F') + return 1; + else if (c >= '0' && c <= '9') + return 1; + return 0; } /* @@ -314,35 +289,35 @@ static int ishexval(char c) */ static int hexval(char c) { - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - else if (c >= '0' && c <= '9') - return c - '0'; - lfatal(curloc, "passed non-hex value '%c' to where hex was expected", c); - return -1; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= '0' && c <= '9') + return c - '0'; + lfatal(curloc, "passed non-hex value '%c' to where hex was expected", c); + return -1; } /* \u{abc} */ static int32_t unichar(void) { - uint32_t v; - int c; - - /* we've already seen the \u */ - if (next() != '{') - lfatal(curloc, "\\u escape sequence without initial '{'"); - v = 0; - while (ishexval(peek())) { - c = next(); - v = 16*v + hexval(c); - if (v > 0x10FFFF) - lfatal(curloc, "invalid codepoint for \\u escape sequence"); - } - if (next() != '}') - lfatal(curloc, "\\u escape sequence without ending '}'"); - return v; + uint32_t v; + int c; + + /* we've already seen the \u */ + if (next() != '{') + lfatal(curloc, "\\u escape sequence without initial '{'"); + v = 0; + while (ishexval(peek())) { + c = next(); + v = 16 * v + hexval(c); + if (v > 0x10FFFF) + lfatal(curloc, "invalid codepoint for \\u escape sequence"); + } + if (next() != '}') + lfatal(curloc, "\\u escape sequence without ending '}'"); + return v; } /* @@ -352,492 +327,507 @@ static int32_t unichar(void) */ static int decode(char **buf, size_t *len, size_t *sz) { - char c, c1, c2; - int32_t v; - - c = next(); - /* we've already seen the '\' */ - switch (c) { - case 'u': - v = unichar(); - appendc(buf, len, sz, v); - return v; - case 'x': /* arbitrary hex */ - c1 = next(); - if (!isxdigit(c1)) - lfatal(curloc, "expected hex digit, got %c", c1); - c2 = next(); - if (!isxdigit(c2)) - lfatal(curloc, "expected hex digit, got %c", c1); - v = 16*hexval(c1) + hexval(c2); - break; - case 'n': v = '\n'; break; - case 'r': v = '\r'; break; - case 't': v = '\t'; break; - case 'b': v = '\b'; break; - case '"': v = '\"'; break; - case '\'': v = '\''; break; - case 'v': v = '\v'; break; - case '\\': v = '\\'; break; - case '0': v = '\0'; break; - default: lfatal(curloc, "unknown escape code \\%c", c); - } - append(buf, len, sz, v); - return v; + char c, c1, c2; + int32_t v; + + c = next(); + /* we've already seen the '\' */ + switch (c) { + case 'u': + v = unichar(); + appendc(buf, len, sz, v); + return v; + case 'x': /* arbitrary hex */ + c1 = next(); + if (!isxdigit(c1)) + lfatal(curloc, "expected hex digit, got %c", c1); + c2 = next(); + if (!isxdigit(c2)) + lfatal(curloc, "expected hex digit, got %c", c1); + v = 16 * hexval(c1) + hexval(c2); + break; + case 'n': v = '\n'; break; + case 'r': v = '\r'; break; + case 't': v = '\t'; break; + case 'b': v = '\b'; break; + case '"': v = '\"'; break; + case '\'': v = '\''; break; + case 'v': v = '\v'; break; + case '\\': v = '\\'; break; + case '0': v = '\0'; break; + default: lfatal(curloc, "unknown escape code \\%c", c); + } + append(buf, len, sz, v); + return v; } static Tok *strlit(void) { - Tok *t; - int c; - size_t len, sz; - char *buf; - - assert(next() == '"'); - - buf = NULL; - len = 0; - sz = 0; - while (1) { - c = next(); - /* we don't unescape here, but on output */ - if (c == '"') - break; - else if (c == End) - lfatal(curloc, "Unexpected EOF within string"); - else if (c == '\n') - lfatal(curloc, "Newlines not allowed in strings"); - else if (c == '\\') - decode(&buf, &len, &sz); - else - append(&buf, &len, &sz, c); - }; - t = mktok(Tstrlit); - t->strval.len = len; - - /* null terminator should not count towards length */ - append(&buf, &len, &sz, '\0'); - t->strval.buf = buf; - t->id = buf; - return t; + Tok *t; + int c; + size_t len, sz; + char *buf; + + assert(next() == '"'); + + buf = NULL; + len = 0; + sz = 0; + while (1) { + c = next(); + /* we don't unescape here, but on output */ + if (c == '"') + break; + else if (c == End) + lfatal(curloc, "Unexpected EOF within string"); + else if (c == '\n') + lfatal(curloc, "Newlines not allowed in strings"); + else if (c == '\\') + decode(&buf, &len, &sz); + else + append(&buf, &len, &sz, c); + }; + t = mktok(Tstrlit); + t->strval.len = len; + + /* null terminator should not count towards length */ + append(&buf, &len, &sz, '\0'); + t->strval.buf = buf; + t->id = buf; + return t; } -static uint32_t readutf(char c, char **buf, size_t *buflen, size_t *sz) { - size_t i, len; - uint32_t val; - - if ((c & 0x80) == 0) - len = 1; - else if ((c & 0xe0) == 0xc0) - len = 2; - else if ((c & 0xf0) == 0xe0) - len = 3; - else if ((c & 0xf8) == 0xf0) - len = 4; - else - lfatal(curloc, "Invalid utf8 encoded character constant"); - - val = c & ((1 << (8 - len)) - 1); - append(buf, buflen, sz, c); - for (i = 1; i < len; i++) { - c = next(); - if ((c & 0xc0) != 0x80) - lfatal(curloc, "Invalid utf8 codepoint in character literal"); - val = (val << 6) | (c & 0x3f); - append(buf, buflen, sz, c); - } - return val; +static uint32_t readutf(char c, char **buf, size_t *buflen, size_t *sz) +{ + size_t i, len; + uint32_t val; + + if ((c & 0x80) == 0) + len = 1; + else if ((c & 0xe0) == 0xc0) + len = 2; + else if ((c & 0xf0) == 0xe0) + len = 3; + else if ((c & 0xf8) == 0xf0) + len = 4; + else + lfatal(curloc, "Invalid utf8 encoded character constant"); + + val = c & ((1 << (8 - len)) - 1); + append(buf, buflen, sz, c); + for (i = 1; i < len; i++) { + c = next(); + if ((c & 0xc0) != 0x80) + lfatal(curloc, "Invalid utf8 codepoint in character literal"); + val = (val << 6) | (c & 0x3f); + append(buf, buflen, sz, c); + } + return val; } static Tok *charlit(void) { - Tok *t; - int c; - uint32_t val; - size_t len, sz; - char *buf; - - - assert(next() == '\''); - - buf = NULL; - len = 0; - sz = 0; - val = 0; - c = next(); - if (c == End) - lfatal(curloc, "Unexpected EOF within char lit"); - else if (c == '\n') - lfatal(curloc, "Newlines not allowed in char lit"); - else if (c == '\\') - val = decode(&buf, &len, &sz); - else - val = readutf(c, &buf, &len, &sz); - append(&buf, &len, &sz, '\0'); - if (next() != '\'') - lfatal(curloc, "Character constant with multiple characters"); - - t = mktok(Tchrlit); - t->chrval = val; - t->id = buf; - return t; + Tok *t; + int c; + uint32_t val; + size_t len, sz; + char *buf; + + assert(next() == '\''); + + buf = NULL; + len = 0; + sz = 0; + val = 0; + c = next(); + if (c == End) + lfatal(curloc, "Unexpected EOF within char lit"); + else if (c == '\n') + lfatal(curloc, "Newlines not allowed in char lit"); + else if (c == '\\') + val = decode(&buf, &len, &sz); + else + val = readutf(c, &buf, &len, &sz); + append(&buf, &len, &sz, '\0'); + if (next() != '\'') + lfatal(curloc, "Character constant with multiple characters"); + + t = mktok(Tchrlit); + t->chrval = val; + t->id = buf; + return t; } static Tok *oper(void) { - int tt; - char c; - - c = next(); - switch (c) { - case '{': tt = Tobrace; break; - case '}': tt = Tcbrace; break; - case '(': tt = Toparen; break; - case ')': tt = Tcparen; break; - case '[': tt = Tosqbrac; break; - case ']': tt = Tcsqbrac; break; - case ',': tt = Tcomma; break; - case '`': tt = Ttick; break; - case '#': tt = Tderef; break; - case ':': - if (match(':')) - tt = Twith; - else - tt = Tcolon; - break; - case '~': tt = Tbnot; break; - case ';': - if (match(';')) - tt = Tendblk; - else - tt = Tendln; - break; - case '.': - if (match('.')) { - if (match('.')) { - tt = Tellipsis; - } else { - unget(); - tt = Tdot; - } - } else { - tt = Tdot; - } - break; - case '+': - if (match('=')) - tt = Taddeq; - else if (match('+')) - tt = Tinc; - else - tt = Tplus; - break; - case '-': - if (match('=')) - tt = Tsubeq; - else if (match('-')) - tt = Tdec; - else if (match('>')) - tt = Tret; - else - tt = Tminus; - break; - case '*': - if (match('=')) - tt = Tmuleq; - else - tt = Tmul; - break; - case '/': - if (match('=')) - tt = Tdiveq; - else - tt = Tdiv; - break; - case '%': - if (match('=')) - tt = Tmodeq; - else - tt = Tmod; - break; - case '=': - if (match('=')) - tt = Teq; - else - tt = Tasn; - break; - case '|': - if (match('=')) - tt = Tboreq; - else if (match('|')) - tt = Tlor; - else - tt = Tbor; - break; - case '&': - if (match('=')) - tt = Tbandeq; - else if (match('&')) - tt = Tland; - else - tt = Tband; - break; - case '^': - if (match('=')) - tt = Tbxoreq; - else - tt = Tbxor; - break; - case '<': - if (match('=')) { - tt = Tle; - } else if (match('<')) { - if (match('=')) - tt = Tbsleq; - else - tt = Tbsl; - } else { - tt = Tlt; - } - break; - case '>': - if (match('=')) { - tt = Tge; - } else if (match('>')) { - if (match('=')) - tt = Tbsreq; - else - tt = Tbsr; - } else { - tt = Tgt; - } - break; - - case '!': - if (match('=')) - tt = Tne; - else - tt = Tlnot; - break; - default: - tt = Terror; - lfatal(curloc, "Junk character %c", c); - break; - } - return mktok(tt); + int tt; + char c; + + c = next(); + switch (c) { + case '{': tt = Tobrace; break; + case '}': tt = Tcbrace; break; + case '(': tt = Toparen; break; + case ')': tt = Tcparen; break; + case '[': tt = Tosqbrac; break; + case ']': tt = Tcsqbrac; break; + case ',': tt = Tcomma; break; + case '`': tt = Ttick; break; + case '#': tt = Tderef; break; + case ':': + if (match(':')) + tt = Twith; + else + tt = Tcolon; + break; + case '~': tt = Tbnot; break; + case ';': + if (match(';')) + tt = Tendblk; + else + tt = Tendln; + break; + case '.': + if (match('.')) { + if (match('.')) { + tt = Tellipsis; + } + else { + unget(); + tt = Tdot; + } + } + else { + tt = Tdot; + } + break; + case '+': + if (match('=')) + tt = Taddeq; + else if (match('+')) + tt = Tinc; + else + tt = Tplus; + break; + case '-': + if (match('=')) + tt = Tsubeq; + else if (match('-')) + tt = Tdec; + else if (match('>')) + tt = Tret; + else + tt = Tminus; + break; + case '*': + if (match('=')) + tt = Tmuleq; + else + tt = Tmul; + break; + case '/': + if (match('=')) + tt = Tdiveq; + else + tt = Tdiv; + break; + case '%': + if (match('=')) + tt = Tmodeq; + else + tt = Tmod; + break; + case '=': + if (match('=')) + tt = Teq; + else + tt = Tasn; + break; + case '|': + if (match('=')) + tt = Tboreq; + else if (match('|')) + tt = Tlor; + else + tt = Tbor; + break; + case '&': + if (match('=')) + tt = Tbandeq; + else if (match('&')) + tt = Tland; + else + tt = Tband; + break; + case '^': + if (match('=')) + tt = Tbxoreq; + else + tt = Tbxor; + break; + case '<': + if (match('=')) { + tt = Tle; + } + else if (match('<')) { + if (match('=')) + tt = Tbsleq; + else + tt = Tbsl; + } + else { + tt = Tlt; + } + break; + case '>': + if (match('=')) { + tt = Tge; + } + else if (match('>')) { + if (match('=')) + tt = Tbsreq; + else + tt = Tbsr; + } + else { + tt = Tgt; + } + break; + + case '!': + if (match('=')) + tt = Tne; + else + tt = Tlnot; + break; + default: + tt = Terror; + lfatal(curloc, "Junk character %c", c); + break; + } + return mktok(tt); } static Tok *number(int base) { - Tok *t; - int start; - int c; - int isfloat; - int unsignedval; - /* because we allow '_' in numbers, and strtod/stroull don't, we - * need a buffer that holds the number without '_'. - */ - char buf[2048]; - size_t nbuf; - - t = NULL; - isfloat = 0; - start = fidx; - nbuf = 0; - for (c = peek(); isxdigit(c) || c == '.' || c == '_'; c = peek()) { - next(); - if (c == '_') - continue; - if (c == '.') - isfloat = 1; - else if (hexval(c) < 0 || hexval(c) > base) - lfatal(curloc, "Integer digit '%c' outside of base %d", c, base); - if (nbuf >= sizeof buf - 1) { - buf[nbuf-1] = '\0'; - lfatal(curloc, "number %s... too long to represent", buf); - } - buf[nbuf++] = c; - } - buf[nbuf] = '\0'; - - /* we only support base 10 floats */ - if (isfloat && base == 10) { - t = mktok(Tfloatlit); - t->id = strdupn(&fbuf[start], fidx - start); - t->fltval = strtod(buf, NULL); - } else { - t = mktok(Tintlit); - t->id = strdupn(&fbuf[start], fidx - start); - t->intval = strtoull(buf, NULL, base); - /* check suffixes: - * u -> unsigned - * l -> 64 bit - * i -> 32 bit - * w -> 16 bit - * b -> 8 bit - */ - unsignedval = 0; + Tok *t; + int start; + int c; + int isfloat; + int unsignedval; + /* because we allow '_' in numbers, and strtod/stroull don't, we + * need a buffer that holds the number without '_'. + */ + char buf[2048]; + size_t nbuf; + + t = NULL; + isfloat = 0; + start = fidx; + nbuf = 0; + for (c = peek(); isxdigit(c) || c == '.' || c == '_'; c = peek()) { + next(); + if (c == '_') + continue; + if (c == '.') + isfloat = 1; + else if (hexval(c) < 0 || hexval(c) > base) + lfatal(curloc, "Integer digit '%c' outside of base %d", c, base); + if (nbuf >= sizeof buf - 1) { + buf[nbuf - 1] = '\0'; + lfatal(curloc, "number %s... too long to represent", buf); + } + buf[nbuf++] = c; + } + buf[nbuf] = '\0'; + + /* we only support base 10 floats */ + if (isfloat && base == 10) { + t = mktok(Tfloatlit); + t->id = strdupn(&fbuf[start], fidx - start); + t->fltval = strtod(buf, NULL); + } + else { + t = mktok(Tintlit); + t->id = strdupn(&fbuf[start], fidx - start); + t->intval = strtoull(buf, NULL, base); + /* check suffixes: + * u -> unsigned + * l -> 64 bit + * i -> 32 bit + * w -> 16 bit + * b -> 8 bit + */ + unsignedval = 0; nextsuffix: - switch (peek()) { - case 'u': - if (unsignedval == 1) - lfatal(curloc, "Duplicate 'u' integer specifier"); - next(); - unsignedval = 1; - goto nextsuffix; - case 'l': - next(); - if (unsignedval) - t->inttype = Tyuint64; - else - t->inttype = Tyint64; - break; - case 'i': - next(); - if (unsignedval) - t->inttype = Tyuint32; - else - t->inttype = Tyint32; - break; - case 's': - next(); - if (unsignedval) - t->inttype = Tyuint16; - else - t->inttype = Tyint16; - break; - case 'b': - next(); - if (unsignedval) - t->inttype = Tyuint8; - else - t->inttype = Tyint8; - break; - default: - if (unsignedval) - lfatal(curloc, "Unrecognized character int type specifier after 'u'"); - break; - } - } - - return t; + switch (peek()) { + case 'u': + if (unsignedval == 1) + lfatal(curloc, "Duplicate 'u' integer specifier"); + next(); + unsignedval = 1; + goto nextsuffix; + case 'l': + next(); + if (unsignedval) + t->inttype = Tyuint64; + else + t->inttype = Tyint64; + break; + case 'i': + next(); + if (unsignedval) + t->inttype = Tyuint32; + else + t->inttype = Tyint32; + break; + case 's': + next(); + if (unsignedval) + t->inttype = Tyuint16; + else + t->inttype = Tyint16; + break; + case 'b': + next(); + if (unsignedval) + t->inttype = Tyuint8; + else + t->inttype = Tyint8; + break; + default: + if (unsignedval) + lfatal( + curloc, "Unrecognized character int type specifier after 'u'"); + break; + } + } + + return t; } static Tok *numlit(void) { - Tok *t; - - /* check for 0x or 0b prefix */ - if (match('0')) { - if (match('x')) - t = number(16); - else if (match('b')) - t = number(2); - else if (match('o')) - t = number(8); - else - t = number(10); - } else { - t = number(10); - } - - return t; + Tok *t; + + /* check for 0x or 0b prefix */ + if (match('0')) { + if (match('x')) + t = number(16); + else if (match('b')) + t = number(2); + else if (match('o')) + t = number(8); + else + t = number(10); + } + else { + t = number(10); + } + + return t; } static Tok *typaram(void) { - Tok *t; - char buf[1024]; - - t = NULL; - if (!match('@')) - return NULL; - if (!identstr(buf, 1024)) - return NULL; - t = mktok(Ttyparam); - t->id = strdup(buf); - return t; + Tok *t; + char buf[1024]; + + t = NULL; + if (!match('@')) + return NULL; + if (!identstr(buf, 1024)) + return NULL; + t = mktok(Ttyparam); + t->id = strdup(buf); + return t; } static Tok *toknext() { - Tok *t; - int c; - - eatspace(); - c = peek(); - if (c == End) { - t = mktok(0); - } else if (c == '\n') { - curloc.line++; - next(); - t = mktok(Tendln); - } else if (isalpha(c) || c == '_' || c == '$') { - t = kwident(); - } else if (c == '"') { - t = strlit(); - } else if (c == '\'') { - t = charlit(); - } else if (isdigit(c)) { - t = numlit(); - } else if (c == '@') { - t = typaram(); - } else { - t = oper(); - } - - if (!t || t->type == Terror) - lfatal(curloc, "Unable to parse token starting with %c", c); - return t; + Tok *t; + int c; + + eatspace(); + c = peek(); + if (c == End) { + t = mktok(0); + } + else if (c == '\n') { + curloc.line++; + next(); + t = mktok(Tendln); + } + else if (isalpha(c) || c == '_' || c == '$') { + t = kwident(); + } + else if (c == '"') { + t = strlit(); + } + else if (c == '\'') { + t = charlit(); + } + else if (isdigit(c)) { + t = numlit(); + } + else if (c == '@') { + t = typaram(); + } + else { + t = oper(); + } + + if (!t || t->type == Terror) + lfatal(curloc, "Unable to parse token starting with %c", c); + return t; } void tokinit(char *file) { - int fd; - int n; - int nread; - - - fd = open(file, O_RDONLY); - if (fd == -1) { - fprintf(stderr, "Unable to open file %s\n", file); - exit(1); - } - - nread = 0; - fbuf = malloc(4096); - while (1) { - n = read(fd, fbuf + nread, 4096); - if (n < 0) - fatal(0, 0, "Error reading file %s", file); - if (n == 0) - break; - if (!fbuf) - die("Out of memory reading %s", file); - nread += n; - fbuf = xrealloc(fbuf, nread + 4096); - } - - fbufsz = nread; - curloc.line = 1; - curloc.file = 0; - close(fd); - filename = strdup(file); + int fd; + int n; + int nread; + + fd = open(file, O_RDONLY); + if (fd == -1) { + fprintf(stderr, "Unable to open file %s\n", file); + exit(1); + } + + nread = 0; + fbuf = malloc(4096); + while (1) { + n = read(fd, fbuf + nread, 4096); + if (n < 0) + fatal(0, 0, "Error reading file %s", file); + if (n == 0) + break; + if (!fbuf) + die("Out of memory reading %s", file); + nread += n; + fbuf = xrealloc(fbuf, nread + 4096); + } + + fbufsz = nread; + curloc.line = 1; + curloc.file = 0; + close(fd); + filename = strdup(file); } /* Interface to yacc */ int yylex(void) { - curtok = toknext(); - yylval.tok = curtok; - return curtok->type; + curtok = toknext(); + yylval.tok = curtok; + return curtok->type; } void yyerror(const char *s) { - fprintf(stderr, "%s:%d: %s", filename, curloc.line, s); - if (curtok->id) - fprintf(stderr, " near \"%s\"", curtok->id); - fprintf(stderr, "\n"); - exit(1); + fprintf(stderr, "%s:%d: %s", filename, curloc.line, s); + if (curtok->id) + fprintf(stderr, " near \"%s\"", curtok->id); + fprintf(stderr, "\n"); + exit(1); } diff --git a/parse/type.c b/parse/type.c index fc0cebd..0e90df1 100644 --- a/parse/type.c +++ b/parse/type.c @@ -15,8 +15,8 @@ typedef struct Typename Typename; struct Typename { - Ty ty; - char *name; + Ty ty; + char *name; }; Type **tytab = NULL; @@ -29,49 +29,44 @@ size_t ntraittab; static Trait *traits[Ntypes + 1][4]; static int tybfmt(char *buf, size_t len, Type *t); - char stackness[] = { -#define Ty(t, n, stk) \ - stk, +#define Ty(t, n, stk) stk, #include "types.def" #undef Ty }; -int isstacktype(Type *t) -{ - return stackness[tybase(t)->type]; -} +int isstacktype(Type *t) { return stackness[tybase(t)->type]; } Type *mktype(Srcloc loc, Ty ty) { - Type *t; - int i; + Type *t; + int i; - /* the first 'n' types will be identity mapped: tytab[Tyint], eg, - * will map to an instantitaion of Tyint. - * - * This is accomplished at program startup by calling mktype() on - * each builtin type in order. As we do this, we put the type into - * the table as ususal, which gives us an identity mapping. - */ - if (ty <= Tyvalist && ty < ntypes) - return types[ty]; + /* the first 'n' types will be identity mapped: tytab[Tyint], eg, + * will map to an instantitaion of Tyint. + * + * This is accomplished at program startup by calling mktype() on + * each builtin type in order. As we do this, we put the type into + * the table as ususal, which gives us an identity mapping. + */ + if (ty <= Tyvalist && ty < ntypes) + return types[ty]; - t = zalloc(sizeof(Type)); - t->type = ty; - t->tid = ntypes++; - t->loc = loc; - tytab = xrealloc(tytab, ntypes*sizeof(Type*)); - tytab[t->tid] = NULL; - types = xrealloc(types, ntypes*sizeof(Type*)); - types[t->tid] = t; - if (ty <= Tyvalist) /* the last builtin atomic type */ - t->vis = Visbuiltin; + t = zalloc(sizeof(Type)); + t->type = ty; + t->tid = ntypes++; + t->loc = loc; + tytab = xrealloc(tytab, ntypes * sizeof(Type *)); + tytab[t->tid] = NULL; + types = xrealloc(types, ntypes * sizeof(Type *)); + types[t->tid] = t; + if (ty <= Tyvalist) /* the last builtin atomic type */ + t->vis = Visbuiltin; - for(i = 0; traits[ty][i]; i++) - settrait(t, traits[ty][i]); + for (i = 0; traits[ty][i]; i++) + settrait(t, traits[ty][i]); - return t; + return t; } /* @@ -80,34 +75,34 @@ Type *mktype(Srcloc loc, Ty ty) */ Type *tydup(Type *t) { - Type *r; + Type *r; - r = mktype(t->loc, t->type); - r->resolved = 0; /* re-resolving doesn't hurt */ - r->fixed = 0; /* re-resolving doesn't hurt */ + r = mktype(t->loc, t->type); + r->resolved = 0; /* re-resolving doesn't hurt */ + r->fixed = 0; /* re-resolving doesn't hurt */ - r->traits = bsdup(t->traits); - r->traitlist = memdup(t->traitlist, t->ntraitlist * sizeof(Node*)); - r->ntraitlist = t->ntraitlist; + r->traits = bsdup(t->traits); + r->traitlist = memdup(t->traitlist, t->ntraitlist * sizeof(Node *)); + r->ntraitlist = t->ntraitlist; - r->arg = memdup(t->arg, t->narg * sizeof(Type*)); - r->narg = t->narg; - r->inst = memdup(t->arg, t->narg * sizeof(Type*)); - r->ninst = t->ninst; + r->arg = memdup(t->arg, t->narg * sizeof(Type *)); + r->narg = t->narg; + r->inst = memdup(t->arg, t->narg * sizeof(Type *)); + r->ninst = t->ninst; - r->sub = memdup(t->sub, t->nsub * sizeof(Type*)); - r->nsub = t->nsub; - r->nmemb = t->nmemb; - switch (t->type) { - case Tyname: r->name = t->name; break; - case Tyunres: r->name = t->name; break; - case Tyarray: r->asize = t->asize; break; - case Typaram: r->pname = strdup(t->pname); break; - case Tystruct: r->sdecls = memdup(t->sdecls, t->nmemb*sizeof(Node*)); break; - case Tyunion: r->udecls = memdup(t->udecls, t->nmemb*sizeof(Node*)); break; - default: break; - } - return r; + r->sub = memdup(t->sub, t->nsub * sizeof(Type *)); + r->nsub = t->nsub; + r->nmemb = t->nmemb; + switch (t->type) { + case Tyname: r->name = t->name; break; + case Tyunres: r->name = t->name; break; + case Tyarray: r->asize = t->asize; break; + case Typaram: r->pname = strdup(t->pname); break; + case Tystruct: r->sdecls = memdup(t->sdecls, t->nmemb * sizeof(Node *)); break; + case Tyunion: r->udecls = memdup(t->udecls, t->nmemb * sizeof(Node *)); break; + default: break; + } + return r; } /* @@ -116,235 +111,238 @@ Type *tydup(Type *t) */ Type *mktylike(Srcloc loc, Ty like) { - Type *t; - int i; + Type *t; + int i; - t = mktyvar(loc); - for (i = 0; traits[like][i]; i++) - settrait(t, traits[like][i]); - return t; + t = mktyvar(loc); + for (i = 0; traits[like][i]; i++) + settrait(t, traits[like][i]); + return t; } /* steals memb, funcs */ -Trait *mktrait(Srcloc loc, Node *name, Type *param, Node **memb, size_t nmemb, Node **funcs, size_t nfuncs, int isproto) -{ - Trait *t; - - t = zalloc(sizeof(Trait)); - t->uid = ntraittab++; - t->loc = loc; - if (t->uid < Ntraits) - t->vis = Visbuiltin; - t->vis = Visintern; - t->name = name; - t->param = param; - t->memb = memb; - t->nmemb = nmemb; - t->funcs = funcs; - t->nfuncs = nfuncs; - t->isproto = isproto; - - traittab = xrealloc(traittab, ntraittab*sizeof(Trait*)); - traittab[t->uid] = t; - return t; +Trait *mktrait(Srcloc loc, Node *name, Type *param, Node **memb, size_t nmemb, Node **funcs, + size_t nfuncs, int isproto) +{ + Trait *t; + + t = zalloc(sizeof(Trait)); + t->uid = ntraittab++; + t->loc = loc; + if (t->uid < Ntraits) + t->vis = Visbuiltin; + t->vis = Visintern; + t->name = name; + t->param = param; + t->memb = memb; + t->nmemb = nmemb; + t->funcs = funcs; + t->nfuncs = nfuncs; + t->isproto = isproto; + + traittab = xrealloc(traittab, ntraittab * sizeof(Trait *)); + traittab[t->uid] = t; + return t; } Type *mktyvar(Srcloc loc) { - Type *t; + Type *t; - t = mktype(loc, Tyvar); - return t; + t = mktype(loc, Tyvar); + return t; } Type *mktyparam(Srcloc loc, char *name) { - Type *t; + Type *t; - t = mktype(loc, Typaram); - t->pname = strdup(name); - return t; + t = mktype(loc, Typaram); + t->pname = strdup(name); + return t; } Type *mktyunres(Srcloc loc, Node *name, Type **arg, size_t narg) { - Type *t; + Type *t; - /* resolve it in the type inference stage */ - t = mktype(loc, Tyunres); - t->name = name; - t->arg = arg; - t->narg = narg; - return t; + /* resolve it in the type inference stage */ + t = mktype(loc, Tyunres); + t->name = name; + t->arg = arg; + t->narg = narg; + return t; } Type *mktygeneric(Srcloc loc, Node *name, Type **param, size_t nparam, Type *base) { - Type *t; + Type *t; - t = mktype(loc, Tygeneric); - t->name = name; - t->nsub = 1; - t->traits = bsdup(base->traits); - t->sub = xalloc(sizeof(Type*)); - t->sub[0] = base; - t->gparam = param; - t->ngparam = nparam; - return t; + t = mktype(loc, Tygeneric); + t->name = name; + t->nsub = 1; + t->traits = bsdup(base->traits); + t->sub = xalloc(sizeof(Type *)); + t->sub[0] = base; + t->gparam = param; + t->ngparam = nparam; + return t; } Type *mktyname(Srcloc loc, Node *name, Type *base) { - Type *t; + Type *t; - t = mktype(loc, Tyname); - t->name = name; - t->nsub = 1; - t->traits = bsdup(base->traits); - t->sub = xalloc(sizeof(Type*)); - t->sub[0] = base; - return t; + t = mktype(loc, Tyname); + t->name = name; + t->nsub = 1; + t->traits = bsdup(base->traits); + t->sub = xalloc(sizeof(Type *)); + t->sub[0] = base; + return t; } Type *mktyarray(Srcloc loc, Type *base, Node *sz) { - Type *t; + Type *t; - t = mktype(loc, Tyarray); - t->nsub = 1; - t->nmemb = 1; /* the size is a "member" */ - t->sub = xalloc(sizeof(Type*)); - t->sub[0] = base; - t->asize = sz; + t = mktype(loc, Tyarray); + t->nsub = 1; + t->nmemb = 1; /* the size is a "member" */ + t->sub = xalloc(sizeof(Type *)); + t->sub[0] = base; + t->asize = sz; - return t; + return t; } Type *mktyslice(Srcloc loc, Type *base) { - Type *t; + Type *t; - t = mktype(loc, Tyslice); - t->nsub = 1; - t->sub = xalloc(sizeof(Type*)); - t->sub[0] = base; - return t; + t = mktype(loc, Tyslice); + t->nsub = 1; + t->sub = xalloc(sizeof(Type *)); + t->sub[0] = base; + return t; } Type *mktyidxhack(Srcloc loc, Type *base) { - Type *t; + Type *t; - t = mktype(loc, Tyvar); - t->nsub = 1; - t->sub = xalloc(sizeof(Type*)); - t->sub[0] = base; - return t; + t = mktype(loc, Tyvar); + t->nsub = 1; + t->sub = xalloc(sizeof(Type *)); + t->sub[0] = base; + return t; } Type *mktyptr(Srcloc loc, Type *base) { - Type *t; + Type *t; - t = mktype(loc, Typtr); - t->nsub = 1; - t->sub = xalloc(sizeof(Type*)); - t->sub[0] = base; - return t; + t = mktype(loc, Typtr); + t->nsub = 1; + t->sub = xalloc(sizeof(Type *)); + t->sub[0] = base; + return t; } Type *mktytuple(Srcloc loc, Type **sub, size_t nsub) { - Type *t; - size_t i; + Type *t; + size_t i; - t = mktype(loc, Tytuple); - t->nsub = nsub; - t->sub = xalloc(nsub*sizeof(Type*)); - for (i = 0; i < nsub; i++) - t->sub[i] = sub[i]; - return t; + t = mktype(loc, Tytuple); + t->nsub = nsub; + t->sub = xalloc(nsub * sizeof(Type *)); + for (i = 0; i < nsub; i++) + t->sub[i] = sub[i]; + return t; } Type *mktyfunc(Srcloc loc, Node **args, size_t nargs, Type *ret) { - Type *t; - size_t i; + Type *t; + size_t i; - t = mktype(loc, Tyfunc); - t->nsub = nargs + 1; - t->sub = xalloc((1 + nargs)*sizeof(Type*)); - t->sub[0] = ret; - for (i = 0; i < nargs; i++) - t->sub[i + 1] = nodetype(args[i]); - return t; + t = mktype(loc, Tyfunc); + t->nsub = nargs + 1; + t->sub = xalloc((1 + nargs) * sizeof(Type *)); + t->sub[0] = ret; + for (i = 0; i < nargs; i++) + t->sub[i + 1] = nodetype(args[i]); + return t; } Type *mktystruct(Srcloc loc, Node **decls, size_t ndecls) { - Type *t; + Type *t; - t = mktype(loc, Tystruct); - t->nsub = 0; - t->nmemb = ndecls; - t->sdecls = memdup(decls, ndecls*sizeof(Node *)); - return t; + t = mktype(loc, Tystruct); + t->nsub = 0; + t->nmemb = ndecls; + t->sdecls = memdup(decls, ndecls * sizeof(Node *)); + return t; } Type *mktyunion(Srcloc loc, Ucon **decls, size_t ndecls) { - Type *t; + Type *t; - t = mktype(loc, Tyunion); - t->nmemb = ndecls; - t->udecls = decls; - return t; + t = mktype(loc, Tyunion); + t->nmemb = ndecls; + t->udecls = decls; + return t; } Ucon *finducon(Type *ty, Node *name) { - size_t i; + size_t i; - ty = tybase(ty); - for (i = 0; i < ty->nmemb; i++) - if (!strcmp(namestr(ty->udecls[i]->name), namestr(name))) - return ty->udecls[i]; - return NULL; + ty = tybase(ty); + for (i = 0; i < ty->nmemb; i++) + if (!strcmp(namestr(ty->udecls[i]->name), namestr(name))) + return ty->udecls[i]; + return NULL; } int istyunsigned(Type *t) { - switch (tybase(t)->type) { - case Tybyte: case Tyuint8: case Tyuint16: case Tyuint: - case Tychar: case Tyuint32: case Tyuint64: - case Typtr: case Tybool: - return 1; - default: - return 0; - } + switch (tybase(t)->type) { + case Tybyte: + case Tyuint8: + case Tyuint16: + case Tyuint: + case Tychar: + case Tyuint32: + case Tyuint64: + case Typtr: + case Tybool: return 1; + default: return 0; + } } int istysigned(Type *t) { - switch (tybase(t)->type) { - case Tyint8: case Tyint16: case Tyint: - case Tyint32: case Tyint64: - return 1; - default: - return 0; - } + switch (tybase(t)->type) { + case Tyint8: + case Tyint16: + case Tyint: + case Tyint32: + case Tyint64: return 1; + default: return 0; + } } int istyfloat(Type *t) { - t = tybase(t); - return t->type == Tyflt32 || t->type == Tyflt64; + t = tybase(t); + return t->type == Tyflt32 || t->type == Tyflt64; } -int istyprimitive(Type *t) -{ - return istysigned(t) || istyunsigned(t) || istyfloat(t); -} +int istyprimitive(Type *t) { return istysigned(t) || istyunsigned(t) || istyfloat(t); } /* * Checks if a type contains any type @@ -352,570 +350,553 @@ int istyprimitive(Type *t) */ int hasparamsrec(Type *t, Bitset *visited) { - size_t i; - - if (bshas(visited, t->tid)) - return 0; - bsput(visited, t->tid); - switch (t->type) { - case Typaram: - case Tygeneric: - return 1; - case Tyname: - for (i = 0; i < t->narg; i++) - if (hasparamsrec(t->arg[i], visited)) - return 1; - return hasparamsrec(t->sub[0], visited); - case Tyunres: - for (i = 0; i < t->narg; i++) - if (hasparamsrec(t->arg[i], visited)) - return 1; - break; - case Tystruct: - for (i = 0; i < t->nmemb; i++) - if (hasparamsrec(t->sdecls[i]->decl.type, visited)) - return 1; - break; - case Tyunion: - for (i = 0; i < t->nmemb; i++) - if (t->udecls[i]->etype && hasparamsrec(t->udecls[i]->etype, visited)) - return 1; - break; - default: - for (i = 0; i < t->nsub; i++) - if (hasparamsrec(t->sub[i], visited)) - return 1; - break; - } - return 0; + size_t i; + + if (bshas(visited, t->tid)) + return 0; + bsput(visited, t->tid); + switch (t->type) { + case Typaram: + case Tygeneric: return 1; + case Tyname: + for (i = 0; i < t->narg; i++) + if (hasparamsrec(t->arg[i], visited)) + return 1; + return hasparamsrec(t->sub[0], visited); + case Tyunres: + for (i = 0; i < t->narg; i++) + if (hasparamsrec(t->arg[i], visited)) + return 1; + break; + case Tystruct: + for (i = 0; i < t->nmemb; i++) + if (hasparamsrec(t->sdecls[i]->decl.type, visited)) + return 1; + break; + case Tyunion: + for (i = 0; i < t->nmemb; i++) + if (t->udecls[i]->etype && hasparamsrec(t->udecls[i]->etype, visited)) + return 1; + break; + default: + for (i = 0; i < t->nsub; i++) + if (hasparamsrec(t->sub[i], visited)) + return 1; + break; + } + return 0; } int hasparams(Type *t) { - Bitset *visited; - int r; + Bitset *visited; + int r; - visited = mkbs(); - r = hasparamsrec(t, visited); - bsfree(visited); - return r; + visited = mkbs(); + r = hasparamsrec(t, visited); + bsfree(visited); + return r; } Type *tybase(Type *t) { - assert(t != NULL); - while (t->type == Tyname || t->type == Tygeneric) - t = t->sub[0]; - return t; + assert(t != NULL); + while (t->type == Tyname || t->type == Tygeneric) + t = t->sub[0]; + return t; } - static int namefmt(char *buf, size_t len, Node *n) { - char *p; - char *end; + char *p; + char *end; - p = buf; - end = p + len; - if (n->name.ns) - p += bprintf(p, end - p, "%s.", n->name.ns); - p += bprintf(p, end - p, "%s", n->name.name); - return len - (end - p); + p = buf; + end = p + len; + if (n->name.ns) + p += bprintf(p, end - p, "%s.", n->name.ns); + p += bprintf(p, end - p, "%s", n->name.name); + return len - (end - p); } int settrait(Type *t, Trait *c) { - if (!t->traits) - t->traits = mkbs(); - bsput(t->traits, c->uid); - return 1; + if (!t->traits) + t->traits = mkbs(); + bsput(t->traits, c->uid); + return 1; } -int hastrait(Type *t, Trait *c) -{ - return t->traits && bshas(t->traits, c->uid); -} +int hastrait(Type *t, Trait *c) { return t->traits && bshas(t->traits, c->uid); } int traitfmt(char *buf, size_t len, Type *t) { - size_t i; - char *p; - char *end; - char *sep; + size_t i; + char *p; + char *end; + char *sep; - if (!t->traits || !bscount(t->traits)) - return 0; + if (!t->traits || !bscount(t->traits)) + return 0; - p = buf; - end = p + len; + p = buf; + end = p + len; - p += bprintf(p, end - p, " :: "); - sep = ""; - for (i = 0; i < ntraittab; i++) { - if (bshas(t->traits, i)) { - p += bprintf(p, end - p, "%s%s", sep, namestr(traittab[i]->name)); - sep = ","; - } - } - return p - buf; + p += bprintf(p, end - p, " :: "); + sep = ""; + for (i = 0; i < ntraittab; i++) { + if (bshas(t->traits, i)) { + p += bprintf(p, end - p, "%s%s", sep, namestr(traittab[i]->name)); + sep = ","; + } + } + return p - buf; } static int fmtstruct(char *buf, size_t len, Type *t) { - size_t i; - char *end, *p; - char *name, *ty; + size_t i; + char *end, *p; + char *name, *ty; - p = buf; - end = p + len; - p += bprintf(p, end - p, "struct\n"); - for (i = 0; i < t->nmemb; i++) { - name = declname(t->sdecls[i]); - ty = tystr(decltype(t->sdecls[i])); - p += bprintf(p, end - p, "\t%s:%s\n ", name, ty); - free(ty); - } - p += bprintf(p, end - p, ";;"); - return p - buf; + p = buf; + end = p + len; + p += bprintf(p, end - p, "struct\n"); + for (i = 0; i < t->nmemb; i++) { + name = declname(t->sdecls[i]); + ty = tystr(decltype(t->sdecls[i])); + p += bprintf(p, end - p, "\t%s:%s\n ", name, ty); + free(ty); + } + p += bprintf(p, end - p, ";;"); + return p - buf; } static int fmtunion(char *buf, size_t len, Type *t) { - size_t i; - char *end, *p; - char *name, *ty; - - p = buf; - end = p + len; - p += bprintf(p, end - p, "union\n"); - for (i = 0; i < t->nmemb; i++) { - name = namestr(t->udecls[i]->name); - if (t->udecls[i]->etype) { - ty = tystr(t->udecls[i]->etype); - p += bprintf(p, end - p, "\t`%s %s\n", name, ty); - free(ty); - } else { - p += bprintf(p, end - p, "\t`%s\n", name); - } - } - p += bprintf(p, end - p, ";;"); - return p - buf; + size_t i; + char *end, *p; + char *name, *ty; + + p = buf; + end = p + len; + p += bprintf(p, end - p, "union\n"); + for (i = 0; i < t->nmemb; i++) { + name = namestr(t->udecls[i]->name); + if (t->udecls[i]->etype) { + ty = tystr(t->udecls[i]->etype); + p += bprintf(p, end - p, "\t`%s %s\n", name, ty); + free(ty); + } + else { + p += bprintf(p, end - p, "\t`%s\n", name); + } + } + p += bprintf(p, end - p, ";;"); + return p - buf; } static int fmtlist(char *buf, size_t len, Type **arg, size_t narg) { - char *end, *p, *sep; - size_t i; + char *end, *p, *sep; + size_t i; - sep = ""; - p = buf; - end = p + len; - p += bprintf(p, end - p, "("); - for (i = 0; i < narg; i++) { - p += bprintf(p, end - p, "%s", sep); - p += tybfmt(p, end - p, arg[i]); - sep = ", "; - } - p += bprintf(p, end - p, ")"); - return p - buf; + sep = ""; + p = buf; + end = p + len; + p += bprintf(p, end - p, "("); + for (i = 0; i < narg; i++) { + p += bprintf(p, end - p, "%s", sep); + p += tybfmt(p, end - p, arg[i]); + sep = ", "; + } + p += bprintf(p, end - p, ")"); + return p - buf; } static int tybfmt(char *buf, size_t len, Type *t) { - size_t i; - char *p; - char *end; - char *sep; - - sep = ""; - p = buf; - end = p + len; - if (!t) { - p += bprintf(p, end - p, "tynil"); - return len - (end - p); - } - switch (t->type) { - case Tybad: p += bprintf(p, end - p, "BAD"); break; - case Tyvoid: p += bprintf(p, end - p, "void"); break; - case Tybool: p += bprintf(p, end - p, "bool"); break; - case Tychar: p += bprintf(p, end - p, "char"); break; - case Tyint8: p += bprintf(p, end - p, "int8"); break; - case Tyint16: p += bprintf(p, end - p, "int16"); break; - case Tyint: p += bprintf(p, end - p, "int"); break; - case Tyint32: p += bprintf(p, end - p, "int32"); break; - case Tyint64: p += bprintf(p, end - p, "int64"); break; - case Tybyte: p += bprintf(p, end - p, "byte"); break; - case Tyuint8: p += bprintf(p, end - p, "uint8"); break; - case Tyuint16: p += bprintf(p, end - p, "uint16"); break; - case Tyuint: p += bprintf(p, end - p, "uint"); break; - case Tyuint32: p += bprintf(p, end - p, "uint32"); break; - case Tyuint64: p += bprintf(p, end - p, "uint64"); break; - case Tyflt32: p += bprintf(p, end - p, "flt32"); break; - case Tyflt64: p += bprintf(p, end - p, "flt64"); break; - case Tyvalist: p += bprintf(p, end - p, "..."); break; - - case Typtr: - p += tybfmt(p, end - p, t->sub[0]); - p += bprintf(p, end - p, "#"); - break; - case Tyslice: - p += tybfmt(p, end - p, t->sub[0]); - p += bprintf(p, end - p, "[:]"); - break; - case Tyarray: - p += tybfmt(p, end - p, t->sub[0]); - if (t->asize) { - i = t->asize->expr.args[0]->lit.intval; - p += bprintf(p, end - p, "[%zd]", i); - } else { - p += bprintf(p, end - p, "[]"); - } - break; - case Tycode: - case Tyfunc: - p += bprintf(p, end - p, "("); - for (i = 1; i < t->nsub; i++) { - p += bprintf(p, end - p, "%s", sep); - p += tybfmt(p, end - p, t->sub[i]); - sep = ", "; - } - p += bprintf(p, end - p, " -> "); - p += tybfmt(p, end - p, t->sub[0]); - p += bprintf(p, end - p, ")"); - break; - case Tytuple: - p += bprintf(p, end - p, "("); - for (i = 0; i < t->nsub; i++) { - p += bprintf(p, end - p, "%s", sep); - p += tybfmt(p, end - p, t->sub[i]); - sep = ","; - } - p += bprintf(p, end - p, ")"); - break; - case Tyvar: - p += bprintf(p, end - p, "$%d", t->tid); - if (t->nsub) { - p += bprintf(p, end - p, "("); - for (i = 0; i < t->nsub; i++) { - p += bprintf(p, end - p, "%s", sep); - p += tybfmt(p, end - p, t->sub[i]); - sep = ", "; - } - p += bprintf(p, end - p, ")[]"); - } - break; - case Typaram: - p += bprintf(p, end - p, "@%s", t->pname); - break; - case Tyunres: - p += namefmt(p, end - p, t->name); - if (t->narg) - p += fmtlist(p, end - p, t->arg, t->narg); - break; - case Tyname: - if (t->name->name.ns) - p += bprintf(p, end - p, "%s.", t->name->name.ns); - p += bprintf(p, end - p, "%s", namestr(t->name)); - if (t->narg) - p += fmtlist(p, end - p, t->arg, t->narg); - break; - case Tygeneric: - if (t->name->name.ns) - p += bprintf(p, end - p, "%s.", t->name->name.ns); - p += bprintf(p, end - p, "%s", namestr(t->name)); - if (t->ngparam) - p += fmtlist(p, end - p, t->gparam, t->ngparam); - break; - case Tystruct: p += fmtstruct(p, end - p, t); break; - case Tyunion: p += fmtunion(p, end - p, t); break; - case Ntypes: - die("Ntypes is not a type"); - break; - } - - /* we only show constraints on non-builtin typaram */ - if (t->type == Tyvar || t->type == Typaram) - p += traitfmt(p, end - p, t); - - return p - buf; + size_t i; + char *p; + char *end; + char *sep; + + sep = ""; + p = buf; + end = p + len; + if (!t) { + p += bprintf(p, end - p, "tynil"); + return len - (end - p); + } + switch (t->type) { + case Tybad: p += bprintf(p, end - p, "BAD"); break; + case Tyvoid: p += bprintf(p, end - p, "void"); break; + case Tybool: p += bprintf(p, end - p, "bool"); break; + case Tychar: p += bprintf(p, end - p, "char"); break; + case Tyint8: p += bprintf(p, end - p, "int8"); break; + case Tyint16: p += bprintf(p, end - p, "int16"); break; + case Tyint: p += bprintf(p, end - p, "int"); break; + case Tyint32: p += bprintf(p, end - p, "int32"); break; + case Tyint64: p += bprintf(p, end - p, "int64"); break; + case Tybyte: p += bprintf(p, end - p, "byte"); break; + case Tyuint8: p += bprintf(p, end - p, "uint8"); break; + case Tyuint16: p += bprintf(p, end - p, "uint16"); break; + case Tyuint: p += bprintf(p, end - p, "uint"); break; + case Tyuint32: p += bprintf(p, end - p, "uint32"); break; + case Tyuint64: p += bprintf(p, end - p, "uint64"); break; + case Tyflt32: p += bprintf(p, end - p, "flt32"); break; + case Tyflt64: p += bprintf(p, end - p, "flt64"); break; + case Tyvalist: p += bprintf(p, end - p, "..."); break; + + case Typtr: + p += tybfmt(p, end - p, t->sub[0]); + p += bprintf(p, end - p, "#"); + break; + case Tyslice: + p += tybfmt(p, end - p, t->sub[0]); + p += bprintf(p, end - p, "[:]"); + break; + case Tyarray: + p += tybfmt(p, end - p, t->sub[0]); + if (t->asize) { + i = t->asize->expr.args[0]->lit.intval; + p += bprintf(p, end - p, "[%zd]", i); + } + else { + p += bprintf(p, end - p, "[]"); + } + break; + case Tycode: + case Tyfunc: + p += bprintf(p, end - p, "("); + for (i = 1; i < t->nsub; i++) { + p += bprintf(p, end - p, "%s", sep); + p += tybfmt(p, end - p, t->sub[i]); + sep = ", "; + } + p += bprintf(p, end - p, " -> "); + p += tybfmt(p, end - p, t->sub[0]); + p += bprintf(p, end - p, ")"); + break; + case Tytuple: + p += bprintf(p, end - p, "("); + for (i = 0; i < t->nsub; i++) { + p += bprintf(p, end - p, "%s", sep); + p += tybfmt(p, end - p, t->sub[i]); + sep = ","; + } + p += bprintf(p, end - p, ")"); + break; + case Tyvar: + p += bprintf(p, end - p, "$%d", t->tid); + if (t->nsub) { + p += bprintf(p, end - p, "("); + for (i = 0; i < t->nsub; i++) { + p += bprintf(p, end - p, "%s", sep); + p += tybfmt(p, end - p, t->sub[i]); + sep = ", "; + } + p += bprintf(p, end - p, ")[]"); + } + break; + case Typaram: p += bprintf(p, end - p, "@%s", t->pname); break; + case Tyunres: + p += namefmt(p, end - p, t->name); + if (t->narg) + p += fmtlist(p, end - p, t->arg, t->narg); + break; + case Tyname: + if (t->name->name.ns) + p += bprintf(p, end - p, "%s.", t->name->name.ns); + p += bprintf(p, end - p, "%s", namestr(t->name)); + if (t->narg) + p += fmtlist(p, end - p, t->arg, t->narg); + break; + case Tygeneric: + if (t->name->name.ns) + p += bprintf(p, end - p, "%s.", t->name->name.ns); + p += bprintf(p, end - p, "%s", namestr(t->name)); + if (t->ngparam) + p += fmtlist(p, end - p, t->gparam, t->ngparam); + break; + case Tystruct: p += fmtstruct(p, end - p, t); break; + case Tyunion: p += fmtunion(p, end - p, t); break; + case Ntypes: die("Ntypes is not a type"); break; + } + + /* we only show constraints on non-builtin typaram */ + if (t->type == Tyvar || t->type == Typaram) + p += traitfmt(p, end - p, t); + + return p - buf; } char *tyfmt(char *buf, size_t len, Type *t) { - tybfmt(buf, len, t); - return buf; + tybfmt(buf, len, t); + return buf; } char *traitstr(Type *t) { - char buf[1024]; - traitfmt(buf, 1024, t); - return strdup(buf); + char buf[1024]; + traitfmt(buf, 1024, t); + return strdup(buf); } char *tystr(Type *t) { - char buf[1024]; - tyfmt(buf, 1024, t); - return strdup(buf); + char buf[1024]; + tyfmt(buf, 1024, t); + return strdup(buf); } ulong tyhash(void *ty) { - size_t i; - Type *t; - ulong hash; - - t = (Type *)ty; - switch (t->type) { - /* Important: we want tyhash to be consistent cross-file, since it - * is used in naming trait impls and such. - * - * We should find a better name. - */ - case Tyvar: hash = inthash(t->tid); break; - case Typaram: hash = strhash(t->pname); break; - case Tyunion: hash = inthash(t->type); break; - case Tystruct: hash = inthash(t->type); break; - case Tyname: hash = namehash(t->name); break; - default: hash = inthash(t->type); break; - } - - for (i = 0; i < t->narg; i++) - hash ^= tyhash(t->arg[i]); - return hash; + size_t i; + Type *t; + ulong hash; + + t = (Type *)ty; + switch (t->type) { + /* Important: we want tyhash to be consistent cross-file, since it + * is used in naming trait impls and such. + * + * We should find a better name. + */ + case Tyvar: hash = inthash(t->tid); break; + case Typaram: hash = strhash(t->pname); break; + case Tyunion: hash = inthash(t->type); break; + case Tystruct: hash = inthash(t->type); break; + case Tyname: hash = namehash(t->name); break; + default: hash = inthash(t->type); break; + } + + for (i = 0; i < t->narg; i++) + hash ^= tyhash(t->arg[i]); + return hash; } int tyeq_rec(Type *a, Type *b, Bitset *visited) { - size_t i; - - if (!a || !b) - return a == b; - if (a->type != b->type) - return 0; - if (a->narg != b->narg) - return 0; - if (a->nsub != b->nsub) - return 0; - if (a->nmemb != b->nmemb) - return 0; - - if (a->tid == b->tid) - return 1; - if (bshas(visited, a->tid) || bshas(visited, b->tid)) - return 1; - - bsput(visited, a->tid); - bsput(visited, b->tid); - - switch (a->type) { - case Typaram: - return streq(a->pname, b->pname); - break; - case Tyvar: - if (a->tid != b->tid) - return 0; - break; - case Tyunres: - if (!nameeq(a->name, b->name)) - return 0; - case Tyunion: - for (i = 0; i < a->nmemb; i++) { - if (!nameeq(a->udecls[i]->name, b->udecls[i]->name)) - return 0; - if (!tyeq_rec(a->udecls[i]->etype, b->udecls[i]->etype, visited)) - return 0; - } - break; - case Tystruct: - for (i = 0; i < a->nmemb; i++) { - if (strcmp(declname(a->sdecls[i]), declname(b->sdecls[i])) != 0) - return 0; - if (!tyeq_rec(decltype(a->sdecls[i]), decltype(b->sdecls[i]), visited)) - return 0; - } - break; - case Tyname: - if (!nameeq(a->name, b->name)) - return 0; - for (i = 0; i < a->narg; i++) - if (!tyeq_rec(a->arg[i], b->arg[i], visited)) - return 0; - for (i = 0; i < a->nsub; i++) - if (!tyeq_rec(a->sub[i], b->sub[i], visited)) - return 0; - break; - case Tyarray: - if (arraysz(a->asize) != arraysz(b->asize)) - return 0; - break; - default: - break; - } - for (i = 0; i < a->nsub; i++) - if (!tyeq_rec(a->sub[i], b->sub[i], visited)) - return 0; - return 1; + size_t i; + + if (!a || !b) + return a == b; + if (a->type != b->type) + return 0; + if (a->narg != b->narg) + return 0; + if (a->nsub != b->nsub) + return 0; + if (a->nmemb != b->nmemb) + return 0; + + if (a->tid == b->tid) + return 1; + if (bshas(visited, a->tid) || bshas(visited, b->tid)) + return 1; + + bsput(visited, a->tid); + bsput(visited, b->tid); + + switch (a->type) { + case Typaram: return streq(a->pname, b->pname); break; + case Tyvar: + if (a->tid != b->tid) + return 0; + break; + case Tyunres: + if (!nameeq(a->name, b->name)) + return 0; + case Tyunion: + for (i = 0; i < a->nmemb; i++) { + if (!nameeq(a->udecls[i]->name, b->udecls[i]->name)) + return 0; + if (!tyeq_rec(a->udecls[i]->etype, b->udecls[i]->etype, visited)) + return 0; + } + break; + case Tystruct: + for (i = 0; i < a->nmemb; i++) { + if (strcmp(declname(a->sdecls[i]), declname(b->sdecls[i])) != 0) + return 0; + if (!tyeq_rec(decltype(a->sdecls[i]), decltype(b->sdecls[i]), visited)) + return 0; + } + break; + case Tyname: + if (!nameeq(a->name, b->name)) + return 0; + for (i = 0; i < a->narg; i++) + if (!tyeq_rec(a->arg[i], b->arg[i], visited)) + return 0; + for (i = 0; i < a->nsub; i++) + if (!tyeq_rec(a->sub[i], b->sub[i], visited)) + return 0; + break; + case Tyarray: + if (arraysz(a->asize) != arraysz(b->asize)) + return 0; + break; + default: break; + } + for (i = 0; i < a->nsub; i++) + if (!tyeq_rec(a->sub[i], b->sub[i], visited)) + return 0; + return 1; } int tyeq(void *a, void *b) { - Bitset *bs; - int eq; + Bitset *bs; + int eq; - if (a == b) - return 1; - bs = mkbs(); - eq = tyeq_rec(a, b, bs); - bsfree(bs); - return eq; + if (a == b) + return 1; + bs = mkbs(); + eq = tyeq_rec(a, b, bs); + bsfree(bs); + return eq; } size_t tyidfmt(char *buf, size_t sz, Type *ty) { - size_t i; - char *p, *end; - - p = buf; - end = buf + sz; - switch (ty->type) { - case Ntypes: - case Tybad: die("invalid type"); break; - case Tyvar: die("tyvar has no idstr"); break; - case Tyvoid: p += bprintf(p, end - p, "v"); break; - case Tychar: p += bprintf(p, end - p, "c"); break; - case Tybool: p += bprintf(p, end - p, "t"); break; - case Tyint8: p += bprintf(p, end - p, "b"); break; - case Tyint16: p += bprintf(p, end - p, "s"); break; - case Tyint: p += bprintf(p, end - p, "i"); break; - case Tyint32: p += bprintf(p, end - p, "w"); break; - case Tyint64: p += bprintf(p, end - p, "q"); break; - - case Tybyte: p += bprintf(p, end - p, "H"); break; - case Tyuint8: p += bprintf(p, end - p, "B"); break; - case Tyuint16: p += bprintf(p, end - p, "S"); break; - case Tyuint: p += bprintf(p, end - p, "I"); break; - case Tyuint32: p += bprintf(p, end - p, "W"); break; - case Tyuint64: p += bprintf(p, end - p, "Q"); break; - case Tyflt32: p += bprintf(p, end - p, "f"); break; - case Tyflt64: p += bprintf(p, end - p, "d"); break; - case Tyvalist: p += bprintf(p, end - p, "V"); break; - case Typtr: - p += bprintf(p, end - p, "$p"); - p += tyidfmt(p, end - p, ty->sub[0]); - break; - case Tyarray: - p += bprintf(p, end - p, "$a%lld", (vlong)arraysz(ty->asize)); - p += tyidfmt(p, end - p, ty->sub[0]); - break; - case Tyslice: - p += bprintf(p, end - p, "$s"); - p += tyidfmt(p, end - p, ty->sub[0]); - break; - case Tycode: - p += bprintf(p, end - p, "$F"); - for (i = 0; i < ty->nsub; i++) { - p += tyidfmt(p, end - p, ty->sub[i]); - p += bprintf(p, end - p, "$"); - } - break; - case Tyfunc: - p += bprintf(p, end - p, "$f"); - for (i = 0; i < ty->nsub; i++) { - p += tyidfmt(p, end - p, ty->sub[i]); - p += bprintf(p, end - p, "$"); - } - break; - case Tytuple: - p += bprintf(p, end - p, "$e"); - for (i = 0; i < ty->nsub; i++) { - p += tyidfmt(p, end - p, ty->sub[i]); - } - p += bprintf(p, end - p, "$"); - break; - case Tystruct: - p += bprintf(p, end - p, "$t%lld", ty->tid); - break; - case Tyunion: - p += bprintf(p, end - p, "$u%lld", ty->tid); - break; - case Typaram: - p += bprintf(p, end - p, "$r%s", ty->pname); - break; - case Tyunres: - case Tyname: - p += bprintf(p, end - p, "$n"); - if (ty->name->name.ns) - p += bprintf(p, end - p, "%s", ty->name->name.ns); - p += bprintf(p, end - p, "$%s", ty->name->name.name); - if (ty->arg) - for (i = 0; i < ty->narg; i++) - p += tyidfmt(p, end - p, ty->arg[i]); - else if (ty->gparam) - for (i = 0; i < ty->ngparam; i++) - p += tyidfmt(p, end - p, ty->gparam[i]); - break; - case Tygeneric: - break; - } - return p - buf; + size_t i; + char *p, *end; + + p = buf; + end = buf + sz; + switch (ty->type) { + case Ntypes: + case Tybad: die("invalid type"); break; + case Tyvar: die("tyvar has no idstr"); break; + case Tyvoid: p += bprintf(p, end - p, "v"); break; + case Tychar: p += bprintf(p, end - p, "c"); break; + case Tybool: p += bprintf(p, end - p, "t"); break; + case Tyint8: p += bprintf(p, end - p, "b"); break; + case Tyint16: p += bprintf(p, end - p, "s"); break; + case Tyint: p += bprintf(p, end - p, "i"); break; + case Tyint32: p += bprintf(p, end - p, "w"); break; + case Tyint64: p += bprintf(p, end - p, "q"); break; + + case Tybyte: p += bprintf(p, end - p, "H"); break; + case Tyuint8: p += bprintf(p, end - p, "B"); break; + case Tyuint16: p += bprintf(p, end - p, "S"); break; + case Tyuint: p += bprintf(p, end - p, "I"); break; + case Tyuint32: p += bprintf(p, end - p, "W"); break; + case Tyuint64: p += bprintf(p, end - p, "Q"); break; + case Tyflt32: p += bprintf(p, end - p, "f"); break; + case Tyflt64: p += bprintf(p, end - p, "d"); break; + case Tyvalist: p += bprintf(p, end - p, "V"); break; + case Typtr: + p += bprintf(p, end - p, "$p"); + p += tyidfmt(p, end - p, ty->sub[0]); + break; + case Tyarray: + p += bprintf(p, end - p, "$a%lld", (vlong)arraysz(ty->asize)); + p += tyidfmt(p, end - p, ty->sub[0]); + break; + case Tyslice: + p += bprintf(p, end - p, "$s"); + p += tyidfmt(p, end - p, ty->sub[0]); + break; + case Tycode: + p += bprintf(p, end - p, "$F"); + for (i = 0; i < ty->nsub; i++) { + p += tyidfmt(p, end - p, ty->sub[i]); + p += bprintf(p, end - p, "$"); + } + break; + case Tyfunc: + p += bprintf(p, end - p, "$f"); + for (i = 0; i < ty->nsub; i++) { + p += tyidfmt(p, end - p, ty->sub[i]); + p += bprintf(p, end - p, "$"); + } + break; + case Tytuple: + p += bprintf(p, end - p, "$e"); + for (i = 0; i < ty->nsub; i++) { + p += tyidfmt(p, end - p, ty->sub[i]); + } + p += bprintf(p, end - p, "$"); + break; + case Tystruct: p += bprintf(p, end - p, "$t%lld", ty->tid); break; + case Tyunion: p += bprintf(p, end - p, "$u%lld", ty->tid); break; + case Typaram: p += bprintf(p, end - p, "$r%s", ty->pname); break; + case Tyunres: + case Tyname: + p += bprintf(p, end - p, "$n"); + if (ty->name->name.ns) + p += bprintf(p, end - p, "%s", ty->name->name.ns); + p += bprintf(p, end - p, "$%s", ty->name->name.name); + if (ty->arg) + for (i = 0; i < ty->narg; i++) + p += tyidfmt(p, end - p, ty->arg[i]); + else if (ty->gparam) + for (i = 0; i < ty->ngparam; i++) + p += tyidfmt(p, end - p, ty->gparam[i]); + break; + case Tygeneric: + break; + } + return p - buf; } void tyinit(Stab *st) { - int i; - Type *ty; + int i; + Type *ty; -/* this must be done after all the types are created, otherwise we will - * clobber the memoized bunch of types with the type params. */ -#define Tc(c, n) \ - mktrait(Zloc, mkname(Zloc, n), NULL, NULL, 0, NULL, 0, 0); + /* this must be done after all the types are created, otherwise we will + * clobber the memoized bunch of types with the type params. */ +#define Tc(c, n) mktrait(Zloc, mkname(Zloc, n), NULL, NULL, 0, NULL, 0, 0); #include "trait.def" #undef Tc - /* char::(numeric,integral) */ - traits[Tychar][0] = traittab[Tcnum]; - traits[Tychar][1] = traittab[Tcint]; - - traits[Tybyte][0] = traittab[Tcnum]; - traits[Tybyte][1] = traittab[Tcint]; - - /* ::(numeric,integral) */ - for (i = Tyint8; i < Tyflt32; i++) { - traits[i][0] = traittab[Tcnum]; - traits[i][1] = traittab[Tcint]; - } - - /* ::(numeric,floating) */ - traits[Tyflt32][0] = traittab[Tcnum]; - traits[Tyflt32][1] = traittab[Tcfloat]; - traits[Tyflt64][0] = traittab[Tcnum]; - traits[Tyflt64][1] = traittab[Tcfloat]; - - /* @a*::(sliceable) */ - traits[Typtr][0] = traittab[Tcslice]; - - /* @a[:]::(indexable,sliceable) */ - traits[Tyslice][0] = traittab[Tcslice]; - traits[Tyslice][1] = traittab[Tcidx]; - - /* @a[SZ]::(indexable,sliceable) */ - traits[Tyarray][0] = traittab[Tcidx]; - traits[Tyarray][1] = traittab[Tcslice]; - - /* @a::function */ - traits[Tyfunc][0] = traittab[Tcfunc]; - -/* Definining and registering the types has to go after we define the - * constraints, otherwise they will have no constraints set on them. */ -#define Ty(t, n, stk) \ - if (t != Ntypes) {\ - ty = mktype(Zloc, t); \ - if (n) { \ - puttype(st, mkname(Zloc, n), ty); \ - } \ - } + /* char::(numeric,integral) */ + traits[Tychar][0] = traittab[Tcnum]; + traits[Tychar][1] = traittab[Tcint]; + + traits[Tybyte][0] = traittab[Tcnum]; + traits[Tybyte][1] = traittab[Tcint]; + + /* ::(numeric,integral) */ + for (i = Tyint8; i < Tyflt32; i++) { + traits[i][0] = traittab[Tcnum]; + traits[i][1] = traittab[Tcint]; + } + + /* ::(numeric,floating) */ + traits[Tyflt32][0] = traittab[Tcnum]; + traits[Tyflt32][1] = traittab[Tcfloat]; + traits[Tyflt64][0] = traittab[Tcnum]; + traits[Tyflt64][1] = traittab[Tcfloat]; + + /* @a*::(sliceable) */ + traits[Typtr][0] = traittab[Tcslice]; + + /* @a[:]::(indexable,sliceable) */ + traits[Tyslice][0] = traittab[Tcslice]; + traits[Tyslice][1] = traittab[Tcidx]; + + /* @a[SZ]::(indexable,sliceable) */ + traits[Tyarray][0] = traittab[Tcidx]; + traits[Tyarray][1] = traittab[Tcslice]; + + /* @a::function */ + traits[Tyfunc][0] = traittab[Tcfunc]; + + /* Definining and registering the types has to go after we define the + * constraints, otherwise they will have no constraints set on them. */ +#define Ty(t, n, stk) \ + if (t != Ntypes) { \ + ty = mktype(Zloc, t); \ + if (n) { \ + puttype(st, mkname(Zloc, n), ty); \ + } \ + } #include "types.def" #undef Ty } diff --git a/parse/use.c b/parse/use.c index a5cbe46..88ac64a 100644 --- a/parse/use.c +++ b/parse/use.c @@ -22,35 +22,34 @@ static void pickle(FILE *fd, Node *n); static Node *unpickle(FILE *fd); /* type fixup list */ -static Htab *tydedup; /* map from name -> type, contains all Tynames loaded ever */ -static Htab *tidmap; /* map from tid -> type */ -static Htab *trmap; /* map from trait id -> trait */ -static Htab *initmap; /* map from init name -> int */ +static Htab *tydedup; /* map from name -> type, contains all Tynames loaded ever */ +static Htab *tidmap; /* map from tid -> type */ +static Htab *trmap; /* map from trait id -> trait */ +static Htab *initmap; /* map from init name -> int */ #define Builtinmask (1 << 30) -static Type ***typefixdest; /* list of types we need to replace */ -static size_t ntypefixdest; /* size of replacement list */ -static intptr_t *typefixid; /* list of types we need to replace */ -static size_t ntypefixid; /* size of replacement list */ - -static Trait ***traitfixdest; /* list of traits we need to replace */ -static size_t ntraitfixdest; /* size of replacement list */ -static Type **traitfixtype; /* list of types we need to set the trait on */ -static size_t ntraitfixtype; /* size of replacement list */ -static intptr_t *traitfixid; /* list of traits we need to replace */ -static size_t ntraitfixid; /* size of replacement list */ - +static Type ***typefixdest; /* list of types we need to replace */ +static size_t ntypefixdest; /* size of replacement list */ +static intptr_t *typefixid; /* list of types we need to replace */ +static size_t ntypefixid; /* size of replacement list */ + +static Trait ***traitfixdest; /* list of traits we need to replace */ +static size_t ntraitfixdest; /* size of replacement list */ +static Type **traitfixtype; /* list of types we need to set the trait on */ +static size_t ntraitfixtype; /* size of replacement list */ +static intptr_t *traitfixid; /* list of traits we need to replace */ +static size_t ntraitfixid; /* size of replacement list */ void addextlibs(Node *file, char **libs, size_t nlibs) { - size_t i, j; - - for (i = 0; i < nlibs; i++) { - for (j = 0; j < file->file.nextlibs; j++) - if (!strcmp(file->file.extlibs[j], libs[i])) - continue; - lappend(&file->file.extlibs, &file->file.nextlibs, libs[i]); - } + size_t i, j; + + for (i = 0; i < nlibs; i++) { + for (j = 0; j < file->file.nextlibs; j++) + if (!strcmp(file->file.extlibs[j], libs[i])) + continue; + lappend(&file->file.extlibs, &file->file.nextlibs, libs[i]); + } } /* Outputs a symbol table to file in a way that can be @@ -58,89 +57,88 @@ void addextlibs(Node *file, char **libs, size_t nlibs) * and sub-namespaces. Captured variables are ommitted. */ static void wrstab(FILE *fd, Stab *val) { - size_t n, i; - void **keys; - - wrstr(fd, val->name); - - /* write decls */ - keys = htkeys(val->dcl, &n); - wrint(fd, n); - for (i = 0; i < n; i++) - wrsym(fd, getdcl(val, keys[i])); - free(keys); - - /* write types */ - keys = htkeys(val->ty, &n); - wrint(fd, n); - for (i = 0; i < n; i++) { - pickle(fd, keys[i]); /* name */ - wrtype(fd, gettype(val, keys[i])); /* type */ - } - free(keys); - + size_t n, i; + void **keys; + + wrstr(fd, val->name); + + /* write decls */ + keys = htkeys(val->dcl, &n); + wrint(fd, n); + for (i = 0; i < n; i++) + wrsym(fd, getdcl(val, keys[i])); + free(keys); + + /* write types */ + keys = htkeys(val->ty, &n); + wrint(fd, n); + for (i = 0; i < n; i++) { + pickle(fd, keys[i]); /* name */ + wrtype(fd, gettype(val, keys[i])); /* type */ + } + free(keys); } /* Reads a symbol table from file. The converse * of wrstab. */ static Stab *rdstab(FILE *fd, int isfunc) { - Stab *st; - Type *ty; - Node *nm; - int n; - int i; - - /* read dcls */ - st = mkstab(isfunc); - st->name = rdstr(fd); - n = rdint(fd); - for (i = 0; i < n; i++) - putdcl(st, rdsym(fd, NULL)); - - /* read types */ - n = rdint(fd); - for (i = 0; i < n; i++) { - nm = unpickle(fd); - rdtype(fd, &ty); - puttype(st, nm, ty); - } - return st; + Stab *st; + Type *ty; + Node *nm; + int n; + int i; + + /* read dcls */ + st = mkstab(isfunc); + st->name = rdstr(fd); + n = rdint(fd); + for (i = 0; i < n; i++) + putdcl(st, rdsym(fd, NULL)); + + /* read types */ + n = rdint(fd); + for (i = 0; i < n; i++) { + nm = unpickle(fd); + rdtype(fd, &ty); + puttype(st, nm, ty); + } + return st; } static void wrucon(FILE *fd, Ucon *uc) { - wrint(fd, uc->loc.line); - wrint(fd, uc->id); - wrbool(fd, uc->synth); - pickle(fd, uc->name); - wrbool(fd, uc->etype != NULL); - if (uc->etype) - wrtype(fd, uc->etype); + wrint(fd, uc->loc.line); + wrint(fd, uc->id); + wrbool(fd, uc->synth); + pickle(fd, uc->name); + wrbool(fd, uc->etype != NULL); + if (uc->etype) + wrtype(fd, uc->etype); } static Ucon *rducon(FILE *fd, Type *ut) { - Type *et; - Node *name; - Ucon *uc; - size_t id; - int line; - int synth; - - et = NULL; - line = rdint(fd); - id = rdint(fd); - synth = rdbool(fd); - name = unpickle(fd); - uc = mkucon(Zloc, name, ut, et); - uc->loc.line = line; - uc->loc.file = file->file.nfiles - 1; - if (rdbool(fd)) - rdtype(fd, &uc->etype); - uc->id = id; - uc->synth = synth; - return uc; + Type *et; + Node *name; + Ucon *uc; + size_t id; + int line; + int synth; + + et = NULL; + line = rdint(fd); + id = rdint(fd); + synth = rdbool(fd); + name = unpickle(fd); + uc = mkucon(Zloc, name, ut, et); + uc->loc.line = line; + uc->loc.file = file->file.nfiles - 1; + if (rdbool(fd)) + rdtype(fd, &uc->etype); + uc->id = id; + uc->synth = synth; + return uc; } /* Writes the name and type of a variable, @@ -149,52 +147,52 @@ static Ucon *rducon(FILE *fd, Type *ut) * the only cross-file inline is generics) */ static void wrsym(FILE *fd, Node *val) { - /* sym */ - wrint(fd, val->loc.line); - pickle(fd, val->decl.name); - wrtype(fd, val->decl.type); - - /* symflags */ - wrint(fd, val->decl.vis); - wrbool(fd, val->decl.isconst); - wrbool(fd, val->decl.isgeneric); - wrbool(fd, val->decl.isextern); - wrbool(fd, val->decl.ispkglocal); - wrbool(fd, val->decl.isnoret); - wrbool(fd, val->decl.isexportinit); - wrbool(fd, val->decl.isinit); - if (val->decl.isexportinit) { - pickle(fd, val->decl.init); - } + /* sym */ + wrint(fd, val->loc.line); + pickle(fd, val->decl.name); + wrtype(fd, val->decl.type); + + /* symflags */ + wrint(fd, val->decl.vis); + wrbool(fd, val->decl.isconst); + wrbool(fd, val->decl.isgeneric); + wrbool(fd, val->decl.isextern); + wrbool(fd, val->decl.ispkglocal); + wrbool(fd, val->decl.isnoret); + wrbool(fd, val->decl.isexportinit); + wrbool(fd, val->decl.isinit); + if (val->decl.isexportinit) { + pickle(fd, val->decl.init); + } } static Node *rdsym(FILE *fd, Trait *ctx) { - int line; - Node *name; - Node *n; - - line = rdint(fd); - name = unpickle(fd); - n = mkdecl(Zloc, name, NULL); - n->loc.line = line; - n->loc.file = file->file.nfiles - 1; - rdtype(fd, &n->decl.type); - - if (rdint(fd) == Vishidden) - n->decl.ishidden = 1; - n->decl.trait = ctx; - n->decl.isconst = rdbool(fd); - n->decl.isgeneric = rdbool(fd); - n->decl.isextern = rdbool(fd); - n->decl.ispkglocal = rdbool(fd); - n->decl.isnoret = rdbool(fd); - n->decl.isimport = 1; - n->decl.isexportinit = rdbool(fd); - n->decl.isinit = rdbool(fd); - if (n->decl.isexportinit) - n->decl.init = unpickle(fd); - return n; + int line; + Node *name; + Node *n; + + line = rdint(fd); + name = unpickle(fd); + n = mkdecl(Zloc, name, NULL); + n->loc.line = line; + n->loc.file = file->file.nfiles - 1; + rdtype(fd, &n->decl.type); + + if (rdint(fd) == Vishidden) + n->decl.ishidden = 1; + n->decl.trait = ctx; + n->decl.isconst = rdbool(fd); + n->decl.isgeneric = rdbool(fd); + n->decl.isextern = rdbool(fd); + n->decl.ispkglocal = rdbool(fd); + n->decl.isnoret = rdbool(fd); + n->decl.isimport = 1; + n->decl.isexportinit = rdbool(fd); + n->decl.isinit = rdbool(fd); + if (n->decl.isexportinit) + n->decl.init = unpickle(fd); + return n; } /* Writes types to a file. Errors on @@ -202,134 +200,129 @@ static Node *rdsym(FILE *fd, Trait *ctx) * will not be meaningful in another file*/ static void typickle(FILE *fd, Type *ty) { - size_t i; - - if (!ty) { - die("trying to pickle null type\n"); - return; - } - wrbyte(fd, ty->type); - wrbyte(fd, ty->vis); - /* tid is generated; don't write */ - /* FIXME: since we only support hardcoded traits, we just write - * out the set of them. we should write out the trait list as - * well */ - if (!ty->traits) { - wrint(fd, 0); - } else { - wrint(fd, bscount(ty->traits)); - for (i = 0; bsiter(ty->traits, &i); i++) { - if (i < Ntraits) - wrint(fd, i | Builtinmask); - else - wrint(fd, i); - } - } - wrint(fd, ty->nsub); - switch (ty->type) { - case Tyunres: - pickle(fd, ty->name); - break; - case Typaram: - wrstr(fd, ty->pname); - break; - case Tystruct: - wrint(fd, ty->nmemb); - for (i = 0; i < ty->nmemb; i++) - pickle(fd, ty->sdecls[i]); - break; - case Tyunion: - wrint(fd, ty->nmemb); - for (i = 0; i < ty->nmemb; i++) - wrucon(fd, ty->udecls[i]); - break; - case Tyarray: - wrtype(fd, ty->sub[0]); - pickle(fd, ty->asize); - break; - case Tyslice: - wrtype(fd, ty->sub[0]); - break; - case Tyvar: - die("Attempting to pickle %s. This will not work.\n", tystr(ty)); - break; - case Tyname: - pickle(fd, ty->name); - wrbool(fd, ty->issynth); - wrint(fd, ty->narg); - for (i = 0; i < ty->narg; i++) - wrtype(fd, ty->arg[i]); - wrtype(fd, ty->sub[0]); - break; - case Tygeneric: - pickle(fd, ty->name); - wrbool(fd, ty->issynth); - wrint(fd, ty->ngparam); - for (i = 0; i < ty->ngparam; i++) - wrtype(fd, ty->gparam[i]); - wrtype(fd, ty->sub[0]); - break; - default: - for (i = 0; i < ty->nsub; i++) - wrtype(fd, ty->sub[i]); - break; - } + size_t i; + + if (!ty) { + die("trying to pickle null type\n"); + return; + } + wrbyte(fd, ty->type); + wrbyte(fd, ty->vis); + /* tid is generated; don't write */ + /* FIXME: since we only support hardcoded traits, we just write + * out the set of them. we should write out the trait list as + * well */ + if (!ty->traits) { + wrint(fd, 0); + } + else { + wrint(fd, bscount(ty->traits)); + for (i = 0; bsiter(ty->traits, &i); i++) { + if (i < Ntraits) + wrint(fd, i | Builtinmask); + else + wrint(fd, i); + } + } + wrint(fd, ty->nsub); + switch (ty->type) { + case Tyunres: pickle(fd, ty->name); break; + case Typaram: wrstr(fd, ty->pname); break; + case Tystruct: + wrint(fd, ty->nmemb); + for (i = 0; i < ty->nmemb; i++) + pickle(fd, ty->sdecls[i]); + break; + case Tyunion: + wrint(fd, ty->nmemb); + for (i = 0; i < ty->nmemb; i++) + wrucon(fd, ty->udecls[i]); + break; + case Tyarray: + wrtype(fd, ty->sub[0]); + pickle(fd, ty->asize); + break; + case Tyslice: wrtype(fd, ty->sub[0]); break; + case Tyvar: die("Attempting to pickle %s. This will not work.\n", tystr(ty)); break; + case Tyname: + pickle(fd, ty->name); + wrbool(fd, ty->issynth); + wrint(fd, ty->narg); + for (i = 0; i < ty->narg; i++) + wrtype(fd, ty->arg[i]); + wrtype(fd, ty->sub[0]); + break; + case Tygeneric: + pickle(fd, ty->name); + wrbool(fd, ty->issynth); + wrint(fd, ty->ngparam); + for (i = 0; i < ty->ngparam; i++) + wrtype(fd, ty->gparam[i]); + wrtype(fd, ty->sub[0]); + break; + default: + for (i = 0; i < ty->nsub; i++) + wrtype(fd, ty->sub[i]); + break; + } } static void traitpickle(FILE *fd, Trait *tr) { - size_t i; - - wrint(fd, tr->uid); - wrbool(fd, tr->ishidden); - pickle(fd, tr->name); - typickle(fd, tr->param); - wrint(fd, tr->nmemb); - for (i = 0; i < tr->nmemb; i++) - wrsym(fd, tr->memb[i]); - wrint(fd, tr->nfuncs); - for (i = 0; i < tr->nfuncs; i++) - wrsym(fd, tr->funcs[i]); + size_t i; + + wrint(fd, tr->uid); + wrbool(fd, tr->ishidden); + pickle(fd, tr->name); + typickle(fd, tr->param); + wrint(fd, tr->nmemb); + for (i = 0; i < tr->nmemb; i++) + wrsym(fd, tr->memb[i]); + wrint(fd, tr->nfuncs); + for (i = 0; i < tr->nfuncs; i++) + wrsym(fd, tr->funcs[i]); } static void wrtype(FILE *fd, Type *ty) { - if (ty->tid >= Builtinmask) - die("Type id %d for %s too big", ty->tid, tystr(ty)); - if (ty->vis == Visbuiltin) - wrint(fd, ty->type | Builtinmask); - else - wrint(fd, ty->tid); + if (ty->tid >= Builtinmask) + die("Type id %d for %s too big", ty->tid, tystr(ty)); + if (ty->vis == Visbuiltin) + wrint(fd, ty->type | Builtinmask); + else + wrint(fd, ty->tid); } static void rdtype(FILE *fd, Type **dest) { - uintptr_t tid; - - tid = rdint(fd); - if (tid & Builtinmask) { - *dest = mktype(Zloc, tid & ~Builtinmask); - } else { - lappend(&typefixdest, &ntypefixdest, dest); - lappend(&typefixid, &ntypefixid, itop(tid)); - } + uintptr_t tid; + + tid = rdint(fd); + if (tid & Builtinmask) { + *dest = mktype(Zloc, tid & ~Builtinmask); + } + else { + lappend(&typefixdest, &ntypefixdest, dest); + lappend(&typefixid, &ntypefixid, itop(tid)); + } } static void rdtrait(FILE *fd, Trait **dest, Type *ty) { - uintptr_t tid; - - tid = rdint(fd); - if (tid & Builtinmask) { - if (dest) - *dest = traittab[tid & ~Builtinmask]; - if (ty) - settrait(ty, traittab[tid & ~Builtinmask]); - } else { - lappend(&traitfixdest, &ntraitfixdest, dest); - lappend(&traitfixtype, &ntraitfixtype, ty); - lappend(&traitfixid, &ntraitfixid, itop(tid)); - } + uintptr_t tid; + + tid = rdint(fd); + if (tid & Builtinmask) { + if (dest) + *dest = traittab[tid & ~Builtinmask]; + if (ty) + settrait(ty, traittab[tid & ~Builtinmask]); + } + else { + lappend(&traitfixdest, &ntraitfixdest, dest); + lappend(&traitfixtype, &ntraitfixtype, ty); + lappend(&traitfixid, &ntraitfixid, itop(tid)); + } } /* Writes types to a file. Errors on @@ -337,94 +330,90 @@ static void rdtrait(FILE *fd, Trait **dest, Type *ty) * will not be meaningful in another file */ static Type *tyunpickle(FILE *fd) { - size_t i, n; - Type *ty; - Ty t; - - t = rdbyte(fd); - ty = mktype(Zloc, t); - ty->isimport = 1; - if (rdbyte(fd) == Vishidden) - ty->ishidden = 1; - /* tid is generated; don't write */ - n = rdint(fd); - for (i = 0; i < n; i++) - rdtrait(fd, NULL, ty); - ty->nsub = rdint(fd); - if (ty->nsub > 0) - ty->sub = zalloc(ty->nsub * sizeof(Type*)); - switch (ty->type) { - case Tyunres: - ty->name = unpickle(fd); - break; - case Typaram: - ty->pname = rdstr(fd); - break; - case Tystruct: - ty->nmemb = rdint(fd); - ty->sdecls = zalloc(ty->nmemb * sizeof(Node*)); - for (i = 0; i < ty->nmemb; i++) - ty->sdecls[i] = unpickle(fd); - break; - case Tyunion: - ty->nmemb = rdint(fd); - ty->udecls = zalloc(ty->nmemb * sizeof(Node*)); - for (i = 0; i < ty->nmemb; i++) - ty->udecls[i] = rducon(fd, ty); - break; - case Tyarray: - rdtype(fd, &ty->sub[0]); - ty->asize = unpickle(fd); - break; - case Tyslice: - rdtype(fd, &ty->sub[0]); - break; - case Tyname: - ty->name = unpickle(fd); - ty->issynth = rdbool(fd); - ty->narg = rdint(fd); - ty->arg = zalloc(ty->narg * sizeof(Type *)); - for (i = 0; i < ty->narg; i++) - rdtype(fd, &ty->arg[i]); - rdtype(fd, &ty->sub[0]); - break; - case Tygeneric: - ty->name = unpickle(fd); - ty->issynth = rdbool(fd); - ty->ngparam = rdint(fd); - ty->gparam = zalloc(ty->ngparam * sizeof(Type *)); - for (i = 0; i < ty->ngparam; i++) - rdtype(fd, &ty->gparam[i]); - rdtype(fd, &ty->sub[0]); - break; - default: - for (i = 0; i < ty->nsub; i++) - rdtype(fd, &ty->sub[i]); - break; - } - return ty; + size_t i, n; + Type *ty; + Ty t; + + t = rdbyte(fd); + ty = mktype(Zloc, t); + ty->isimport = 1; + if (rdbyte(fd) == Vishidden) + ty->ishidden = 1; + /* tid is generated; don't write */ + n = rdint(fd); + for (i = 0; i < n; i++) + rdtrait(fd, NULL, ty); + ty->nsub = rdint(fd); + if (ty->nsub > 0) + ty->sub = zalloc(ty->nsub * sizeof(Type *)); + switch (ty->type) { + case Tyunres: ty->name = unpickle(fd); break; + case Typaram: ty->pname = rdstr(fd); break; + case Tystruct: + ty->nmemb = rdint(fd); + ty->sdecls = zalloc(ty->nmemb * sizeof(Node *)); + for (i = 0; i < ty->nmemb; i++) + ty->sdecls[i] = unpickle(fd); + break; + case Tyunion: + ty->nmemb = rdint(fd); + ty->udecls = zalloc(ty->nmemb * sizeof(Node *)); + for (i = 0; i < ty->nmemb; i++) + ty->udecls[i] = rducon(fd, ty); + break; + case Tyarray: + rdtype(fd, &ty->sub[0]); + ty->asize = unpickle(fd); + break; + case Tyslice: + rdtype(fd, &ty->sub[0]); + break; + case Tyname: + ty->name = unpickle(fd); + ty->issynth = rdbool(fd); + ty->narg = rdint(fd); + ty->arg = zalloc(ty->narg * sizeof(Type *)); + for (i = 0; i < ty->narg; i++) + rdtype(fd, &ty->arg[i]); + rdtype(fd, &ty->sub[0]); + break; + case Tygeneric: + ty->name = unpickle(fd); + ty->issynth = rdbool(fd); + ty->ngparam = rdint(fd); + ty->gparam = zalloc(ty->ngparam * sizeof(Type *)); + for (i = 0; i < ty->ngparam; i++) + rdtype(fd, &ty->gparam[i]); + rdtype(fd, &ty->sub[0]); + break; + default: + for (i = 0; i < ty->nsub; i++) + rdtype(fd, &ty->sub[i]); + break; + } + return ty; } Trait *traitunpickle(FILE *fd) { - Trait *tr; - size_t i, n; - intptr_t uid; - - /* create an empty trait */ - tr = mktrait(Zloc, NULL, NULL, NULL, 0, NULL, 0, 0); - uid = rdint(fd); - tr->ishidden = rdbool(fd); - tr->name = unpickle(fd); - tr->param = tyunpickle(fd); - n = rdint(fd); - for (i = 0; i < n; i++) - lappend(&tr->memb, &tr->nmemb, rdsym(fd, tr)); - n = rdint(fd); - for (i = 0; i < n; i++) - lappend(&tr->funcs, &tr->nfuncs, rdsym(fd, tr)); - htput(trmap, itop(uid), tr); - return tr; + Trait *tr; + size_t i, n; + intptr_t uid; + + /* create an empty trait */ + tr = mktrait(Zloc, NULL, NULL, NULL, 0, NULL, 0, 0); + uid = rdint(fd); + tr->ishidden = rdbool(fd); + tr->name = unpickle(fd); + tr->param = tyunpickle(fd); + n = rdint(fd); + for (i = 0; i < n; i++) + lappend(&tr->memb, &tr->nmemb, rdsym(fd, tr)); + n = rdint(fd); + for (i = 0; i < n; i++) + lappend(&tr->funcs, &tr->nfuncs, rdsym(fd, tr)); + htput(trmap, itop(uid), tr); + return tr; } /* Pickles a node to a file. The format @@ -435,127 +424,125 @@ Trait *traitunpickle(FILE *fd) * crash the compiler */ static void pickle(FILE *fd, Node *n) { - size_t i; - - if (!n) { - wrbyte(fd, Nnone); - return; - } - wrbyte(fd, n->type); - wrint(fd, n->loc.line); - switch (n->type) { - case Nfile: - wrstr(fd, n->file.files[0]); - wrint(fd, n->file.nuses); - for (i = 0; i < n->file.nuses; i++) - pickle(fd, n->file.uses[i]); - wrint(fd, n->file.nstmts); - for (i = 0; i < n->file.nstmts; i++) - pickle(fd, n->file.stmts[i]); - wrstab(fd, n->file.globls); - break; - - case Nexpr: - wrbyte(fd, n->expr.op); - wrtype(fd, n->expr.type); - wrbool(fd, n->expr.isconst); - pickle(fd, n->expr.idx); - wrint(fd, n->expr.nargs); - for (i = 0; i < n->expr.nargs; i++) - pickle(fd, n->expr.args[i]); - break; - case Nname: - wrbool(fd, n->name.ns != NULL); - if (n->name.ns) { - wrstr(fd, n->name.ns); - } - wrstr(fd, n->name.name); - break; - case Nuse: - wrbool(fd, n->use.islocal); - wrstr(fd, n->use.name); - break; - case Nlit: - wrbyte(fd, n->lit.littype); - wrtype(fd, n->lit.type); - wrint(fd, n->lit.nelt); - switch (n->lit.littype) { - case Lchr: wrint(fd, n->lit.chrval); break; - case Lint: wrint(fd, n->lit.intval); break; - case Lflt: wrflt(fd, n->lit.fltval); break; - case Lstr: wrlenstr(fd, n->lit.strval); break; - case Llbl: wrstr(fd, n->lit.lblval); break; - case Lbool: wrbool(fd, n->lit.boolval); break; - case Lfunc: pickle(fd, n->lit.fnval); break; - } - break; - case Nloopstmt: - pickle(fd, n->loopstmt.init); - pickle(fd, n->loopstmt.cond); - pickle(fd, n->loopstmt.step); - pickle(fd, n->loopstmt.body); - break; - case Niterstmt: - pickle(fd, n->iterstmt.elt); - pickle(fd, n->iterstmt.seq); - pickle(fd, n->iterstmt.body); - break; - case Nmatchstmt: - pickle(fd, n->matchstmt.val); - wrint(fd, n->matchstmt.nmatches); - for (i = 0; i < n->matchstmt.nmatches; i++) - pickle(fd, n->matchstmt.matches[i]); - break; - case Nmatch: - pickle(fd, n->match.pat); - pickle(fd, n->match.block); - break; - case Nifstmt: - pickle(fd, n->ifstmt.cond); - pickle(fd, n->ifstmt.iftrue); - pickle(fd, n->ifstmt.iffalse); - break; - case Nblock: - wrstab(fd, n->block.scope); - wrint(fd, n->block.nstmts); - for (i = 0; i < n->block.nstmts; i++) - pickle(fd, n->block.stmts[i]); - break; - case Ndecl: - /* sym */ - pickle(fd, n->decl.name); - wrtype(fd, n->decl.type); - - /* symflags */ - wrbool(fd, n->decl.isconst); - wrbool(fd, n->decl.isgeneric); - wrbool(fd, n->decl.isextern); - wrbool(fd, n->decl.isnoret); - wrbool(fd, n->decl.ispkglocal); - - /* init */ - pickle(fd, n->decl.init); - break; - case Nfunc: - wrtype(fd, n->func.type); - wrstab(fd, n->func.scope); - wrint(fd, n->func.nargs); - for (i = 0; i < n->func.nargs; i++) - pickle(fd, n->func.args[i]); - pickle(fd, n->func.body); - break; - case Nimpl: - pickle(fd, n->impl.traitname); - wrint(fd, n->impl.trait->uid); - wrtype(fd, n->impl.type); - wrint(fd, n->impl.ndecls); - for (i = 0; i < n->impl.ndecls; i++) - wrsym(fd, n->impl.decls[i]); - break; - case Nnone: - die("Nnone should not be seen as node type!"); - break; - } + size_t i; + + if (!n) { + wrbyte(fd, Nnone); + return; + } + wrbyte(fd, n->type); + wrint(fd, n->loc.line); + switch (n->type) { + case Nfile: + wrstr(fd, n->file.files[0]); + wrint(fd, n->file.nuses); + for (i = 0; i < n->file.nuses; i++) + pickle(fd, n->file.uses[i]); + wrint(fd, n->file.nstmts); + for (i = 0; i < n->file.nstmts; i++) + pickle(fd, n->file.stmts[i]); + wrstab(fd, n->file.globls); + break; + + case Nexpr: + wrbyte(fd, n->expr.op); + wrtype(fd, n->expr.type); + wrbool(fd, n->expr.isconst); + pickle(fd, n->expr.idx); + wrint(fd, n->expr.nargs); + for (i = 0; i < n->expr.nargs; i++) + pickle(fd, n->expr.args[i]); + break; + case Nname: + wrbool(fd, n->name.ns != NULL); + if (n->name.ns) { + wrstr(fd, n->name.ns); + } + wrstr(fd, n->name.name); + break; + case Nuse: + wrbool(fd, n->use.islocal); + wrstr(fd, n->use.name); + break; + case Nlit: + wrbyte(fd, n->lit.littype); + wrtype(fd, n->lit.type); + wrint(fd, n->lit.nelt); + switch (n->lit.littype) { + case Lchr: wrint(fd, n->lit.chrval); break; + case Lint: wrint(fd, n->lit.intval); break; + case Lflt: wrflt(fd, n->lit.fltval); break; + case Lstr: wrlenstr(fd, n->lit.strval); break; + case Llbl: wrstr(fd, n->lit.lblval); break; + case Lbool: wrbool(fd, n->lit.boolval); break; + case Lfunc: pickle(fd, n->lit.fnval); break; + } + break; + case Nloopstmt: + pickle(fd, n->loopstmt.init); + pickle(fd, n->loopstmt.cond); + pickle(fd, n->loopstmt.step); + pickle(fd, n->loopstmt.body); + break; + case Niterstmt: + pickle(fd, n->iterstmt.elt); + pickle(fd, n->iterstmt.seq); + pickle(fd, n->iterstmt.body); + break; + case Nmatchstmt: + pickle(fd, n->matchstmt.val); + wrint(fd, n->matchstmt.nmatches); + for (i = 0; i < n->matchstmt.nmatches; i++) + pickle(fd, n->matchstmt.matches[i]); + break; + case Nmatch: + pickle(fd, n->match.pat); + pickle(fd, n->match.block); + break; + case Nifstmt: + pickle(fd, n->ifstmt.cond); + pickle(fd, n->ifstmt.iftrue); + pickle(fd, n->ifstmt.iffalse); + break; + case Nblock: + wrstab(fd, n->block.scope); + wrint(fd, n->block.nstmts); + for (i = 0; i < n->block.nstmts; i++) + pickle(fd, n->block.stmts[i]); + break; + case Ndecl: + /* sym */ + pickle(fd, n->decl.name); + wrtype(fd, n->decl.type); + + /* symflags */ + wrbool(fd, n->decl.isconst); + wrbool(fd, n->decl.isgeneric); + wrbool(fd, n->decl.isextern); + wrbool(fd, n->decl.isnoret); + wrbool(fd, n->decl.ispkglocal); + + /* init */ + pickle(fd, n->decl.init); + break; + case Nfunc: + wrtype(fd, n->func.type); + wrstab(fd, n->func.scope); + wrint(fd, n->func.nargs); + for (i = 0; i < n->func.nargs; i++) + pickle(fd, n->func.args[i]); + pickle(fd, n->func.body); + break; + case Nimpl: + pickle(fd, n->impl.traitname); + wrint(fd, n->impl.trait->uid); + wrtype(fd, n->impl.type); + wrint(fd, n->impl.ndecls); + for (i = 0; i < n->impl.ndecls; i++) + wrsym(fd, n->impl.decls[i]); + break; + case Nnone: die("Nnone should not be seen as node type!"); break; + } } /* Unpickles a node from a file. Minimal checking @@ -563,243 +550,243 @@ static void pickle(FILE *fd, Node *n) * sane arities, a bad file can crash the compiler */ static Node *unpickle(FILE *fd) { - size_t i; - Ntype type; - Node *n; - - type = rdbyte(fd); - if (type == Nnone) - return NULL; - n = mknode(Zloc, type); - n->loc.line = rdint(fd); - n->loc.file = file->file.nfiles - 1; - switch (n->type) { - case Nfile: - lappend(&n->file.files, &n->file.nfiles, rdstr(fd)); - n->file.nuses = rdint(fd); - n->file.uses = zalloc(sizeof(Node*)*n->file.nuses); - for (i = 0; i < n->file.nuses; i++) - n->file.uses[i] = unpickle(fd); - n->file.nstmts = rdint(fd); - n->file.stmts = zalloc(sizeof(Node*)*n->file.nstmts); - for (i = 0; i < n->file.nstmts; i++) - n->file.stmts[i] = unpickle(fd); - n->file.globls = rdstab(fd, 0); - break; - - case Nexpr: - n->expr.op = rdbyte(fd); - rdtype(fd, &n->expr.type); - n->expr.isconst = rdbool(fd); - n->expr.idx = unpickle(fd); - n->expr.nargs = rdint(fd); - n->expr.args = zalloc(sizeof(Node *)*n->expr.nargs); - for (i = 0; i < n->expr.nargs; i++) - n->expr.args[i] = unpickle(fd); - break; - case Nname: - if (rdbool(fd)) - n->name.ns = rdstr(fd); - n->name.name = rdstr(fd); - break; - case Nuse: - n->use.islocal = rdbool(fd); - n->use.name = rdstr(fd); - break; - case Nlit: - n->lit.littype = rdbyte(fd); - rdtype(fd, &n->lit.type); - n->lit.nelt = rdint(fd); - switch (n->lit.littype) { - case Lchr: n->lit.chrval = rdint(fd); break; - case Lint: n->lit.intval = rdint(fd); break; - case Lflt: n->lit.fltval = rdflt(fd); break; - case Lstr: rdlenstr(fd, &n->lit.strval); break; - case Llbl: n->lit.lblval = rdstr(fd); break; - case Lbool: n->lit.boolval = rdbool(fd); break; - case Lfunc: n->lit.fnval = unpickle(fd); break; - } - break; - case Nloopstmt: - n->loopstmt.init = unpickle(fd); - n->loopstmt.cond = unpickle(fd); - n->loopstmt.step = unpickle(fd); - n->loopstmt.body = unpickle(fd); - break; - case Niterstmt: - n->iterstmt.elt = unpickle(fd); - n->iterstmt.seq = unpickle(fd); - n->iterstmt.body = unpickle(fd); - break; - case Nmatchstmt: - n->matchstmt.val = unpickle(fd); - n->matchstmt.nmatches = rdint(fd); - n->matchstmt.matches = zalloc(sizeof(Node *)*n->matchstmt.nmatches); - for (i = 0; i < n->matchstmt.nmatches; i++) - n->matchstmt.matches[i] = unpickle(fd); - break; - case Nmatch: - n->match.pat = unpickle(fd); - n->match.block = unpickle(fd); - break; - case Nifstmt: - n->ifstmt.cond = unpickle(fd); - n->ifstmt.iftrue = unpickle(fd); - n->ifstmt.iffalse = unpickle(fd); - break; - case Nblock: - n->block.scope = rdstab(fd, 0); - n->block.nstmts = rdint(fd); - n->block.stmts = zalloc(sizeof(Node *)*n->block.nstmts); - n->block.scope->super = curstab(); - pushstab(n->func.scope->super); - for (i = 0; i < n->block.nstmts; i++) - n->block.stmts[i] = unpickle(fd); - popstab(); - break; - case Ndecl: - n->decl.did = ndecls; /* unique within file */ - /* sym */ - n->decl.name = unpickle(fd); - rdtype(fd, &n->decl.type); - - /* symflags */ - n->decl.isconst = rdbool(fd); - n->decl.isgeneric = rdbool(fd); - n->decl.isextern = rdbool(fd); - n->decl.isnoret = rdbool(fd); - n->decl.ispkglocal = rdbool(fd); - - /* init */ - n->decl.init = unpickle(fd); - lappend(&decls, &ndecls, n); - break; - case Nfunc: - rdtype(fd, &n->func.type); - n->func.scope = rdstab(fd, 1); - n->func.nargs = rdint(fd); - n->func.args = zalloc(sizeof(Node *)*n->func.nargs); - n->func.scope->super = curstab(); - pushstab(n->func.scope->super); - for (i = 0; i < n->func.nargs; i++) - n->func.args[i] = unpickle(fd); - n->func.body = unpickle(fd); - popstab(); - break; - case Nimpl: - n->impl.traitname = unpickle(fd); - i = rdint(fd); - rdtrait(fd, &n->impl.trait, NULL); - rdtype(fd, &n->impl.type); - n->impl.ndecls = rdint(fd); - n->impl.decls = zalloc(sizeof(Node *)*n->impl.ndecls); - for (i = 0; i < n->impl.ndecls; i++) - n->impl.decls[i] = rdsym(fd, n->impl.trait); - break; - case Nnone: - die("Nnone should not be seen as node type!"); - break; - } - return n; + size_t i; + Ntype type; + Node *n; + + type = rdbyte(fd); + if (type == Nnone) + return NULL; + n = mknode(Zloc, type); + n->loc.line = rdint(fd); + n->loc.file = file->file.nfiles - 1; + switch (n->type) { + case Nfile: + lappend(&n->file.files, &n->file.nfiles, rdstr(fd)); + n->file.nuses = rdint(fd); + n->file.uses = zalloc(sizeof(Node *) * n->file.nuses); + for (i = 0; i < n->file.nuses; i++) + n->file.uses[i] = unpickle(fd); + n->file.nstmts = rdint(fd); + n->file.stmts = zalloc(sizeof(Node *) * n->file.nstmts); + for (i = 0; i < n->file.nstmts; i++) + n->file.stmts[i] = unpickle(fd); + n->file.globls = rdstab(fd, 0); + break; + + case Nexpr: + n->expr.op = rdbyte(fd); + rdtype(fd, &n->expr.type); + n->expr.isconst = rdbool(fd); + n->expr.idx = unpickle(fd); + n->expr.nargs = rdint(fd); + n->expr.args = zalloc(sizeof(Node *) * n->expr.nargs); + for (i = 0; i < n->expr.nargs; i++) + n->expr.args[i] = unpickle(fd); + break; + case Nname: + if (rdbool(fd)) + n->name.ns = rdstr(fd); + n->name.name = rdstr(fd); + break; + case Nuse: + n->use.islocal = rdbool(fd); + n->use.name = rdstr(fd); + break; + case Nlit: + n->lit.littype = rdbyte(fd); + rdtype(fd, &n->lit.type); + n->lit.nelt = rdint(fd); + switch (n->lit.littype) { + case Lchr: n->lit.chrval = rdint(fd); break; + case Lint: n->lit.intval = rdint(fd); break; + case Lflt: n->lit.fltval = rdflt(fd); break; + case Lstr: rdlenstr(fd, &n->lit.strval); break; + case Llbl: n->lit.lblval = rdstr(fd); break; + case Lbool: n->lit.boolval = rdbool(fd); break; + case Lfunc: n->lit.fnval = unpickle(fd); break; + } + break; + case Nloopstmt: + n->loopstmt.init = unpickle(fd); + n->loopstmt.cond = unpickle(fd); + n->loopstmt.step = unpickle(fd); + n->loopstmt.body = unpickle(fd); + break; + case Niterstmt: + n->iterstmt.elt = unpickle(fd); + n->iterstmt.seq = unpickle(fd); + n->iterstmt.body = unpickle(fd); + break; + case Nmatchstmt: + n->matchstmt.val = unpickle(fd); + n->matchstmt.nmatches = rdint(fd); + n->matchstmt.matches = zalloc(sizeof(Node *) * n->matchstmt.nmatches); + for (i = 0; i < n->matchstmt.nmatches; i++) + n->matchstmt.matches[i] = unpickle(fd); + break; + case Nmatch: + n->match.pat = unpickle(fd); + n->match.block = unpickle(fd); + break; + case Nifstmt: + n->ifstmt.cond = unpickle(fd); + n->ifstmt.iftrue = unpickle(fd); + n->ifstmt.iffalse = unpickle(fd); + break; + case Nblock: + n->block.scope = rdstab(fd, 0); + n->block.nstmts = rdint(fd); + n->block.stmts = zalloc(sizeof(Node *) * n->block.nstmts); + n->block.scope->super = curstab(); + pushstab(n->func.scope->super); + for (i = 0; i < n->block.nstmts; i++) + n->block.stmts[i] = unpickle(fd); + popstab(); + break; + case Ndecl: + n->decl.did = ndecls; /* unique within file */ + /* sym */ + n->decl.name = unpickle(fd); + rdtype(fd, &n->decl.type); + + /* symflags */ + n->decl.isconst = rdbool(fd); + n->decl.isgeneric = rdbool(fd); + n->decl.isextern = rdbool(fd); + n->decl.isnoret = rdbool(fd); + n->decl.ispkglocal = rdbool(fd); + + /* init */ + n->decl.init = unpickle(fd); + lappend(&decls, &ndecls, n); + break; + case Nfunc: + rdtype(fd, &n->func.type); + n->func.scope = rdstab(fd, 1); + n->func.nargs = rdint(fd); + n->func.args = zalloc(sizeof(Node *) * n->func.nargs); + n->func.scope->super = curstab(); + pushstab(n->func.scope->super); + for (i = 0; i < n->func.nargs; i++) + n->func.args[i] = unpickle(fd); + n->func.body = unpickle(fd); + popstab(); + break; + case Nimpl: + n->impl.traitname = unpickle(fd); + i = rdint(fd); + rdtrait(fd, &n->impl.trait, NULL); + rdtype(fd, &n->impl.type); + n->impl.ndecls = rdint(fd); + n->impl.decls = zalloc(sizeof(Node *) * n->impl.ndecls); + for (i = 0; i < n->impl.ndecls; i++) + n->impl.decls[i] = rdsym(fd, n->impl.trait); + break; + case Nnone: + die("Nnone should not be seen as node type!"); + break; + } + return n; } static Stab *findstab(Stab *st, char *pkg) { - Stab *s; - - if (!pkg) { - if (!st->name) - return st; - else - return NULL; - } - - s = getns(file, pkg); - if (!s) { - s = mkstab(0); - s->name = strdup(pkg); - putns(file, s); - } - return s; + Stab *s; + + if (!pkg) { + if (!st->name) + return st; + else + return NULL; + } + + s = getns(file, pkg); + if (!s) { + s = mkstab(0); + s->name = strdup(pkg); + putns(file, s); + } + return s; } static int isspecialization(Type *t1, Type *t2) { - if ((t1->type != Tygeneric || t2->type != Tyname) && - (t1->type != Tyname || t2->type != Tygeneric) && - (t1->type != Tyname || t2->type != Tyname)) - return 0; - /* FIXME: this should be done better */ - return nameeq(t1->name, t2->name); + if ((t1->type != Tygeneric || t2->type != Tyname) && + (t1->type != Tyname || t2->type != Tygeneric) && + (t1->type != Tyname || t2->type != Tyname)) + return 0; + /* FIXME: this should be done better */ + return nameeq(t1->name, t2->name); } static void fixtypemappings(Stab *st) { - size_t i; - Type *t, *old; - - - /* - * merge duplicate definitions. - * This allows us to compare named types by id, instead - * of doing a deep walk through the type. This ability is - * depended on when we do type inference. - */ - for (i = 0; i < ntypefixdest; i++) { - t = htget(tidmap, itop(typefixid[i])); - if (!t) - die("Unable to find type for id %zd\n", typefixid[i]); - *typefixdest[i] = t; - } - for (i = 0; i < ntypefixdest; i++) { - old = *typefixdest[i]; - if (old->type == Tyname || old->type == Tygeneric) { - t = htget(tydedup, old); - if (!t) { - t = old; - htput(tydedup, old, old); - } - *typefixdest[i] = t; - } - } - - /* check for duplicate type definitions */ - for (i = 0; i < ntypefixdest; i++) { - t = htget(tidmap, itop(typefixid[i])); - if ((t->type != Tyname && t->type != Tygeneric) || t->issynth) - continue; - old = htget(tydedup, t); - if (old && !tyeq(t, old) && !isspecialization(t, old)) - lfatal(t->loc, "Duplicate definition of type %s on %s:%d", tystr(old), file->file.files[old->loc.file], old->loc.line); - } - for (i = 0; i < ntypefixdest; i++) - lfree(&typefixdest, &ntypefixdest); - lfree(&typefixid, &ntypefixid); + size_t i; + Type *t, *old; + + /* + * merge duplicate definitions. + * This allows us to compare named types by id, instead + * of doing a deep walk through the type. This ability is + * depended on when we do type inference. + */ + for (i = 0; i < ntypefixdest; i++) { + t = htget(tidmap, itop(typefixid[i])); + if (!t) + die("Unable to find type for id %zd\n", typefixid[i]); + *typefixdest[i] = t; + } + for (i = 0; i < ntypefixdest; i++) { + old = *typefixdest[i]; + if (old->type == Tyname || old->type == Tygeneric) { + t = htget(tydedup, old); + if (!t) { + t = old; + htput(tydedup, old, old); + } + *typefixdest[i] = t; + } + } + + /* check for duplicate type definitions */ + for (i = 0; i < ntypefixdest; i++) { + t = htget(tidmap, itop(typefixid[i])); + if ((t->type != Tyname && t->type != Tygeneric) || t->issynth) + continue; + old = htget(tydedup, t); + if (old && !tyeq(t, old) && !isspecialization(t, old)) + lfatal(t->loc, "Duplicate definition of type %s on %s:%d", tystr(old), + file->file.files[old->loc.file], old->loc.line); + } + for (i = 0; i < ntypefixdest; i++) + lfree(&typefixdest, &ntypefixdest); + lfree(&typefixid, &ntypefixid); } static void fixtraitmappings(Stab *st) { - size_t i; - Trait *t; - - /* - * merge duplicate definitions. - * This allows us to compare named types by id, instead - * of doing a deep walk through the type. This ability is - * depended on when we do type inference. - */ - for (i = 0; i < ntraitfixdest; i++) { - t = htget(trmap, itop(traitfixid[i])); - if (!t) - die("Unable to find trait for id %zd\n", traitfixid[i]); - if (traitfixdest[i]) - *traitfixdest[i] = t; - if (traitfixtype[i]) - settrait(traitfixtype[i], t); - } - - lfree(&traitfixdest, &ntraitfixdest); - lfree(&traitfixid, &ntraitfixid); + size_t i; + Trait *t; + + /* + * merge duplicate definitions. + * This allows us to compare named types by id, instead + * of doing a deep walk through the type. This ability is + * depended on when we do type inference. + */ + for (i = 0; i < ntraitfixdest; i++) { + t = htget(trmap, itop(traitfixid[i])); + if (!t) + die("Unable to find trait for id %zd\n", traitfixid[i]); + if (traitfixdest[i]) + *traitfixdest[i] = t; + if (traitfixtype[i]) + settrait(traitfixtype[i], t); + } + + lfree(&traitfixdest, &ntraitfixdest); + lfree(&traitfixid, &ntraitfixid); } /* Usefile format: @@ -812,169 +799,172 @@ static void fixtraitmappings(Stab *st) */ int loaduse(char *path, FILE *f, Stab *st, Vis vis) { - intptr_t tid; - size_t i; - int v; - char *pkg; - Node *dcl, *impl, *init; - Stab *s; - Type *ty; - Trait *tr; - char *lib; - int c; - - pushstab(file->file.globls); - if (!tydedup) - tydedup = mkht(tyhash, tyeq); - if (fgetc(f) != 'U') - return 0; - v = rdint(f); - if (v != Abiversion) { - fprintf(stderr, "%s: abi version %d, expected %d\n", path, v, Abiversion); - return 0; - } - pkg = rdstr(f); - /* if the package names match up, or the usefile has no declared - * package, then we simply add to the current stab. Otherwise, - * we add a new stab under the current one */ - if (st->name) { - if (pkg && !strcmp(pkg, st->name)) { - s = st; - } else { - s = findstab(st, pkg); - } - } else { - if (pkg) { - s = findstab(st, pkg); - } else { - s = st; - } - } - if (!streq(st->name, pkg)) - vis = Visintern; - if (!s) { - printf("could not find matching package for merge: %s in %s\n", st->name, path); - exit(1); - } - tidmap = mkht(ptrhash, ptreq); - trmap = mkht(ptrhash, ptreq); - if (!initmap) - initmap = mkht(namehash, nameeq); - /* builtin traits */ - for (i = 0; i < Ntraits; i++) - htput(trmap, itop(i), traittab[i]); - while ((c = fgetc(f)) != EOF) { - switch(c) { - case 'L': - lib = rdstr(f); - for (i = 0; i < file->file.nlibdeps; i++) - if (!strcmp(file->file.libdeps[i], lib)) - /* break out of both loop and switch */ - goto foundlib; - lappend(&file->file.libdeps, &file->file.nlibdeps, lib); + intptr_t tid; + size_t i; + int v; + char *pkg; + Node *dcl, *impl, *init; + Stab *s; + Type *ty; + Trait *tr; + char *lib; + int c; + + pushstab(file->file.globls); + if (!tydedup) + tydedup = mkht(tyhash, tyeq); + if (fgetc(f) != 'U') + return 0; + v = rdint(f); + if (v != Abiversion) { + fprintf(stderr, "%s: abi version %d, expected %d\n", path, v, Abiversion); + return 0; + } + pkg = rdstr(f); + /* if the package names match up, or the usefile has no declared + * package, then we simply add to the current stab. Otherwise, + * we add a new stab under the current one */ + if (st->name) { + if (pkg && !strcmp(pkg, st->name)) { + s = st; + } + else { + s = findstab(st, pkg); + } + } + else { + if (pkg) { + s = findstab(st, pkg); + } + else { + s = st; + } + } + if (!streq(st->name, pkg)) + vis = Visintern; + if (!s) { + printf("could not find matching package for merge: %s in %s\n", st->name, path); + exit(1); + } + tidmap = mkht(ptrhash, ptreq); + trmap = mkht(ptrhash, ptreq); + if (!initmap) + initmap = mkht(namehash, nameeq); + /* builtin traits */ + for (i = 0; i < Ntraits; i++) + htput(trmap, itop(i), traittab[i]); + while ((c = fgetc(f)) != EOF) { + switch (c) { + case 'L': + lib = rdstr(f); + for (i = 0; i < file->file.nlibdeps; i++) + if (!strcmp(file->file.libdeps[i], lib)) + /* break out of both loop and switch */ + goto foundlib; + lappend(&file->file.libdeps, &file->file.nlibdeps, lib); foundlib: - break; - case 'X': - lib = rdstr(f); - for (i = 0; i < file->file.nextlibs; i++) - if (!strcmp(file->file.extlibs[i], lib)) - /* break out of both loop and switch */ - goto foundextlib; - lappend(&file->file.extlibs, &file->file.nextlibs, lib); + break; + case 'X': + lib = rdstr(f); + for (i = 0; i < file->file.nextlibs; i++) + if (!strcmp(file->file.extlibs[i], lib)) + /* break out of both loop and switch */ + goto foundextlib; + lappend(&file->file.extlibs, &file->file.nextlibs, lib); foundextlib: - break; - case 'F': - lappend(&file->file.files, &file->file.nfiles, rdstr(f)); - break; - case 'G': - case 'D': - dcl = rdsym(f, NULL); - dcl->decl.vis = vis; - dcl->decl.isglobl = 1; - putdcl(s, dcl); - break; - case 'S': - init = unpickle(f); - if (!hthas(initmap, init)) { - htput(initmap, init, init); - lappend(&file->file.init, &file->file.ninit, init); - } - break; - case 'R': - tr = traitunpickle(f); - tr->vis = vis; - puttrait(s, tr->name, tr); - for (i = 0; i < tr->nfuncs; i++) - putdcl(s, tr->funcs[i]); - break; - case 'T': - tid = rdint(f); - ty = tyunpickle(f); - if(!ty->ishidden) - ty->vis = vis; - htput(tidmap, itop(tid), ty); - /* fix up types */ - if (ty->type == Tyname || ty->type == Tygeneric) { - if (ty->issynth) - break; - if (!streq(s->name, ty->name->name.ns)) - ty->ishidden = 1; - if (!gettype(s, ty->name) && !ty->ishidden) - puttype(s, ty->name, ty); - } else if (ty->type == Tyunion) { - for (i = 0; i < ty->nmemb; i++) - if (!getucon(s, ty->udecls[i]->name) && !ty->udecls[i]->synth) - putucon(s, ty->udecls[i]); - } - break; - case 'I': - impl = unpickle(f); - putimpl(s, impl); - /* specialized declarations always go into the global stab */ - for (i = 0; i < impl->impl.ndecls; i++) - putdcl(file->file.globls, impl->impl.decls[i]); - break; - case EOF: - break; - } - } - fixtypemappings(s); - fixtraitmappings(s); - htfree(tidmap); - popstab(); - return 1; + break; + case 'F': lappend(&file->file.files, &file->file.nfiles, rdstr(f)); break; + case 'G': + case 'D': + dcl = rdsym(f, NULL); + dcl->decl.vis = vis; + dcl->decl.isglobl = 1; + putdcl(s, dcl); + break; + case 'S': + init = unpickle(f); + if (!hthas(initmap, init)) { + htput(initmap, init, init); + lappend(&file->file.init, &file->file.ninit, init); + } + break; + case 'R': + tr = traitunpickle(f); + tr->vis = vis; + puttrait(s, tr->name, tr); + for (i = 0; i < tr->nfuncs; i++) + putdcl(s, tr->funcs[i]); + break; + case 'T': + tid = rdint(f); + ty = tyunpickle(f); + if (!ty->ishidden) + ty->vis = vis; + htput(tidmap, itop(tid), ty); + /* fix up types */ + if (ty->type == Tyname || ty->type == Tygeneric) { + if (ty->issynth) + break; + if (!streq(s->name, ty->name->name.ns)) + ty->ishidden = 1; + if (!gettype(s, ty->name) && !ty->ishidden) + puttype(s, ty->name, ty); + } + else if (ty->type == Tyunion) { + for (i = 0; i < ty->nmemb; i++) + if (!getucon(s, ty->udecls[i]->name) && + !ty->udecls[i]->synth) + putucon(s, ty->udecls[i]); + } + break; + case 'I': + impl = unpickle(f); + putimpl(s, impl); + /* specialized declarations always go into the global stab */ + for (i = 0; i < impl->impl.ndecls; i++) + putdcl(file->file.globls, impl->impl.decls[i]); + break; + case EOF: break; + } + } + fixtypemappings(s); + fixtraitmappings(s); + htfree(tidmap); + popstab(); + return 1; } void readuse(Node *use, Stab *st, Vis vis) { - size_t i; - FILE *fd; - char *t, *p; - - /* local (quoted) uses are always relative to the cwd */ - fd = NULL; - p = NULL; - if (use->use.islocal) { - p = strdup(use->use.name); - fd = fopen(p, "r"); - /* nonlocal (barename) uses are always searched on the include path */ - } else { - for (i = 0; i < nincpaths; i++) { - t = strjoin(incpaths[i], "/"); - p = strjoin(t, use->use.name); - fd = fopen(p, "r"); - if (fd) { - free(t); - break; - } - } - } - if (!fd) - fatal(use, "Could not open %s", use->use.name); - - if (!loaduse(p, fd, st, vis)) - die("Could not load usefile %s from %s", use->use.name, p); - free(p); + size_t i; + FILE *fd; + char *t, *p; + + /* local (quoted) uses are always relative to the cwd */ + fd = NULL; + p = NULL; + if (use->use.islocal) { + p = strdup(use->use.name); + fd = fopen(p, "r"); + /* nonlocal (barename) uses are always searched on the include path */ + } + else { + for (i = 0; i < nincpaths; i++) { + t = strjoin(incpaths[i], "/"); + p = strjoin(t, use->use.name); + fd = fopen(p, "r"); + if (fd) { + free(t); + break; + } + } + } + if (!fd) + fatal(use, "Could not open %s", use->use.name); + + if (!loaduse(p, fd, st, vis)) + die("Could not load usefile %s from %s", use->use.name, p); + free(p); } /* Usefile format: @@ -988,92 +978,92 @@ void readuse(Node *use, Stab *st, Vis vis) */ void writeuse(FILE *f, Node *file) { - Stab *st; - void **k; - Node *s, *u; - size_t i, n; - - assert(file->type == Nfile); - st = file->file.globls; - - /* usefile name */ - wrbyte(f, 'U'); - wrint(f, Abiversion); /* use version */ - if (st->name) - wrstr(f, st->name); - else - wrstr(f, NULL); - - /* library deps */ - for (i = 0; i < file->file.nuses; i++) { - u = file->file.uses[i]; - if (!u->use.islocal) { - wrbyte(f, 'L'); - wrstr(f, u->use.name); - } - } - for (i = 0; i < file->file.nlibdeps; i++) { - wrbyte(f, 'L'); - wrstr(f, file->file.libdeps[i]); - } - for (i = 0; i < file->file.nextlibs; i++) { - wrbyte(f, 'X'); - wrstr(f, file->file.extlibs[i]); - } - - /* source file name */ - wrbyte(f, 'F'); - wrstr(f, file->file.files[0]); - - for (i = 0; i < ntypes; i++) { - if (types[i]->vis == Visexport || types[i]->vis == Vishidden) { - wrbyte(f, 'T'); - wrint(f, types[i]->tid); - typickle(f, types[i]); - } - } - - for (i = 0; i < ntraittab; i++) { - if (traittab[i]->vis == Visexport || traittab[i]->vis == Vishidden) { - wrbyte(f, 'R'); - traitpickle(f, traittab[i]); - } - } - - k = htkeys(st->impl, &n); - for (i = 0; i < n; i++) { - /* merging during inference should remove all protos */ - s = getimpl(st, k[i]); - assert(!s->impl.isproto); - if (s->impl.vis == Visexport || s->impl.vis == Vishidden) { - wrbyte(f, 'I'); - pickle(f, s); - } - } - free(k); - - k = htkeys(st->dcl, &n); - for (i = 0; i < n; i++) { - s = getdcl(st, k[i]); - assert(s != NULL); - if (s->decl.vis == Visintern || s->decl.vis == Visbuiltin) - continue; - /* trait functions get written out with their traits */ - if (s->decl.trait || s->decl.isinit) - continue; - else if (s->decl.isgeneric) - wrbyte(f, 'G'); - else - wrbyte(f, 'D'); - wrsym(f, s); - } - for (i = 0; i < file->file.ninit; i++) { - wrbyte(f, 'S'); - pickle(f, file->file.init[i]); - } - if (file->file.localinit) { - wrbyte(f, 'S'); - pickle(f, file->file.localinit->decl.name); - } - free(k); + Stab *st; + void **k; + Node *s, *u; + size_t i, n; + + assert(file->type == Nfile); + st = file->file.globls; + + /* usefile name */ + wrbyte(f, 'U'); + wrint(f, Abiversion); /* use version */ + if (st->name) + wrstr(f, st->name); + else + wrstr(f, NULL); + + /* library deps */ + for (i = 0; i < file->file.nuses; i++) { + u = file->file.uses[i]; + if (!u->use.islocal) { + wrbyte(f, 'L'); + wrstr(f, u->use.name); + } + } + for (i = 0; i < file->file.nlibdeps; i++) { + wrbyte(f, 'L'); + wrstr(f, file->file.libdeps[i]); + } + for (i = 0; i < file->file.nextlibs; i++) { + wrbyte(f, 'X'); + wrstr(f, file->file.extlibs[i]); + } + + /* source file name */ + wrbyte(f, 'F'); + wrstr(f, file->file.files[0]); + + for (i = 0; i < ntypes; i++) { + if (types[i]->vis == Visexport || types[i]->vis == Vishidden) { + wrbyte(f, 'T'); + wrint(f, types[i]->tid); + typickle(f, types[i]); + } + } + + for (i = 0; i < ntraittab; i++) { + if (traittab[i]->vis == Visexport || traittab[i]->vis == Vishidden) { + wrbyte(f, 'R'); + traitpickle(f, traittab[i]); + } + } + + k = htkeys(st->impl, &n); + for (i = 0; i < n; i++) { + /* merging during inference should remove all protos */ + s = getimpl(st, k[i]); + assert(!s->impl.isproto); + if (s->impl.vis == Visexport || s->impl.vis == Vishidden) { + wrbyte(f, 'I'); + pickle(f, s); + } + } + free(k); + + k = htkeys(st->dcl, &n); + for (i = 0; i < n; i++) { + s = getdcl(st, k[i]); + assert(s != NULL); + if (s->decl.vis == Visintern || s->decl.vis == Visbuiltin) + continue; + /* trait functions get written out with their traits */ + if (s->decl.trait || s->decl.isinit) + continue; + else if (s->decl.isgeneric) + wrbyte(f, 'G'); + else + wrbyte(f, 'D'); + wrsym(f, s); + } + for (i = 0; i < file->file.ninit; i++) { + wrbyte(f, 'S'); + pickle(f, file->file.init[i]); + } + if (file->file.localinit) { + wrbyte(f, 'S'); + pickle(f, file->file.localinit->decl.name); + } + free(k); } diff --git a/parse/util.c b/parse/util.c index be96a15..68a50a1 100644 --- a/parse/util.c +++ b/parse/util.c @@ -16,546 +16,543 @@ /* malloc wrappers */ void *zalloc(size_t sz) { - void *mem; + void *mem; - mem = calloc(1, sz); - if (!mem && sz) - die("Out of memory"); - return mem; + mem = calloc(1, sz); + if (!mem && sz) + die("Out of memory"); + return mem; } - void *xalloc(size_t sz) { - void *mem; + void *mem; - mem = malloc(sz); - if (!mem && sz) - die("Out of memory"); - return mem; + mem = malloc(sz); + if (!mem && sz) + die("Out of memory"); + return mem; } void *zrealloc(void *mem, size_t oldsz, size_t sz) { - char *p; + char *p; - p = xrealloc(mem, sz); - if (sz > oldsz) - memset(&p[oldsz], 0, sz - oldsz); - return p; + p = xrealloc(mem, sz); + if (sz > oldsz) + memset(&p[oldsz], 0, sz - oldsz); + return p; } void *xrealloc(void *mem, size_t sz) { - mem = realloc(mem, sz); - if (!mem && sz) - die("Out of memory"); - return mem; + mem = realloc(mem, sz); + if (!mem && sz) + die("Out of memory"); + return mem; } /* errors */ void die(char *msg, ...) { - va_list ap; + va_list ap; - va_start(ap, msg); - vfprintf(stderr, msg, ap); - fprintf(stderr, "\n"); - va_end(ap); - abort(); + va_start(ap, msg); + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + va_end(ap); + abort(); } void fatal(Node *n, char *msg, ...) { - va_list ap; + va_list ap; - va_start(ap, msg); - lfatalv(n->loc, msg, ap); - va_end(ap); + va_start(ap, msg); + lfatalv(n->loc, msg, ap); + va_end(ap); } void lfatal(Srcloc l, char *msg, ...) { - va_list ap; + va_list ap; - va_start(ap, msg); - lfatalv(l, msg, ap); - va_end(ap); + va_start(ap, msg); + lfatalv(l, msg, ap); + va_end(ap); } void lfatalv(Srcloc l, char *msg, va_list ap) { - fprintf(stdout, "%s:%d: ", fname(l), lnum(l)); - vfprintf(stdout, msg, ap); - fprintf(stdout, "\n"); - exit(1); + fprintf(stdout, "%s:%d: ", fname(l), lnum(l)); + vfprintf(stdout, msg, ap); + fprintf(stdout, "\n"); + exit(1); } /* Some systems don't have strndup. */ char *strdupn(char *s, size_t len) { - char *ret; + char *ret; - ret = xalloc(len + 1); - memcpy(ret, s, len); - ret[len] = '\0'; - return ret; + ret = xalloc(len + 1); + memcpy(ret, s, len); + ret[len] = '\0'; + return ret; } char *strjoin(char *u, char *v) { - size_t n; - char *s; + size_t n; + char *s; - n = strlen(u) + strlen(v) + 1; - s = xalloc(n); - bprintf(s, n + 1, "%s%s", u, v); - return s; + n = strlen(u) + strlen(v) + 1; + s = xalloc(n); + bprintf(s, n + 1, "%s%s", u, v); + return s; } void *memdup(void *mem, size_t len) { - void *ret; + void *ret; - ret = xalloc(len); - return memcpy(ret, mem, len); + ret = xalloc(len); + return memcpy(ret, mem, len); } /* lists */ void lappend(void *l, size_t *len, void *n) { - void ***pl; + void ***pl; - pl = l; - *pl = xrealloc(*pl, (*len + 1)*sizeof(void*)); - (*pl)[*len] = n; - (*len)++; + pl = l; + *pl = xrealloc(*pl, (*len + 1) * sizeof(void *)); + (*pl)[*len] = n; + (*len)++; } void *lpop(void *l, size_t *len) { - void ***pl; - void *v; + void ***pl; + void *v; - pl = l; - (*len)--; - v = (*pl)[*len]; - *pl = xrealloc(*pl, *len * sizeof(void*)); - return v; + pl = l; + (*len)--; + v = (*pl)[*len]; + *pl = xrealloc(*pl, *len * sizeof(void *)); + return v; } void linsert(void *p, size_t *len, size_t idx, void *v) { - void ***pl, **l; + void ***pl, **l; - pl = p; - *pl = xrealloc(*pl, (*len + 1)*sizeof(void*)); - l = *pl; + pl = p; + *pl = xrealloc(*pl, (*len + 1) * sizeof(void *)); + l = *pl; - memmove(&l[idx + 1], &l[idx], (*len - idx)*sizeof(void*)); - l[idx] = v; - (*len)++; + memmove(&l[idx + 1], &l[idx], (*len - idx) * sizeof(void *)); + l[idx] = v; + (*len)++; } void ldel(void *p, size_t *len, size_t idx) { - void ***pl, **l; + void ***pl, **l; - assert(p != NULL); - assert(idx < *len); - pl = p; - l = *pl; - memmove(&l[idx], &l[idx + 1], (*len - idx - 1)*sizeof(void*)); - (*len)--; - *pl = xrealloc(l, *len * sizeof(void*)); + assert(p != NULL); + assert(idx < *len); + pl = p; + l = *pl; + memmove(&l[idx], &l[idx + 1], (*len - idx - 1) * sizeof(void *)); + (*len)--; + *pl = xrealloc(l, *len * sizeof(void *)); } void lcat(void *dst, size_t *ndst, void *src, size_t nsrc) { - size_t i; - void ***d, **s; + size_t i; + void ***d, **s; - d = dst; - s = src; - for (i = 0; i < nsrc; i++) - lappend(d, ndst, s[i]); + d = dst; + s = src; + for (i = 0; i < nsrc; i++) + lappend(d, ndst, s[i]); } - void lfree(void *l, size_t *len) { - void ***pl; + void ***pl; - assert(l != NULL); - pl = l; - free(*pl); - *pl = NULL; - *len = 0; + assert(l != NULL); + pl = l; + free(*pl); + *pl = NULL; + *len = 0; } /* endian packing */ void be64(vlong v, byte buf[8]) { - buf[0] = (v >> 56) & 0xff; - buf[1] = (v >> 48) & 0xff; - buf[2] = (v >> 40) & 0xff; - buf[3] = (v >> 32) & 0xff; - buf[4] = (v >> 24) & 0xff; - buf[5] = (v >> 16) & 0xff; - buf[6] = (v >> 8) & 0xff; - buf[7] = (v >> 0) & 0xff; + buf[0] = (v >> 56) & 0xff; + buf[1] = (v >> 48) & 0xff; + buf[2] = (v >> 40) & 0xff; + buf[3] = (v >> 32) & 0xff; + buf[4] = (v >> 24) & 0xff; + buf[5] = (v >> 16) & 0xff; + buf[6] = (v >> 8) & 0xff; + buf[7] = (v >> 0) & 0xff; } vlong host64(byte buf[8]) { - vlong v = 0; + vlong v = 0; - v |= ((vlong)buf[0] << 56LL); - v |= ((vlong)buf[1] << 48LL); - v |= ((vlong)buf[2] << 40LL); - v |= ((vlong)buf[3] << 32LL); - v |= ((vlong)buf[4] << 24LL); - v |= ((vlong)buf[5] << 16LL); - v |= ((vlong)buf[6] << 8LL); - v |= ((vlong)buf[7] << 0LL); - return v; + v |= ((vlong)buf[0] << 56LL); + v |= ((vlong)buf[1] << 48LL); + v |= ((vlong)buf[2] << 40LL); + v |= ((vlong)buf[3] << 32LL); + v |= ((vlong)buf[4] << 24LL); + v |= ((vlong)buf[5] << 16LL); + v |= ((vlong)buf[6] << 8LL); + v |= ((vlong)buf[7] << 0LL); + return v; } void be32(long v, byte buf[4]) { - buf[0] = (v >> 24) & 0xff; - buf[1] = (v >> 16) & 0xff; - buf[2] = (v >> 8) & 0xff; - buf[3] = (v >> 0) & 0xff; + buf[0] = (v >> 24) & 0xff; + buf[1] = (v >> 16) & 0xff; + buf[2] = (v >> 8) & 0xff; + buf[3] = (v >> 0) & 0xff; } long host32(byte buf[4]) { - int32_t v = 0; - v |= ((long)buf[0] << 24); - v |= ((long)buf[1] << 16); - v |= ((long)buf[2] << 8); - v |= ((long)buf[3] << 0); - return v; + int32_t v = 0; + v |= ((long)buf[0] << 24); + v |= ((long)buf[1] << 16); + v |= ((long)buf[2] << 8); + v |= ((long)buf[3] << 0); + return v; } void wrbuf(FILE *fd, void *p, size_t sz) { - size_t n; - char *buf; + size_t n; + char *buf; - n = 0; - buf = p; - while (n < sz) { - n += fwrite(buf + n, 1, sz - n, fd); - if (feof(fd)) - die("Unexpected EOF"); - if (ferror(fd)) - die("Error writing"); - } + n = 0; + buf = p; + while (n < sz) { + n += fwrite(buf + n, 1, sz - n, fd); + if (feof(fd)) + die("Unexpected EOF"); + if (ferror(fd)) + die("Error writing"); + } } void rdbuf(FILE *fd, void *buf, size_t sz) { - size_t n; + size_t n; - n = sz; - while (n > 0) { - n -= fread(buf, 1, n, fd); - if (feof(fd)) - die("Unexpected EOF"); - if (ferror(fd)) - die("Error writing"); - } + n = sz; + while (n > 0) { + n -= fread(buf, 1, n, fd); + if (feof(fd)) + die("Unexpected EOF"); + if (ferror(fd)) + die("Error writing"); + } } void wrbyte(FILE *fd, char val) { - if (fputc(val, fd) == EOF) - die("Unexpected EOF"); + if (fputc(val, fd) == EOF) + die("Unexpected EOF"); } char rdbyte(FILE *fd) { - int c; - c = fgetc(fd); - if (c == EOF) - die("Unexpected EOF"); - return c; + int c; + c = fgetc(fd); + if (c == EOF) + die("Unexpected EOF"); + return c; } void wrint(FILE *fd, long val) { - byte buf[4]; - be32(val, buf); - wrbuf(fd, buf, 4); + byte buf[4]; + be32(val, buf); + wrbuf(fd, buf, 4); } long rdint(FILE *fd) { - byte buf[4]; - rdbuf(fd, buf, 4); - return host32(buf); + byte buf[4]; + rdbuf(fd, buf, 4); + return host32(buf); } void wrstr(FILE *fd, char *val) { - size_t len; + size_t len; - if (!val) { - wrint(fd, -1); - } else { - wrint(fd, strlen(val)); - len = strlen(val); - wrbuf(fd, val, len); - } + if (!val) { + wrint(fd, -1); + } + else { + wrint(fd, strlen(val)); + len = strlen(val); + wrbuf(fd, val, len); + } } char *rdstr(FILE *fd) { - ssize_t len; - char *s; + ssize_t len; + char *s; - len = rdint(fd); - if (len == -1) { - return NULL; - } else { - s = xalloc(len + 1); - rdbuf(fd, s, len); - s[len] = '\0'; - return s; - } + len = rdint(fd); + if (len == -1) { + return NULL; + } + else { + s = xalloc(len + 1); + rdbuf(fd, s, len); + s[len] = '\0'; + return s; + } } void wrlenstr(FILE *fd, Str str) { - wrint(fd, str.len); - wrbuf(fd, str.buf, str.len); + wrint(fd, str.len); + wrbuf(fd, str.buf, str.len); } void rdlenstr(FILE *fd, Str *str) { - str->len = rdint(fd); - str->buf = xalloc(str->len + 1); - rdbuf(fd, str->buf, str->len); - str->buf[str->len] = '\0'; + str->len = rdint(fd); + str->buf = xalloc(str->len + 1); + rdbuf(fd, str->buf, str->len); + str->buf[str->len] = '\0'; } void wrflt(FILE *fd, double val) { - byte buf[8]; - /* Assumption: We have 'val' in 64 bit IEEE format */ - union { - uvlong ival; - double fval; - } u; + byte buf[8]; + /* Assumption: We have 'val' in 64 bit IEEE format */ + union { + uvlong ival; + double fval; + } u; - u.fval = val; - be64(u.ival, buf); - wrbuf(fd, buf, 8); + u.fval = val; + be64(u.ival, buf); + wrbuf(fd, buf, 8); } double rdflt(FILE *fd) { - byte buf[8]; - union { - uvlong ival; - double fval; - } u; + byte buf[8]; + union { + uvlong ival; + double fval; + } u; - if (fread(buf, 8, 1, fd) < 8) - die("Unexpected EOF"); - u.ival = host64(buf); - return u.fval; + if (fread(buf, 8, 1, fd) < 8) + die("Unexpected EOF"); + u.ival = host64(buf); + return u.fval; } size_t bprintf(char *buf, size_t sz, char *fmt, ...) { - va_list ap; - size_t n; + va_list ap; + size_t n; - va_start(ap, fmt); - n = vsnprintf(buf, sz, fmt, ap); - assert(n <= sz); - va_end(ap); + va_start(ap, fmt); + n = vsnprintf(buf, sz, fmt, ap); + assert(n <= sz); + va_end(ap); - return n; + return n; } -void wrbool(FILE *fd, int val) -{ - wrbyte(fd, val); -} +void wrbool(FILE *fd, int val) { wrbyte(fd, val); } -int rdbool(FILE *fd) -{ - return rdbyte(fd); -} +int rdbool(FILE *fd) { return rdbyte(fd); } char *swapsuffix(char *buf, size_t sz, char *s, char *suf, char *swap) { - size_t slen, suflen, swaplen; + size_t slen, suflen, swaplen; - slen = strlen(s); - suflen = strlen(suf); - swaplen = strlen(swap); + slen = strlen(s); + suflen = strlen(suf); + swaplen = strlen(swap); - if (slen < suflen) - return NULL; - if (slen + swaplen >= sz) - die("swapsuffix: buf too small"); + if (slen < suflen) + return NULL; + if (slen + swaplen >= sz) + die("swapsuffix: buf too small"); - buf[0] = '\0'; - /* if we have matching suffixes */ - if (suflen < slen && !strcmp(suf, &s[slen - suflen])) { - strncat(buf, s, slen - suflen); - strncat(buf, swap, swaplen); - } else { - bprintf(buf, sz, "%s%s", s, swap); - } + buf[0] = '\0'; + /* if we have matching suffixes */ + if (suflen < slen && !strcmp(suf, &s[slen - suflen])) { + strncat(buf, s, slen - suflen); + strncat(buf, swap, swaplen); + } + else { + bprintf(buf, sz, "%s%s", s, swap); + } - return buf; + return buf; } size_t max(size_t a, size_t b) { - if (a > b) - return a; - else - return b; + if (a > b) + return a; + else + return b; } size_t min(size_t a, size_t b) { - if (a < b) - return a; - else - return b; + if (a < b) + return a; + else + return b; } size_t align(size_t sz, size_t a) { - /* align to 0 just returns sz */ - if (a == 0) - return sz; - return (sz + a - 1) & ~(a - 1); + /* align to 0 just returns sz */ + if (a == 0) + return sz; + return (sz + a - 1) & ~(a - 1); } void indentf(int depth, char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - vfindentf(stdout, depth, fmt, ap); - va_end(ap); + va_list ap; + va_start(ap, fmt); + vfindentf(stdout, depth, fmt, ap); + va_end(ap); } void findentf(FILE *fd, int depth, char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - vfindentf(fd, depth, fmt, ap); - va_end(ap); + va_list ap; + va_start(ap, fmt); + vfindentf(fd, depth, fmt, ap); + va_end(ap); } void vfindentf(FILE *fd, int depth, char *fmt, va_list ap) { - ssize_t i; + ssize_t i; - for (i = 0; i < depth; i++) - fprintf(fd, "\t"); - vfprintf(fd, fmt, ap); + for (i = 0; i < depth; i++) + fprintf(fd, "\t"); + vfprintf(fd, fmt, ap); } static int optinfo(Optctx *ctx, char arg, int *take, int *mand) { - char *s; - - for (s = ctx->optstr; *s != '\0'; s++) { - if (*s == arg) { - s++; - if (*s == ':') { - *take = 1; - *mand = 1; - return 1; - } else if (*s == '?') { - *take = 1; - *mand = 0; - return 1; - } else { - *take = 0; - *mand = 0; - return 1; - } - } - } - return 0; + char *s; + + for (s = ctx->optstr; *s != '\0'; s++) { + if (*s == arg) { + s++; + if (*s == ':') { + *take = 1; + *mand = 1; + return 1; + } + else if (*s == '?') { + *take = 1; + *mand = 0; + return 1; + } + else { + *take = 0; + *mand = 0; + return 1; + } + } + } + return 0; } static int findnextopt(Optctx *ctx) { - size_t i; + size_t i; - for (i = ctx->argidx + 1; i < ctx->noptargs; i++) { - if (ctx->optargs[i][0] == '-') - goto foundopt; - else - lappend(&ctx->args, &ctx->nargs, ctx->optargs[i]); - } - ctx->finished = 1; - return 0; + for (i = ctx->argidx + 1; i < ctx->noptargs; i++) { + if (ctx->optargs[i][0] == '-') + goto foundopt; + else + lappend(&ctx->args, &ctx->nargs, ctx->optargs[i]); + } + ctx->finished = 1; + return 0; foundopt: - ctx->argidx = i; - ctx->curarg = ctx->optargs[i] + 1; /* skip initial '-' */ - return 1; + ctx->argidx = i; + ctx->curarg = ctx->optargs[i] + 1; /* skip initial '-' */ + return 1; } void optinit(Optctx *ctx, char *optstr, char **optargs, size_t noptargs) { - ctx->args = NULL; - ctx->nargs = 0; + ctx->args = NULL; + ctx->nargs = 0; - ctx->optstr = optstr; - ctx->optargs = optargs; - ctx->noptargs = noptargs; - ctx->optdone = 0; - ctx->finished = 0; - ctx->argidx = 0; - ctx->curarg = ""; - findnextopt(ctx); + ctx->optstr = optstr; + ctx->optargs = optargs; + ctx->noptargs = noptargs; + ctx->optdone = 0; + ctx->finished = 0; + ctx->argidx = 0; + ctx->curarg = ""; + findnextopt(ctx); } int optnext(Optctx *ctx) { - int take, mand; - int c; - - c = *ctx->curarg; - ctx->curarg++; - if (!optinfo(ctx, c, &take, &mand)) { - printf("Unexpected argument %c\n", *ctx->curarg); - exit(1); - } - - ctx->optarg = NULL; - if (take) { - if (*ctx->curarg) { - ctx->optarg = ctx->curarg; - ctx->curarg += strlen(ctx->optarg); - } else if (ctx->argidx < ctx->noptargs - 1) { - ctx->optarg = ctx->optargs[ctx->argidx + 1]; - ctx->argidx++; - } else if (mand) { - fprintf(stderr, "expected argument for %c\n", *ctx->curarg); - } - findnextopt(ctx); - } else { - if (*ctx->curarg == '\0') - findnextopt(ctx); - } - return c; -} - -int optdone(Optctx *ctx) -{ - return *ctx->curarg == '\0' && ctx->finished; -} + int take, mand; + int c; + + c = *ctx->curarg; + ctx->curarg++; + if (!optinfo(ctx, c, &take, &mand)) { + printf("Unexpected argument %c\n", *ctx->curarg); + exit(1); + } + + ctx->optarg = NULL; + if (take) { + if (*ctx->curarg) { + ctx->optarg = ctx->curarg; + ctx->curarg += strlen(ctx->optarg); + } + else if (ctx->argidx < ctx->noptargs - 1) { + ctx->optarg = ctx->optargs[ctx->argidx + 1]; + ctx->argidx++; + } + else if (mand) { + fprintf(stderr, "expected argument for %c\n", *ctx->curarg); + } + findnextopt(ctx); + } + else { + if (*ctx->curarg == '\0') + findnextopt(ctx); + } + return c; +} + +int optdone(Optctx *ctx) { return *ctx->curarg == '\0' && ctx->finished; } -- cgit v1.1