/* simplifies * a || b * to * if a || b * t = true * else * t = false * ;; */ static Node *simplazy(Simp *s, Node *n) { Node *r, *t, *u; Node *ltrue, *lfalse, *ldone; /* set up temps and labels */ r = temp(s, n); ltrue = genlbl(); lfalse = genlbl(); ldone = genlbl(); /* simp the conditional */ simpcond(s, n, ltrue, lfalse); /* if true */ append(s, ltrue); u = mkexpr(n->line, Olit, mkbool(n->line, 1), NULL); u->expr.type = mktype(n->line, Tybool); t = set(r, u); append(s, t); jmp(s, ldone); /* if false */ append(s, lfalse); u = mkexpr(n->line, Olit, mkbool(n->line, 0), NULL); u->expr.type = mktype(n->line, Tybool); t = set(r, u); append(s, t); jmp(s, ldone); /* finish */ append(s, ldone); return r; }
static Node * comparecomplex(Flattenctx *s, Node *n, Op op) { Type *ty; Node *l, *r, *e; /* special case: unions with nullary constructors can be compared easily. */ ty = tybase(exprtype(n->expr.args[0])); if (ty->type == Tyunion && isenum(ty)) { l = mkexpr(n->loc, Outag, rval(s, n->expr.args[0]), NULL); r = mkexpr(n->loc, Outag, rval(s, n->expr.args[1]), NULL); l->expr.type = mktype(n->loc, Tyuint32); r->expr.type = mktype(n->loc, Tyuint32); if (op == Oeq) e = mkexpr(n->loc, Oueq, l, r, NULL); else if (op == One) e = mkexpr(n->loc, Oune, l, r, NULL); else fatal(n, "unsupported operator %s for enum union", opstr[op]); e->expr.type = mktype(n->loc, Tybool); return e; } fatal(n, "cannot compare values of type %s for equality\n", tystr(exprtype(n->expr.args[0]))); return NULL; }
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->line, Tyuint)); tag = mkintlit(n->line, uc->id); tag->expr.type = mktype(n->line, Tyuint); append(s, set(deref(u), tag)); /* fill the value, if needed */ if (!uc->etype) return tmp; elt = rval(s, n->expr.args[1], NULL); u = addk(u, Wordsz); if (stacktype(uc->etype)) { elt = addr(s, elt, uc->etype); sz = disp(n->line, tysize(uc->etype)); r = mkexpr(n->line, Oblit, u, elt, sz, NULL); } else { r = set(deref(u), elt); } append(s, r); return tmp; }
Node * mkboollit(Srcloc loc, int val) { Node *e; e = mkexpr(loc, Olit, mkbool(loc, val), NULL); e->expr.type = mktype(loc, Tybool); return e; }
static Dtree *addunion(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap) { Node *elt, *tag, *id; int32_t t1, t2; Dtree *sub; Ucon *uc; size_t i; if (t->any) return t->any; uc = finducon(tybase(exprtype(pat)), pat->expr.args[0]); t2 = uc->id; /* if we have the value already... */ sub = NULL; for (i = 0; i < t->nval; i++) { tag = t->val[i]->expr.args[0]; t1 = tag->lit.intval; if (t1 == t2) { if (pat->expr.nargs > 1) { elt = uvalue(val, exprtype(pat->expr.args[1])); return addpat(t->sub[i], pat->expr.args[1], elt, cap, ncap); } else { return t->sub[i]; } } } /* otherwise create a new match */ sub = mkdtree(); sub->patexpr = pat; tag = mkexpr(pat->loc, Outag, val, NULL); tag->expr.type = mktype(pat->loc, Tyint32); id = mkintlit(pat->loc, uc->id); id->expr.type = mktype(pat->loc, Tyint32); lappend(&t->val, &t->nval, id); lappend(&t->sub, &t->nsub, sub); lappend(&t->load, &t->nload, tag); if (pat->expr.nargs == 2) { elt = uvalue(val, exprtype(pat->expr.args[1])); sub = addpat(sub, pat->expr.args[1], elt, cap, ncap); } return sub; }
static void jmp(Flattenctx *s, Node *lbl) { Node *n; n = mkexpr(lbl->loc, Ojmp, lbl, NULL); n->expr.type = mktype(n->loc, Tyvoid); append(s, n); }
static void cjmp(Flattenctx *s, Node *cond, Node *iftrue, Node *iffalse) { Node *jmp; jmp = mkexpr(cond->loc, Ocjmp, cond, iftrue, iffalse, NULL); jmp->expr.type = mktype(cond->loc, Tyvoid); append(s, jmp); }
static Node *arrayelt(Node *n, size_t i) { 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; }
static Node *uconid(Simp *s, Node *n) { Ucon *uc; if (exprop(n) != Oucon) return load(addr(s, n, mktype(n->line, Tyuint))); uc = finducon(n); return word(uc->line, uc->id); }
static void rdtype(FILE *fd, Type **dest) { uintptr_t tid; tid = rdint(fd); if (tid & Builtinmask) { *dest = mktype(Zloc, tid & ~Builtinmask); } else { lappend(&typefixdest, &ntypefixdest, dest); lappend(&typefixid, &ntypefixid, itop(tid)); } }
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; }
/* flatten * a || b * to * if a || b * t = true * else * t = false * ;; */ static Node * flattenlazy(Flattenctx *s, Node *n) { 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); /* flatten the conditional */ flattencond(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 = asn(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 = asn(r, u); append(s, t); jmp(s, ldone); /* finish */ append(s, ldone); return r; }
static void dispose(Flattenctx *s, Stab *st, size_t n) { Node *e, *call, *func; Trait *tr; Type *ty; size_t i; tr = traittab[Tcdisp]; /* dispose in reverse order of appearance */ for (i = st->nautotmp; i-- > n;) { e = st->autotmp[i]; ty = exprtype(e); func = traitfn(Zloc, tr, "__dispose__", ty); call = mkexpr(Zloc, Ocall, func, e, NULL); call->expr.type = mktype(Zloc, Tyvoid); flatten(s, call); } }
static Node * visit(Flattenctx *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]); if (opispure[exprop(n)]) { r = n; } else { if (exprtype(n)->type == Tyvoid) { r = mkexpr(n->loc, Olit, mkvoid(n->loc), NULL); r->expr.type = mktype(n->loc, Tyvoid); append(s, n); } else { r = temp(s, n); append(s, asn(r, n)); } } return r; }
static Node * destructure(Flattenctx *s, Node *lhs, Node *rhs) { Node *lv, *rv, *idx; Node **args; size_t i; args = lhs->expr.args; rhs = rval(s, rhs); for (i = 0; i < lhs->expr.nargs; i++) { idx = mkintlit(rhs->loc, i); idx->expr.type = mktype(rhs->loc, Tyuint64); rv = mkexpr(rhs->loc, Otupget, rhs, idx, NULL); rv->expr.type = lhs->expr.type; if (exprop(args[i]) == Otup) { destructure(s, args[i], rv); } else { lv = lval(s, args[i]); append(s, assign(s, lv, rv)); } } return rhs; }
/* Writes types to a file. Errors on * internal only types like Tyvar that * will not be meaningful in another file */ static Type *tyunpickle(FILE *fd) { size_t i, n; Type *ty; Ty t; t = rdbyte(fd); ty = mktype(Zloc, t); ty->isimport = 1; if (rdbyte(fd) == Vishidden) ty->ishidden = 1; /* tid is generated; don't write */ n = rdint(fd); for (i = 0; i < n; i++) rdtrait(fd, NULL, ty); ty->nsub = rdint(fd); if (ty->nsub > 0) ty->sub = zalloc(ty->nsub * sizeof(Type*)); switch (ty->type) { case Tyunres: ty->name = unpickle(fd); break; case Typaram: ty->pname = rdstr(fd); break; case Tystruct: ty->nmemb = rdint(fd); ty->sdecls = zalloc(ty->nmemb * sizeof(Node*)); for (i = 0; i < ty->nmemb; i++) ty->sdecls[i] = unpickle(fd); break; case Tyunion: ty->nmemb = rdint(fd); ty->udecls = zalloc(ty->nmemb * sizeof(Node*)); for (i = 0; i < ty->nmemb; i++) ty->udecls[i] = rducon(fd, ty); break; case Tyarray: rdtype(fd, &ty->sub[0]); ty->asize = unpickle(fd); break; case Tyslice: rdtype(fd, &ty->sub[0]); break; case Tyname: ty->name = unpickle(fd); ty->issynth = rdbool(fd); ty->narg = rdint(fd); ty->arg = zalloc(ty->narg * sizeof(Type *)); for (i = 0; i < ty->narg; i++) rdtype(fd, &ty->arg[i]); rdtype(fd, &ty->sub[0]); break; case Tygeneric: ty->name = unpickle(fd); ty->issynth = rdbool(fd); ty->ngparam = rdint(fd); ty->gparam = zalloc(ty->ngparam * sizeof(Type *)); for (i = 0; i < ty->ngparam; i++) rdtype(fd, &ty->gparam[i]); rdtype(fd, &ty->sub[0]); break; default: for (i = 0; i < ty->nsub; i++) rdtype(fd, &ty->sub[i]); break; } return ty; }
static void umatch(Simp *s, Node *pat, Node *val, Type *t, Node *iftrue, Node *iffalse) { Node *v, *x, *y; Node *deeper, *next; Node **patarg; Ucon *uc; size_t i; size_t off; assert(pat->type == Nexpr); t = tybase(t); if (exprop(pat) == Ovar && !decls[pat->expr.did]->decl.isconst) { v = assign(s, pat, val); append(s, v); jmp(s, iftrue); return; } switch (t->type) { /* Never supported */ case Tyvoid: case Tybad: case Tyvalist: case Tyvar: case Typaram: case Tyunres: case Tyname: case Ntypes: /* Should never show up */ case Tyslice: die("Unsupported type for compare"); break; case Tybool: case Tychar: case Tybyte: case Tyint8: case Tyint16: case Tyint32: case Tyint: case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint: case Tyint64: case Tyuint64: case Tylong: case Tyulong: case Tyfloat32: case Tyfloat64: case Typtr: case Tyfunc: v = mkexpr(pat->line, Oeq, pat, val, NULL); v->expr.type = mktype(pat->line, Tybool); cjmp(s, v, iftrue, iffalse); break; /* We got lucky. The structure of tuple, array, and struct literals * is the same, so long as we don't inspect the type, so we can * share the code*/ case Tystruct: case Tytuple: case Tyarray: patarg = pat->expr.args; off = 0; for (i = 0; i < pat->expr.nargs; i++) { off = tyalign(off, size(patarg[i])); next = genlbl(); v = load(addk(addr(s, val, exprtype(patarg[i])), off)); umatch(s, patarg[i], v, exprtype(patarg[i]), next, iffalse); append(s, next); off += size(patarg[i]); } jmp(s, iftrue); break; case Tyunion: uc = finducon(pat); if (!uc) uc = finducon(val); deeper = genlbl(); x = uconid(s, pat); y = uconid(s, val); v = mkexpr(pat->line, Oeq, x, y, NULL); v->expr.type = tyintptr; cjmp(s, v, deeper, iffalse); append(s, deeper); if (uc->etype) { pat = patval(s, pat, uc->etype); val = patval(s, val, uc->etype); umatch(s, pat, val, uc->etype, iftrue, iffalse); } break; } }