#include "from.h" #include "cgen.h" #include "fn.h" #include "errloc.h" #include "stmt.h" #include "storage.h" #include "tmp.h" #include "type.h" #include #include #include #include #include void from_free(struct from *fr) { } static int loadvar(const struct from_it *st, struct cgen *c) { const struct stentry *e = st->u.e; size_t sz = e->t->sz; const char *tmp = cgen_tmp(sz); printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(e->t)); cgen_printvar(c->fn, e); putchar('\n'); return 0; } /* TODO: de-duplicate function */ static unsigned long long tonum(const char *s) { unsigned long long v; char *end; errno = 0; v = strtoull(s, &end, 0); if (*s == '-' || errno || *end) return strtoll(s, NULL, 0); return v; } static int loadval(const struct from *fr, struct cgen *c) { const struct stentry *dst = fr->var; const struct from_it *st = &fr->start; unsigned long long v = tonum(st->u.tk->s); printf("store%s %llu, ", cgen_sz(dst->t->sz), v); cgen_printvar(c->fn, dst); putchar('\n'); return 0; } static int endvar(const struct from *fr, struct cgen *c) { fprintf(stderr, "%s: TODO\n", __func__); return -1; } static int endval(const struct from *fr, struct cgen *c) { const struct stentry *src = fr->var; size_t sz = src->t->sz; const char *tmp = cgen_tmp(sz); const struct from_it *end = &fr->end; const struct tk *tk = end->u.tk; int neg = *tk->s == '-'; size_t bl = fr->block_i; printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(src->t)); cgen_printvar(c->fn, src); putchar('\n'); printf("%%%s =%s c", tmp, cgen_sz(sz)); fputs(neg ? "sge" : "uge", stdout); printf("%s ", cgen_sz(sz)); printf("%%%s, %s\n", tmp, tk->s); printf("jnz %%%s, @__end%zu, @__blockbody%zu\n", tmp, bl, bl); printf("@__blockbody%zu\n", bl); return 0; } static int from_var(const struct from *fr, struct cgen *c) { const struct from_it *st = &fr->start; switch (st->type) { case FR_VAR: if (loadvar(st, c)) return -1; break; case FR_VAL: if (loadval(fr, c)) return -1; break; } printf("@__block%zu\n", fr->block_i); switch (fr->end.type) { case FR_VAR: if (endvar(fr, c)) return -1; break; case FR_VAL: if (endval(fr, c)) return -1; break; } return 0; } int from_cgen(const struct from *fr, struct cgen *c) { return from_var(fr, c); } static int from_end(const struct stmt *s, struct cgen *c) { const struct from *fr = &s->u.from; const struct stentry *src = fr->var; const struct type *t = src->t; size_t sz = t->sz; const char *tmp = cgen_tmp(sz); const struct fn *fn = c->fn; printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(t)); cgen_printvar(fn, src); putchar('\n'); printf("%%%s =%s add %%%s, 1\n", tmp, cgen_sz(sz), tmp); printf("store%s %%%s, ", cgen_sz(sz), tmp); cgen_printvar(fn, src); putchar('\n'); printf("jmp @__block%zu\n", fr->block_i); return 0; } static int checksym(const struct fn *fn, const struct tk *tk, struct from_it *fr) { const struct stentry *e = fn_var(fn, tk); if (!e) { errloc(tk, "undefined reference to \"%s\"", tk->s); return -1; } switch (e->t->type) { case C: case BUILTIN: break; case U: case S: case P: case T: case PTR: case ARY: { char *s = type_name(e->t); if (s) errloc(tk, "\"%s\" (\"%s\") cannot be used in \"from\" loop", tk->s, s); free(s); return -1; } } fr->type = FR_VAR; fr->u.e = e; return 0; } static int check(const struct fn *fn, const struct tk *tk, struct from_it *fr) { switch (tk->type) { case NUM: fr->type = FR_VAL; fr->u.tk = tk; break; case ID: return checksym(fn, tk, fr); case LIT: errloc(tk, "unexpected literal"); return -1; case UNDEF: case ANY: fprintf(stderr, "%s: unreachable\n", __func__); return -1; } return 0; } static int finalize(struct prv *p, struct fn *fn, struct from *fr) { struct stmt *s; struct pos *pos = &p->pos[p->i]; size_t nst = fn->nstmts + 1, nbl = fn->nblocks + 1, *bl = realloc(fn->blocks, nbl * sizeof *bl); if (!bl) { perror("realloc(3)"); return -1; } fr->block_i = bl[fn->nblocks++] = fn->nstmts; fn->blocks = bl; if (!(s = realloc(fn->stmts, nst * sizeof *s))) { perror("realloc(3)"); return -1; } s[fn->nstmts++] = (struct stmt) { .type = FROM, .u.from = *fr, .end = from_end }; fn->stmts = s; pos->seq = pos->stseq = stmts; pos->step = stmts->steps; fprintf(stderr, ", iterator %s, block index %zu\n", fr->var->tk->s, bl[fn->nblocks - 1]); return 0; } static const struct type *valtype(const struct fn *fn, const struct tk *tk) { char *end; errno = 0; strtol(tk->s, &end, 0); if (errno || *end) { errno = 0; strtoll(tk->s, &end, 0); if (errno || *end) return type_find(fn, "ulong"); return type_find(fn, "long"); } return type_find(fn, "word"); } static const struct type *ittype(const struct fn *fn, const struct from_it *it) { switch (it->type) { case FR_VAL: return valtype(fn, it->u.tk); case FR_VAR: return it->u.e->t; } fprintf(stderr, "%s: unreachable\n", __func__); return NULL; } static const struct type *gettype(const struct fn *fn, const struct from_it *a, const struct from_it *b) { const struct type *ta = ittype(fn, a), *tb = ittype(fn, b); return ta->sz > tb->sz ? ta : tb; } int from(const struct lex *l, struct prv *p) { const struct tk *start = p->stk + 1, *end = p->stk + 3; struct fn *fn = fn_cur(p); struct from fr = {0}; const struct type *t; if (check(fn, start, &fr.start) || check(fn, end, &fr.end) || !(t = gettype(fn, &fr.start, &fr.end)) || !(fr.var = tmp_create(fn, t))) return -1; fprintf(stderr, "\t\tadding from statement [%s, %s]", start->s, end->s); if (finalize(p, fn, &fr)) return -1; p->stk = ++end; return 1; } static int checkvar(const struct fn *fn, const struct tk *tk, struct from *fr) { const struct stentry *e; if (tk->type != ID) { errloc(tk, "\"%s\" not a variable", tk->s); return -1; } else if (!(e = fn_var(fn, tk))) { errloc(tk, "undefined reference to \"%s\"", tk->s); return -1; } else if (e->t->type != BUILTIN) { errloc(tk, "variable \"%s\" not an integer", tk->s); return -1; } fr->var = e; return 0; } int from_id(const struct lex *l, struct prv *p) { const struct tk *start = p->stk + 1, *end = p->stk + 3, *var = p->stk + 5; struct fn *fn = fn_cur(p); struct from fr = {0}; if (check(fn, start, &fr.start) || check(fn, end, &fr.end) || checkvar(fn, var, &fr)) return -1; fprintf(stderr, "\t\tadding from statement [%s, %s] using %s", start->s, end->s, var->s); if (finalize(p, fn, &fr)) return -1; p->stk = ++var; return 1; } int from_by(const struct lex *l, struct prv *p) { fprintf(stderr, "%s: TODO\n", __func__); return -1; } int from_idby(const struct lex *l, struct prv *p) { fprintf(stderr, "%s: TODO\n", __func__); return -1; }