diff options
-rw-r--r-- | 6/asm.h | 316 | ||||
-rw-r--r-- | 6/blob.c | 378 | ||||
-rw-r--r-- | 6/gen.c | 220 | ||||
-rw-r--r-- | 6/gengas.c | 726 | ||||
-rw-r--r-- | 6/genp9.c | 766 | ||||
-rw-r--r-- | 6/isel.c | 1744 | ||||
-rw-r--r-- | 6/locs.c | 336 | ||||
-rw-r--r-- | 6/main.c | 376 | ||||
-rw-r--r-- | 6/peep.c | 96 | ||||
-rw-r--r-- | 6/ra.c | 2183 | ||||
-rw-r--r-- | 6/simp.c | 2886 | ||||
-rw-r--r-- | 6/typeinfo.c | 595 | ||||
-rw-r--r-- | bench/runner.c | 84 | ||||
-rw-r--r-- | mi/cfg.c | 456 | ||||
-rw-r--r-- | mi/dfcheck.c | 184 | ||||
-rw-r--r-- | mi/fold.c | 390 | ||||
-rw-r--r-- | mi/match.c | 1288 | ||||
-rw-r--r-- | mi/mi.h | 48 | ||||
-rw-r--r-- | mi/reaching.c | 233 | ||||
-rw-r--r-- | mk/lexyacc.mk | 2 | ||||
-rw-r--r-- | muse/muse.c | 140 | ||||
-rw-r--r-- | parse/bitset.c | 240 | ||||
-rw-r--r-- | parse/dump.c | 408 | ||||
-rw-r--r-- | parse/gram.y | 1387 | ||||
-rw-r--r-- | parse/htab.c | 377 | ||||
-rw-r--r-- | parse/infer.c | 4048 | ||||
-rw-r--r-- | parse/names.c | 11 | ||||
-rw-r--r-- | parse/node.c | 532 | ||||
-rw-r--r-- | parse/parse.h | 625 | ||||
-rw-r--r-- | parse/specialize.c | 832 | ||||
-rw-r--r-- | parse/stab.c | 644 | ||||
-rw-r--r-- | parse/tok.c | 1330 | ||||
-rw-r--r-- | parse/type.c | 1341 | ||||
-rw-r--r-- | parse/use.c | 1826 | ||||
-rw-r--r-- | parse/util.c | 653 |
35 files changed, 13770 insertions, 13931 deletions
@@ -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 */ @@ -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; } @@ -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; + } } @@ -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); } @@ -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); } @@ -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); } @@ -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]); } @@ -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; } @@ -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); + } } @@ -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"); } @@ -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 <stdlib.h> -#include <stdio.h> - -#include <fcntl.h> -#include <unistd.h> -#include <err.h> -#include <sys/types.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/wait.h> - -#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; -} - @@ -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); } @@ -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; } @@ -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); } @@ -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 <uconlist> 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, "<e>("); - 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<e%zd>:%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, "<e>("); + 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<e%zd>:%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, "<e1:%s> %s <e2:%s>", t1, oppretty[exprop(n)], t2); - break; - case OTpre: - bprintf(buf, sizeof buf, "%s<e%s>", t1, oppretty[exprop(n)]); - break; - case OTpost: - bprintf(buf, sizeof buf, "<e:%s>%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[<e1:%s>]", namestr(args[0]->expr.args[0]), t2); - else - bprintf(buf, sizeof buf, "<sl:%s>[<e1%s>]", t1, t2); - break; - case Oslice: - if (exprop(args[0]) == Ovar) - bprintf(buf, sizeof buf, "%s[<e1:%s>:<e2:%s>]", namestr(args[0]->expr.args[0]), t2, t3); - else - bprintf(buf, sizeof buf, "<sl:%s>[<e1%s>:<e2:%s>]", 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<e%s>", t1, oppretty[exprop(n)]); break; + case OTpost: bprintf(buf, sizeof buf, "<e:%s>%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, "<e1:%s> %s <e2:%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[<e1:%s>]", namestr(args[0]->expr.args[0]), t2); + else + bprintf(buf, sizeof buf, "<sl:%s>[<e1%s>]", t1, t2); + break; + case Oslice: + if (exprop(args[0]) == Ovar) + bprintf(buf, sizeof buf, "%s[<e1:%s>:<e2:%s>]", namestr(args[0]->expr.args[0]), t2, t3); + else + bprintf( buf, sizeof buf, "<sl:%s>[<e1%s>:<e2:%s>]", 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]))); |