From 6b5838f72fe535afb542e888d7d2d2da3571bea2 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sat, 24 Feb 2024 17:47:39 +0200 Subject: initial commit + Now to do the actual hard parts, heh --- src/nodes.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 src/nodes.c (limited to 'src/nodes.c') diff --git a/src/nodes.c b/src/nodes.c new file mode 100644 index 0000000..9eb0113 --- /dev/null +++ b/src/nodes.c @@ -0,0 +1,225 @@ +#include +#include +#include + +#include +#include +#include + +void insadd(struct blk *b, enum insn_type o, enum val_type t, struct val r, struct val a0, struct val a1) +{ + struct insn i = insn_create(o, t, r, a0, a1); + vec_append(&b->insns, &i); +} + +int64_t idalloc(struct fn *f, const char *id) +{ + int64_t t = idmatch(f, id); + if (t >= 0) { + return t; + } + + t = f->ntmp++; + vec_append(&f->tmps, &(struct tmp_map){.id = id, .v = t}); + return t; +} + +int64_t idmatch(struct fn *f, const char *id) +{ + foreach_tmp(i, f->tmps) { + struct tmp_map t = tmp_at(f->tmps, i); + if (strcmp(t.id, id) == 0) + return t.v; + } + + return -1; +} + +void finish_block(struct blk *b, enum insn_type cmp, struct val a0, struct val a1, const char *label) +{ + assert(cmp >= BEQ && cmp <= RET && "illegal comparison type for block"); + b->btype = cmp; + b->cmp[0] = a0; + b->cmp[1] = a1; + b->to = label; +} + +struct blk *new_block(struct fn *f) +{ + struct blk *b = calloc(1, sizeof(struct blk)); + b->id = ++f->nblk; + b->insns = vec_create(sizeof(struct insn)); + vec_append(&f->blks, &b); + return b; +} + +static struct label_map label_find(struct fn *f, const char *name) +{ + foreach_label(i, f->labels) { + struct label_map m = label_at(f->labels, i); + if (strcmp(m.id, name) == 0) + return m; + } + + return (struct label_map){.id = NULL, .b = NULL}; +} + +bool blk_empty(struct blk *b) +{ + return vec_len(&b->insns) == 0; +} + +void finish_function(struct fn *f, const char *name) +{ + /** @todo check that returns match */ + f->name = name; + /* last block should always be empty and can be removed */ + struct blk *last_blk = blk_pop(f->blks); + if (!blk_empty(last_blk)) { + error("last block not empty, %s missing return?", name); + abort(); + } + + destroy_block(last_blk); + + foreach_blk(i, f->blks) { + struct blk *b = blk_at(f->blks, i); + if (!b->to) + continue; + + struct label_map m = label_find(f, b->to); + if (!m.id) { + error("no label %s", b->to); + abort(); + } + + b->s2 = m.b; + } + +} + +struct fn *new_function() +{ + struct fn *f = calloc(1, sizeof(struct fn)); + f->blks = vec_create(sizeof(struct blk *)); + f->tmps = vec_create(sizeof(struct tmp_map)); + f->labels = vec_create(sizeof(struct label_map)); + /* empty block */ + new_block(f); + return f; +} + +void destroy_function(struct fn *f) +{ + vec_destroy(&f->tmps); + vec_destroy(&f->labels); + + foreach_blk(i, f->blks) { + struct blk *b = blk_at(f->blks, i); + destroy_block(b); + } + vec_destroy(&f->blks); + + free(f); +} + +void destroy_block(struct blk *b) +{ + vec_destroy(&b->insns); + free(b); +} + +void new_label(struct fn *f, struct blk *b, const char *name) +{ + vec_append(&f->labels, &(struct label_map){.id = name, .b = b}); +} + +static const char *op_str(enum insn_type n) { +#define CASE(I) case I: return #I; + switch (n) { + FOREACH_INSN_TYPE(CASE); + } +#undef CASE + return "unknown"; +} + +void dump_val(struct val val) { + long long r = val.r; + long long v = val.v; + const char *s = val.s; + + switch (val.class) { + case REG: printf("r%lli", r); break; + case TMP: printf("t%lli", r); break; + case IMM: printf("%lli", v); break; + case MEM: printf("(r%lli, %lli)", r, v); break; + case REF: printf("\"%s\"", s); break; + case NOCLASS: break; + } +} + +void dump_insn(struct insn i) +{ + printf("\t"); + + if (hasclass(i.out)) { + dump_val(i.out); + printf(" "); + } + + printf("%s", op_str(i.type)); + + if (hasclass(i.in[0])) { + printf(" "); + dump_val(i.in[0]); + } + + if (hasclass(i.in[1])) { + printf(" "); + dump_val(i.in[1]); + } + + printf("\n"); +} + +bool return_blk(struct blk *b) +{ + return b->btype == RET; +} + +void dump_block(struct blk *b) +{ + printf("\t/*** block %lld ", (long long)b->id); + if (b->name) printf("(%s) ", b->name); + printf("***/\n"); + + foreach_insn(i, b->insns) { + struct insn n = insn_at(b->insns, i); + dump_insn(n); + } + + if (return_blk(b)) { + printf("\n"); + return; + } + + if (b->btype != J) { + assert(b->s2); + struct blk *s2 = b->s2; + printf("\t%s ", op_str(b->btype)); + dump_val(b->cmp[0]); + printf(" "); + dump_val(b->cmp[1]); + printf(" -> %lli\n", (long long)s2->id); + } + printf("\n"); +} + +void dump_function(struct fn *f) { + printf("/*** function %s ***/\n", f->name); + foreach_blk(i, f->blks) { + struct blk *b = blk_at(f->blks, i); + dump_block(b); + } + printf("\n"); +} -- cgit v1.3