static void flattencond(Flattenctx *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); flattencond(s, args[0], lnext, lfalse); append(s, lnext); flattencond(s, args[1], ltrue, lfalse); break; case Olor: lnext = genlbl(n->loc); flattencond(s, args[0], ltrue, lnext); append(s, lnext); flattencond(s, args[1], ltrue, lfalse); break; case Olnot: flattencond(s, args[0], lfalse, ltrue); break; default: v = rval(s, n); cjmp(s, v, ltrue, lfalse); break; } }
static Node* flattentern(Flattenctx *s, Node *n) { Node *l1, *l2, *l3; Node *res, *t; l1 = genlbl(n->loc); l2 = genlbl(n->loc); l3 = genlbl(n->loc); res = temp(s, n); flattencond(s, n->expr.args[0], l1, l2); append(s, l1); t = assign(s, res, rval(s, n->expr.args[1])); append(s, t); jmp(s, l3); append(s, l2); t = assign(s, res, rval(s, n->expr.args[2])); append(s, t); append(s, l3); return res; }
static void simpmatch(Simp *s, Node *n) { Node *end, *cur, *next; /* labels */ Node *val, *tmp; Node *m; size_t i; end = genlbl(); val = temp(s, n->matchstmt.val); tmp = rval(s, n->matchstmt.val, val); if (val != tmp) append(s, assign(s, val, tmp)); for (i = 0; i < n->matchstmt.nmatches; i++) { m = n->matchstmt.matches[i]; /* check pattern */ cur = genlbl(); next = genlbl(); umatch(s, m->match.pat, val, val->expr.type, cur, next); /* do the action if it matches */ append(s, cur); simp(s, m->match.block); jmp(s, end); append(s, next); } append(s, end); }
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(); simpcond(s, args[0], lnext, lfalse); append(s, lnext); simpcond(s, args[1], ltrue, lfalse); break; case Olor: lnext = genlbl(); 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; } }
/* init; while cond; body;; * => init * jmp :cond * :body * ...body... * ...step... * :cond * ...cond... * cjmp (cond) :body :end * :end */ static void simploop(Simp *s, Node *n) { Node *lbody; Node *lend; Node *lcond; Node *lstep; lbody = genlbl(); lcond = genlbl(); lstep = genlbl(); lend = genlbl(); 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 */ s->nloopstep--; s->nloopexit--; }
/* 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(); l2 = genlbl(); if (exit) l3 = exit; else l3 = genlbl(); 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); }
/* 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; }
/* pat; seq; * body;; * * => * .pseudo = seqinit * jmp :cond * :body * ...body... * :step * ...step... * :cond * ...cond... * cjmp (cond) :match :end * :match * ...match... * cjmp (match) :body :step * :end */ static void simpiter(Simp *s, Node *n) { Node *lbody, *lstep, *lcond, *lmatch, *lend; Node *idx, *len, *dcl, *seq, *val, *done; Node *zero; lbody = genlbl(); lstep = genlbl(); lcond = genlbl(); lmatch = genlbl(); lend = genlbl(); lappend(&s->loopstep, &s->nloopstep, lstep); lappend(&s->loopexit, &s->nloopexit, lend); zero = mkintlit(n->line, 0); zero->expr.type = tyintptr; seq = rval(s, n->iterstmt.seq, NULL); idx = gentemp(s, n, 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->line, Olt, idx, len, NULL); cjmp(s, done, lmatch, lend); simp(s, lmatch); val = load(idxaddr(s, seq, idx)); umatch(s, n->iterstmt.elt, val, val->expr.type, lbody, lstep); simp(s, lend); s->nloopstep--; s->nloopexit--; }
/* 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 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; } }