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 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 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; } }
Node * fold(Node *n, int foldvar) { Node **args, *r; Type *t; vlong a, b; Ucon *uc; 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 Outag: if (exprop(args[0]) != Oucon) break; uc = finducon(tybase(exprtype(args[0])), args[0]->expr.args[0]); r = val(n->loc, uc->id, exprtype(n)); break; case Oudata: if (exprop(args[0]) != Oucon || args[0]->expr.nargs != 2) break; r = args[0]->expr.args[1]; break; 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, (uint64_t)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%0 = error */ if (isintval(args[1], 0)) fatal(args[1], "division by zero"); /* x%1 = 0 */ if (isintval(args[1], 1)) r = val(n->loc, 0, exprtype(n)); 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, (uint64_t)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; r->expr.type = exprtype(n); } break; case Oarr: if (n->expr.nargs > 0) qsort(n->expr.args, n->expr.nargs, sizeof(Node*), idxcmp); break; case Ocast: r = foldcast(n); break; case Osize: if (sizefn) r = val(n->loc, sizefn(n->expr.args[0]), exprtype(n)); break; default: break; } if (r && n->expr.idx) r->expr.idx = n->expr.idx; if (r) return r; else return n; }