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; }
/* 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 *base, *sz, *len; Node *stbase, *stlen; if (dst) t = dst; else t = temp(s, n); /* *(&slice) = (void*)base + off*sz */ base = slicebase(s, n->expr.args[0], 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->line, tyintptr)), base); sz = addk(simpcast(s, t, mktyptr(t->line, tyintptr)), Ptrsz); } else { stbase = set(deref(addr(s, t, tyintptr)), base); sz = addk(addr(s, t, tyintptr), Ptrsz); } /* *(&slice + ptrsz) = len */ stlen = set(deref(sz), len); append(s, stbase); append(s, stlen); return t; }
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 *slicebase(Simp *s, Node *n, Node *off) { Node *t, *u, *v; Type *ty; int sz; t = rval(s, n, NULL); u = NULL; ty = tybase(exprtype(n)); switch (ty->type) { case Typtr: u = t; break; case Tyarray: u = addr(s, t, base(exprtype(n))); break; case Tyslice: u = load(addr(s, t, mktyptr(n->line, 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->line, sz)); return add(u, v); } else { return u; } }
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 * asn(Node *a, Node *b) { Node *n; assert(a != NULL && b != NULL); if (tybase(exprtype(a))->type == Tyvoid) return a; n = mkexpr(a->loc, Oasn, a, b, NULL); n->expr.type = exprtype(a); 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 <= Tyfloat64) return 1; return 0; }
/* gets the byte offset of 'memb' within the aggregate type 'aggr' */ static size_t offset(Node *aggr, Node *memb) { Type *ty; Node **nl; size_t i; size_t off; ty = tybase(exprtype(aggr)); if (ty->type == Typtr) ty = tybase(ty->sub[0]); assert(ty->type == Tystruct); nl = ty->sdecls; off = 0; for (i = 0; i < ty->nmemb; i++) { off = tyalign(off, size(nl[i])); if (!strcmp(namestr(memb), declname(nl[i]))) return off; off += size(nl[i]); } die("Could not find member %s in struct", namestr(memb)); return -1; }
static int isexhaustive(Dtree *dt) { Type *subt; size_t i; if (dt->any) return 1; if (dt->nsub > 0) { subt = tybase(exprtype(dt->sub[0]->patexpr)); if (dt->nsub != nconstructors(subt)) return 0; } switch (exprop(dt->patexpr)) { case Ovar: return 1; case Olit: return 1; case Oucon: for (i = 0; i < dt->nsub; i++) if (!isexhaustive(dt->sub[i])) return 0; return 1; break; case Otup: for (i = 0; i < dt->nsub; i++) if (!isexhaustive(dt->sub[i])) return 0; return 1; break; case Oarr: for (i = 0; i < dt->nsub; i++) if (!isexhaustive(dt->sub[i])) return 0; return 1; break; case Ostruct: for (i = 0; i < dt->nsub; i++) if (!isexhaustive(dt->sub[i])) return 0; return 1; break; default: die("Invalid pattern in exhaustivenes check. BUG."); break; } return 0; }
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; }
static void checkundef(Node *n, Reaching *r, Bitset *reach, Bitset *kill) { 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; } } }
/* We treat all integer types, boolean types, etc, as having 2^n constructors. * * since, of course, we can't represent all of the constructors for 64 bit * integers using 64 bit values, we just approximate it. We'd have failed (run * out of memory, etc) long before getting to this code if we actually had that * many branches of the switch statements anyways. */ 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; }
static Ucon *finducon(Node *n) { size_t i; Type *t; Ucon *uc; t = tybase(n->expr.type); if (exprop(n) != Oucon) return NULL; for (i = 0; i < t->nmemb; i++) { uc = t->udecls[i]; if (!strcmp(namestr(uc->name), namestr(n->expr.args[0]))) return uc; } die("No ucon?!?"); return NULL; }
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 Node *membaddr(Simp *s, Node *n) { 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->line, offset(args[0], args[1])); r = add(t, u); r->expr.type = mktyptr(n->line, n->expr.type); return r; }
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; 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 (isval(args[0], 0)) r = args[1]; if (isval(args[1], 0)) r = args[0]; if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a + b, exprtype(n)); break; case Osub: /* x - 0 = 0 */ if (isval(args[1], 0)) r = args[0]; if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a - b, exprtype(n)); break; case Omul: /* 1 * x = x */ if (isval(args[0], 1)) r = args[1]; if (isval(args[1], 1)) r = args[0]; /* 0 * x = 0 */ if (isval(args[0], 0)) r = args[0]; if (isval(args[1], 0)) r = args[1]; if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a * b, exprtype(n)); break; case Odiv: /* x/1 = x */ if (isval(args[1], 1)) r = args[0]; /* 0/x = 0 */ if (isval(args[1], 0)) r = args[1]; if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a / b, exprtype(n)); break; case Omod: /* x%1 = x */ if (isval(args[1], 0)) r = args[0]; if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a % b, exprtype(n)); break; case Oneg: if (islit(args[0], &a)) r = val(n->line, -a, exprtype(n)); break; case Obsl: if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a << b, exprtype(n)); break; case Obsr: if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a >> b, exprtype(n)); break; case Obor: if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a | b, exprtype(n)); break; case Oband: if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a & b, exprtype(n)); break; case Obxor: if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, 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 Ocast: r = foldcast(n); break; default: break; } if (r) return r; else return n; }
int stacktype(Type *t) { /* the types are arranged in types.def such that this is true */ t = tybase(t); return t->type >= Tyslice; }
int floattype(Type *t) { t = tybase(t); return t->type == Tyfloat32 || t->type == Tyfloat64; }
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; } }
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 Tylong: case Tyulong: case Tychar: case Tybyte: case Typtr: t = tybase(exprtype(val)); switch (t->type) { /* ptr -> slice conversion is disallowed */ case Tyslice: if (t->type == Typtr) fatal(val->line, "Bad cast from %s to %s", tystr(exprtype(val)), tystr(to)); r = slicebase(s, val, NULL); break; /* signed conversions */ case Tyint8: case Tyint16: case Tyint32: case Tyint64: case Tyint: case Tylong: r = intconvert(s, val, to, 1); break; /* unsigned conversions */ case Tybool: case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64: case Tyuint: case Tyulong: case Tychar: case Tybyte: case Typtr: r = intconvert(s, val, to, 0); break; case Tyfloat32: case Tyfloat64: if (tybase(to)->type == Typtr) fatal(val->line, "Bad cast from %s to %s", tystr(exprtype(val)), tystr(to)); r = mkexpr(val->line, Oflt2int, rval(s, val, NULL), NULL); r->expr.type = to; break; default: fatal(val->line, "Bad cast from %s to %s", tystr(exprtype(val)), tystr(to)); } break; case Tyfloat32: case Tyfloat64: 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 Tylong: case Tyulong: case Tychar: case Tybyte: r = mkexpr(val->line, Oflt2int, rval(s, val, NULL), NULL); r->expr.type = to; break; default: fatal(val->line, "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->line, "Bad cast from %s to %s", tystr(exprtype(val)), tystr(to)); } return r; }
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%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, 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; default: break; } if (r && n->expr.idx) r->expr.idx = n->expr.idx; if (r) return r; else return n; }