From: David Given Date: Sun, 18 Sep 2016 21:24:54 +0000 (+0200) Subject: Archival checking of the half-written IR treebuilder. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=176cd7365c5bf441624ac5f0771c233ca21de3f6;p=ack.git Archival checking of the half-written IR treebuilder. --- diff --git a/mach/proto/mcg/array.c b/mach/proto/mcg/array.c new file mode 100644 index 000000000..1b72352b0 --- /dev/null +++ b/mach/proto/mcg/array.c @@ -0,0 +1,39 @@ +#include "mcg.h" +#include "array.h" + +void array_append(void*** array, int* count, int* max, void* value) +{ + if (*count == *max) + { + int newmax = (*max == 0) ? 8 : (*max * 2); + void** newarray = realloc(*array, newmax * sizeof(void*)); + if (!newarray) + fatal("memory allocation failure"); + + *max = newmax; + *array = newarray; + } + + (*array)[*count] = value; + (*count)++; +} + +bool array_contains(void** array, int count, void* value) +{ + int i; + + for (i=0; i +#include + +static int next_id = 0; + +void bb_init(void) +{ + init_idf(); +} + +struct basicblock* bb_get(const char* name) +{ + struct idf* p; + + if (!name) + name = aprintf("___anon_bb_%d", next_id++); + p = str2idf((char*) name, 0); + if (!p->block) + { + p->block = calloc(sizeof(struct basicblock), 1); + p->block->name = name; + } + return p->block; +} + +void bb_alias(struct basicblock* block, const char* name) +{ + struct idf* p = str2idf((char*) name, -1); + assert(p == NULL); + + p = str2idf((char*) name, 0); + p->block = block; +} + +void bb_wire_outs_to_ins(struct basicblock* inblock, struct basicblock* outblock) +{ + int i; + + if (!outblock->is_wired) + { + for (i=0; iouts_count; i++) + { + struct ir* value = inblock->outs[i]; + APPEND(outblock->ins, + new_phiir(value->size) + ); + } + outblock->is_wired = true; + } + + assert(inblock->outs_count == outblock->ins_count); + for (i=0; iouts_count; i++) + { + struct ir* srcvalue = inblock->outs[i]; + struct ir* destvalue = outblock->ins[i]; + assert(srcvalue->size == destvalue->size); + assert(destvalue->opcode == IR_PHI); + + APPENDU(destvalue->u.phivalue.srcs, srcvalue); + } +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua index ef53f2802..5db304b46 100644 --- a/mach/proto/mcg/build.lua +++ b/mach/proto/mcg/build.lua @@ -1,12 +1,12 @@ normalrule { - name = "push_pop_c", - outleaves = { "push_pop.c" }, + name = "ircodes", + outleaves = { "ircodes.h", "ircodes.c" }, ins = { - "./push_pop.awk", - "h/em_table" + "./ircodes.sh", + "./ir.dat" }, commands = { - "awk -f %{ins[1]} %{ins[2]} > %{outs}" + "%{ins[1]} %{ins[2]} %{outs[1]} %{outs[2]}" } } @@ -14,16 +14,22 @@ cprogram { name = "mcg", srcs = { "./*.c", - "+push_pop_c", + matching(filenamesof("+ircodes"), "%.c$") }, deps = { + "+ircodes", "h+emheaders", "modules+headers", - "modules/src/read_em+lib_kv", + "modules/src/alloc+lib", "modules/src/em_code+lib_k", "modules/src/em_data+lib", - "modules/src/alloc+lib", + "modules/src/idf+lib", + "modules/src/read_em+lib_kv", "modules/src/system+lib", + "./*.h", + }, + vars = { + ["+cflags"] = {"-Werror-implicit-function-declaration"} } } diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c new file mode 100644 index 000000000..acc14c0fd --- /dev/null +++ b/mach/proto/mcg/data.c @@ -0,0 +1,113 @@ +#include "mcg.h" +#include + +static struct symbol* pending; + +void data_label(const char* label) +{ + if (pending) + fatal("two consecutive data labels ('%s' and '%s')", + pending->name, label); + + pending = symbol_get(label); + if (pending->is_defined) + fatal("label '%s' defined twice", pending->name); + pending->is_defined = true; +} + +static const char* section_to_str(int section) +{ + switch (section) + { + case SECTION_ROM: return ".rom"; + case SECTION_DATA: return ".data"; + case SECTION_BSS: return ".bss"; + case SECTION_TEXT: return ".text"; + default: return "unknown"; + } +} + +static void emit_header(int desired_section) +{ + if (pending) + { + if (pending->section == SECTION_UNKNOWN) + pending->section = desired_section; + else if (pending->section != desired_section) + fatal("label '%s' can't change sections", pending->name); + + printf("\n.sect %s\n", section_to_str(pending->section)); + printf("%s:\n", pending->name); + pending = NULL; + } +} + +void data_int(arith data, size_t size, bool is_ro) +{ + emit_header(is_ro ? SECTION_ROM : SECTION_DATA); + assert((size == 1) || (size == 2) || (size == 4) || (size == 8)); + printf("\t.data%d 0x%0*lld\n", size, size*2, data); +} + +void data_block(const uint8_t* data, size_t size, bool is_ro) +{ + const uint8_t* start = data; + const uint8_t* end = data + size; + const uint8_t* p = data; + + emit_header(is_ro ? SECTION_ROM : SECTION_DATA); + + start = p = data; + while (p < end) + { + while ((p < end) && isprint(*p)) + p++; + + if (start < p) + { + printf("\t.ascii \""); + while (start < p) + { + printf("%c", *start); + start++; + } + printf("\"\n"); + } + + while ((p < end) && !isprint(*p)) + p++; + + if (start < p) + { + bool first = true; + + printf("\t.data1 "); + while (start < p) + { + if (!first) + printf(", "); + printf("0x%02x", *start); + start++; + first = false; + } + printf("\n"); + } + } +} + +void data_offset(const char* label, arith offset, bool is_ro) +{ + emit_header(is_ro ? SECTION_ROM : SECTION_DATA); + printf("\t.data%d %s+%lld\n", EM_pointersize, label, offset); +} + +void data_bss(arith size, int init) +{ + if (init != 0) + fatal("non-zero-initialised bss not supported"); + + emit_header(SECTION_BSS); + printf("\t.space %lld\n", size); +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c new file mode 100644 index 000000000..8973bfc73 --- /dev/null +++ b/mach/proto/mcg/ir.c @@ -0,0 +1,137 @@ +#include "mcg.h" + +static int next_id = 0; + +struct ir* new_ir0(int opcode, int size) +{ + struct ir* ir = calloc(sizeof(struct ir), 1); + ir->id = next_id++; + ir->opcode = opcode; + ir->size = size; + + switch (ir->opcode) + { + case IR_JUMP: + case IR_CJUMP: + ir->terminates = true; + break; + } + + return ir; +} + +struct ir* new_ir1(int opcode, int size, + struct ir* c1) +{ + struct ir* ir = new_ir0(opcode, size); + ir->children[0] = c1; + return ir; +} + +struct ir* new_ir2(int opcode, int size, + struct ir* c1, struct ir* c2) +{ + struct ir* ir = new_ir0(opcode, size); + ir->children[0] = c1; + ir->children[1] = c2; + return ir; +} + +struct ir* new_ir3(int opcode, int size, + struct ir* c1, struct ir* c2, struct ir* c3) +{ + struct ir* ir = new_ir0(opcode, size); + ir->children[0] = c1; + ir->children[1] = c2; + ir->children[2] = c3; + return ir; +} + +struct ir* new_labelir(const char* label) +{ + struct ir* ir = new_ir0(IR_LABEL, EM_pointersize); + ir->u.lvalue = label; + return ir; +} + +struct ir* new_wordir(arith value) +{ + struct ir* ir = new_ir0(IR_ICONST, EM_wordsize); + ir->u.ivalue = value; + return ir; +} + +struct ir* new_regir(int reg) +{ + struct ir* ir = new_ir0(IR_REG, EM_pointersize); + ir->u.rvalue = reg; + return ir; +} + +struct ir* new_bbir(struct basicblock* bb) +{ + struct ir* ir = new_ir0(IR_BLOCK, EM_pointersize); + ir->u.bvalue = bb; + return ir; +} + +struct ir* new_anyir(int size) +{ + return new_ir0(IR_ANY, size); +} + +struct ir* new_phiir(int size) +{ + return new_ir0(IR_PHI, size); +} + +void ir_print(const struct ir* ir) +{ + int i; + for (i=0; ichildren)/sizeof(*ir->children); i++) + { + if (ir->children[i]) + ir_print(ir->children[i]); + } + + printf("\t; %c ", + ir->sequence ? 'S' : ' '); + printf("$%d = ", ir->id); + printf("%s%d(", + ir_names[ir->opcode], + ir->size); + + switch (ir->opcode) + { + case IR_ICONST: + printf("%d", ir->u.ivalue); + break; + + case IR_LABEL: + printf("%s", ir->u.lvalue); + break; + + case IR_REG: + printf("%d", ir->u.rvalue); + break; + + case IR_BLOCK: + printf("%s", ir->u.bvalue->name); + break; + + default: + for (i=0; ichildren)/sizeof(*ir->children); i++) + { + if (ir->children[i]) + { + if (i > 0) + printf(", "); + printf("$%d", ir->children[i]->id); + } + } + } + + printf(")\n"); +} + +/* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/ir.dat b/mach/proto/mcg/ir.dat new file mode 100644 index 000000000..044f9c0f3 --- /dev/null +++ b/mach/proto/mcg/ir.dat @@ -0,0 +1,33 @@ +# Simple terminals +ICONST +REG +LABEL +BLOCK +ANY +PHI + +# Memory operations +LOAD +STORE + +# Arithemetic operations +ADD + +# Conversions +FROMI1 +FROMI2 +FROMI4 +FROMI8 + +# Comparisons +COMPARES +COMPAREU + +# Flow control +JUMP +CJUMP +RET + +# Special +SETREG + diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h new file mode 100644 index 000000000..33b892528 --- /dev/null +++ b/mach/proto/mcg/ir.h @@ -0,0 +1,53 @@ +#ifndef IR_H +#define IR_H + +#include "ircodes.h" + +enum +{ + IRR_LB = -1, + IRR_AB = -2, + IRR_SP = -3, + IRR_RR = -4, +}; + +struct ir +{ + int id; + int opcode; + int size; + struct ir* children[3]; + union { + arith ivalue; + int rvalue; + const char* lvalue; + struct basicblock* bvalue; + struct { + ARRAY(struct ir, srcs); + } phivalue; + } u; + bool sequence : 1; + bool terminates : 1; +}; + +extern const char* ir_names[]; + +extern struct ir* new_ir0(int opcode, int size); +extern struct ir* new_ir1(int opcode, int size, + struct ir* c1); +extern struct ir* new_ir2(int opcode, int size, + struct ir* c1, struct ir* c2); +extern struct ir* new_ir3(int opcode, int size, + struct ir* c1, struct ir* c2, struct ir* c3); + +extern struct ir* new_labelir(const char* label); +extern struct ir* new_regir(int reg); +extern struct ir* new_wordir(arith value); +extern struct ir* new_bbir(struct basicblock* bb); +extern struct ir* new_anyir(int size); +extern struct ir* new_phiir(int size); + +extern void ir_print(const struct ir* ir); + +#endif + diff --git a/mach/proto/mcg/ircodes.sh b/mach/proto/mcg/ircodes.sh new file mode 100755 index 000000000..8f88b8bf4 --- /dev/null +++ b/mach/proto/mcg/ircodes.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +in=$1 +header=$2 +source=$3 + +echo "enum {" > $header +sed -n 's/^[A-Z].*$/IR_&,/p' < $in >> $header +echo "};" >> $header + +echo "const char* ir_names[] = {" > $source +sed -n 's/^[A-Z].*$/"&",/p' < $in >> $source +echo "};" >> $source + diff --git a/mach/proto/mcg/main.c b/mach/proto/mcg/main.c index 035259d54..a89b5a7d9 100644 --- a/mach/proto/mcg/main.c +++ b/mach/proto/mcg/main.c @@ -1,5 +1,4 @@ #include "mcg.h" -#include "em_comp.h" void fatal(const char* msg, ...) { @@ -13,8 +12,31 @@ void fatal(const char* msg, ...) abort(); } +const char* aprintf(const char* fmt, ...) +{ + int n; + char* p; + va_list ap; + + va_start(ap, fmt); + n = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + p = malloc(n); + if (!p) + return NULL; + + va_start(ap, fmt); + vsnprintf(p, n, fmt, ap); + va_end(ap); + + return p; +} + int main(int argc, char* argv[]) { + symbol_init(); + if (!EM_open(argv[1])) fatal("Couldn't open input file: %s", EM_error); diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index e008249ed..06e8160eb 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -16,24 +16,69 @@ #include "em_mnem.h" #include "em_flag.h" #include "em_ptyp.h" +#include "array.h" +#include "ir.h" extern char em_pseu[][4]; extern char em_mnem[][4]; extern char em_flag[]; +enum { + SECTION_UNKNOWN = 0, + SECTION_ROM, + SECTION_DATA, + SECTION_BSS, + SECTION_TEXT +}; + +struct symbol { + const char* name; + int section; + bool is_defined : 1; + bool is_exported : 1; + bool is_proc : 1; +}; + +enum { + PARAM_NONE, + PARAM_VALUE, + PARAM_LABEL +}; + +struct basicblock { + const char* name; + ARRAY(struct ir, irs); + ARRAY(struct basicblock, inblocks); + ARRAY(struct basicblock, outblocks); + ARRAY(struct ir, outs); + ARRAY(struct ir, ins); + bool is_wired : 1; +}; extern void fatal(const char* s, ...); +extern const char* aprintf(const char* fmt, ...); extern void parse_em(void); +extern void symbol_init(void); +extern bool symbol_exists(const char* name); +extern struct symbol* symbol_get(const char* name); +extern void symbol_declare(const char* name, bool is_exported, bool is_proc); + +extern void data_label(const char* name); +extern void data_int(arith data, size_t size, bool is_ro); +extern void data_block(const uint8_t* data, size_t size, bool is_ro); +extern void data_offset(const char* label, arith offset, bool is_ro); +extern void data_bss(arith size, int init); + +extern void bb_init(void); +extern struct basicblock* bb_get(const char* name); +extern void bb_alias(struct basicblock* block, const char* name); +extern void bb_wire_outs_to_ins(struct basicblock* outblock, struct basicblock* inblock); + extern void tb_filestart(void); extern void tb_fileend(void); -extern void tb_symbol(const char* name, bool is_exported, bool is_proc); -extern void tb_dlabel(const char* label); extern void tb_ilabel(const char* label); -extern void tb_data(const uint8_t* data, size_t size, bool is_ro); -extern void tb_data_offset(const char* label, arith offset, bool is_ro); -extern void tb_bss(size_t size, uint8_t init); extern void tb_procstart(const char* label, size_t nlocals); extern void tb_procend(void); extern void tb_regvar(arith offset, int size, int type, int priority); diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 11aeb5c17..22ac92e81 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -1,6 +1,7 @@ #include "mcg.h" static struct e_instr insn; +static const char* current_proc; static const char* type_to_str(int type) { @@ -44,35 +45,15 @@ static void unknown_type(const char* s) argtype_to_str(insn.em_arg.ema_argtype)); } -static const uint8_t* arith_to_bytes(arith a, size_t sz) -{ - uint8_t* p = malloc(8); - - switch (sz) - { - case 1: *(uint8_t*)p = a; break; - case 2: *(uint16_t*)p = a; break; - case 4: *(uint32_t*)p = a; break; - case 8: *(uint64_t*)p = a; break; - default: - fatal("bad constant size '%d'", sz); - } - - return p; -} - static const char* ilabel_to_str(label l) { - char s[16]; - sprintf(s, "__I%d", l); - return strdup(s); + assert(current_proc != NULL); + return aprintf("__%s_I%d", current_proc, l); } static const char* dlabel_to_str(label l) { - char s[16]; - sprintf(s, ".%d", l); - return strdup(s); + return aprintf("__D%d", l); } static void parse_pseu(void) @@ -90,17 +71,17 @@ static void parse_pseu(void) switch (insn.em_arg.ema_argtype) { case pro_ptyp: - tb_symbol(strdup(insn.em_pnam), export, proc); + symbol_declare(strdup(insn.em_pnam), export, proc); break; case sof_ptyp: assert(insn.em_off == 0); - tb_symbol(strdup(insn.em_dnam), export, proc); + symbol_declare(strdup(insn.em_dnam), export, proc); break; case nof_ptyp: assert(insn.em_off == 0); - tb_symbol(dlabel_to_str(insn.em_dlb), export, proc); + symbol_declare(dlabel_to_str(insn.em_dlb), export, proc); break; default: @@ -120,24 +101,24 @@ static void parse_pseu(void) case uco_ptyp: { arith val = atol(insn.em_string); - tb_data(arith_to_bytes(val, insn.em_size), insn.em_size, ro); + data_int(val, insn.em_size, ro); break; } case str_ptyp: - tb_data(strdup(insn.em_string), insn.em_size, ro); + data_block(strdup(insn.em_string), insn.em_size, ro); break; case cst_ptyp: - tb_data(arith_to_bytes(insn.em_cst, EM_wordsize), EM_wordsize, ro); + data_int(insn.em_cst, EM_wordsize, ro); break; case nof_ptyp: - tb_data_offset(dlabel_to_str(insn.em_dlb), insn.em_off, ro); + data_offset(dlabel_to_str(insn.em_dlb), insn.em_off, ro); break; case ilb_ptyp: - tb_data_offset(ilabel_to_str(insn.em_ilb), 0, ro); + data_offset(ilabel_to_str(insn.em_ilb), 0, ro); break; default: @@ -151,7 +132,7 @@ static void parse_pseu(void) switch (insn.em_arg.ema_argtype) { case cst_ptyp: - tb_bss(EM_bsssize, EM_bssinit); + data_bss(EM_bsssize, insn.em_cst); break; default: @@ -164,11 +145,13 @@ static void parse_pseu(void) if (insn.em_nlocals == -1) fatal("procedures with unspecified number of locals are not supported yet"); - tb_procstart(strdup(insn.em_pnam), insn.em_nlocals); + current_proc = strdup(insn.em_pnam); + tb_procstart(current_proc, insn.em_nlocals); break; case ps_end: /* procedure end */ tb_procend(); + current_proc = NULL; break; default: @@ -228,16 +211,16 @@ void parse_em(void) break; case EM_DEFDLB: - tb_dlabel(dlabel_to_str(insn.em_dlb)); + data_label(dlabel_to_str(insn.em_dlb)); break; case EM_DEFDNAM: - tb_dlabel(strdup(insn.em_dnam)); + data_label(strdup(insn.em_dnam)); break; case EM_STARTMES: parse_mes(); - break; + break; case EM_MNEM: { @@ -268,8 +251,12 @@ void parse_em(void) break; case cst_ptyp: - tb_insn_value(insn.em_opcode, flags, - insn.em_cst); + if ((flags & EM_PAR) == PAR_B) + tb_insn_label(insn.em_opcode, flags, + ilabel_to_str(insn.em_ilb), 0); + else + tb_insn_value(insn.em_opcode, flags, + insn.em_cst); break; default: diff --git a/mach/proto/mcg/push_pop.awk b/mach/proto/mcg/push_pop.awk deleted file mode 100644 index 83560912e..000000000 --- a/mach/proto/mcg/push_pop.awk +++ /dev/null @@ -1,52 +0,0 @@ -BEGIN { - print "#include " - print "#include \"push_pop.h\"" - print "" - - s = 0; - count = 0; -} - -/^aar/ { - s = 1; -} - -/^[a-z]/ { - if (!s) - next; - - opcode[count++] = $1; - data[$1] = $3; -} - -END { - for (op in data) - { - print "static const struct stackop so_" op "[] = {"; - - pushpops = data[op] - if (pushpops != "0") - { - for (i=1; i<=length(pushpops); i+=2) - { - printf "\t{ "; - if (substr(pushpops, i, 1) == "+") - printf "true, "; - else - printf "false, "; - - printf("'%s' },\n", substr(pushpops, i+1, 1)); - } - } - print "\t{ false, 0 }" - - print "};"; - print ""; - } - - print "const struct stackop* const stackops[] = {"; - for (i=0; i +#include + +void symbol_init(void) +{ + init_idf(); +} + +bool symbol_exists(const char* name) +{ + return !!findidf((char*) name); +} + +struct symbol* symbol_get(const char* name) +{ + struct idf* p = str2idf((char*) name, 0); + p->symbol.name = p->id_text; + return &p->symbol; +} + +void symbol_declare(const char* name, bool is_exported, bool is_proc) +{ + struct symbol* s = symbol_get(name); + s->is_exported = is_exported; + + if (is_proc) + { + if (s->section == SECTION_UNKNOWN) + s->section = SECTION_TEXT; + else if (s->section != SECTION_TEXT) + fatal("section mismatch for '%s'", name); + } +} + diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index b8bff66b7..c7abd5cc8 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -1,93 +1,414 @@ #include "mcg.h" -void tb_filestart(void) +static struct symbol* currentproc; +static struct basicblock* rootbb; +static struct basicblock* currentbb; + +static int stackptr; +static struct ir* stack[64]; + +static void resetstack(void) { + stackptr = 0; } -void tb_fileend(void) +static void push(struct ir* ir) { + if (stackptr == sizeof(stack)/sizeof(*stack)) + fatal("stack overflow"); + + stack[stackptr++] = ir; } -void tb_symbol(const char* name, bool is_exported, bool is_proc) +static struct ir* pop(void) { - printf("; symbol name=%s, exported=%s, is_proc=%s\n", - name, - is_exported ? "yes" : "no", - is_proc ? "yes" : "no"); + if (stackptr == 0) + fatal("stack underflow"); + + return stack[--stackptr]; } -void tb_dlabel(const char* label) +static struct ir* appendir(struct ir* ir) { - printf("; dlabel name=%s\n", label); + assert(currentbb != NULL); + ir->sequence = true; + APPEND(currentbb->irs, ir); + + ir_print(ir); + return ir; } -void tb_ilabel(const char* label) +void tb_filestart(void) +{ +} + +void tb_fileend(void) { - printf("; ilabel name=%s\n", label); } -void tb_data(const uint8_t* data, size_t size, bool is_ro) +static void materialise(void) { - printf("; data size=%d ro=%s\n", - size, - is_ro ? "yes" : "no"); + int i; + + for (i=0; i 0) + { + printf("\t; block exiting with %d on stack:\n", stackptr); + for (i=0; iid, ir->size); + APPENDU(currentbb->outs, ir); + } + } + + for (i=0; ioutblocks_count; i++) + bb_wire_outs_to_ins(currentbb, currentbb->outblocks[i]); + + currentbb = bb; + printf("; new block: %s\n", currentbb->name); + + resetstack(); + + if (currentbb->ins_count > 0) + { + printf("\t; block entering with %d on stack:\n", currentbb->ins_count); + for (i=0; iins_count; i++) + { + struct ir* ir = currentbb->ins[i]; + printf("\t; $%d size %d\n", ir->id, ir->size); + push(ir); + } + } } -void tb_bss(size_t size, uint8_t init) +void tb_ilabel(const char* label) { - printf("; bss size=%d init=0x%x\n", - size, init); + materialise(); + + #if 0 + if (currentbb->irs_count == 0) + { + /* Current BB has no instructions, so just alias it to the + * new name. + */ + bb_alias(currentbb, label); + } + else + #endif + { + struct basicblock* newbb = bb_get(label); + + if ((currentbb->irs_count == 0) || + !currentbb->irs[currentbb->irs_count-1]->terminates) + { + APPEND(currentbb->outblocks, newbb); + appendir( + new_ir1( + IR_JUMP, 0, + new_labelir(label) + ) + ); + } + + changeblock(newbb); + } } void tb_procstart(const char* label, size_t nlocals) { - printf("; proc name=%s nlocals=%d\n", label, nlocals); + assert(currentproc == NULL); + + currentproc = symbol_get(label); + currentproc->section = SECTION_TEXT; + + rootbb = calloc(sizeof(struct basicblock), 1); + currentbb = rootbb; + + resetstack(); } void tb_procend(void) { - printf("; endproc\n"); + assert(currentproc != NULL); + + printf("\n.text\n"); + printf("%s:\n", currentproc->name); + + currentproc = NULL; } void tb_regvar(arith offset, int size, int type, int priority) { - printf("; regvar offset=%d size=%d type=%d priority=%d\n", - offset, size, type, priority); + /* ignored */ } -static void printinsn(int opcode, int flags) +static struct ir* address_of_local(int index) { - printf("; insn %s %c%c%c%c ", - em_mnem[opcode - sp_fmnem], - "/CDNFLGWSZOPBR"[flags & EM_PAR], - (flags & FLO_C) ? 'c' : '.', - (flags & FLO_P) ? 'p' : '.', - (flags & FLO_T) ? 't' : '.'); + return + new_ir2( + IR_ADD, EM_pointersize, + new_regir((index < 0) ? IRR_LB : IRR_AB), + new_wordir(index) + ); +} + +static struct ir* tristate_compare(int size, int opcode) +{ + struct ir* right = pop(); + struct ir* left = pop(); + + return + new_ir2( + opcode, size, + left, right + ); +} + +static struct ir* convert(int destsize, int srcsize, int opcode) +{ + switch (srcsize) + { + case 1: opcode += 0; break; + case 2: opcode += 1; break; + case 4: opcode += 2; break; + case 8: opcode += 3; break; + default: + fatal("can't convert from things of size %d", srcsize); + } + + return + new_ir1( + opcode, destsize, + pop() + ); } void tb_insn_simple(int opcode, int flags) { - printinsn(opcode, flags); - printf("\n"); + switch (opcode) + { + case op_cii: + { + struct ir* destsize = pop(); + struct ir* srcsize = pop(); + + assert(srcsize->opcode == IR_ICONST); + assert(destsize->opcode == IR_ICONST); + + push( + convert(destsize->u.ivalue, srcsize->u.ivalue, IR_FROMI1) + ); + break; + } + + default: + fatal("unknown insn_simple instruction '%s'", + em_mnem[opcode - sp_fmnem]); + } } void tb_insn_label(int opcode, int flags, const char* label, arith offset) { - printinsn(opcode, flags); - printf("label=%s offset=%d\n", label, offset); + materialise(); + + switch (opcode) + { + case op_zne: + { + struct basicblock* truebb = bb_get(label); + struct basicblock* falsebb = bb_get(NULL); + + APPENDU(currentbb->outblocks, truebb); + APPENDU(currentbb->outblocks, falsebb); + + appendir( + new_ir3( + IR_CJUMP, 0, + pop(), + new_bbir(truebb), + new_bbir(falsebb) + ) + ); + + changeblock(falsebb); + break; + } + + case op_bra: + { + struct basicblock* destbb = bb_get(label); + APPENDU(currentbb->outblocks, destbb); + + appendir( + new_ir1( + IR_JUMP, 0, + new_bbir(destbb) + ) + ); + break; + } + + default: + fatal("unknown insn_label instruction '%s'", + em_mnem[opcode - sp_fmnem]); + } } void tb_insn_value(int opcode, int flags, arith value) { - printinsn(opcode, flags); - printf("value=%d\n", value); + struct ir* left; + struct ir* right; + + switch (opcode) + { + case op_lol: + push( + new_ir1( + IR_LOAD, EM_wordsize, + address_of_local(value) + ) + ); + break; + + case op_stl: + appendir( + new_ir2( + IR_STORE, EM_wordsize, + address_of_local(value), + pop() + ) + ); + break; + + case op_loc: + push( + new_wordir(value) + ); + break; + + case op_loi: + push( + new_ir1( + IR_LOAD, value, + pop() + ) + ); + break; + + case op_sti: + right = pop(); + left = pop(); + + appendir( + new_ir2( + IR_STORE, value, + right, left + ) + ); + break; + + case op_cmi: + push( + tristate_compare(value, IR_COMPARES) + ); + break; + + case op_cmu: + push( + tristate_compare(value, IR_COMPAREU) + ); + break; + + case op_ads: + right = pop(); + left = pop(); + + if (value != EM_pointersize) + right = convert(EM_pointersize, value, IR_FROMI1); + + push( + new_ir2( + IR_ADD, EM_wordsize, + left, right + ) + ); + break; + + case op_dup: + { + struct ir* v = pop(); + appendir(v); + push(v); + push(v); + break; + } + + case op_asp: + { + switch (value) + { + case 0: + break; + + case -1: + case -2: + case -4: + case -8: + push(new_anyir(-value)); + break; + + default: + appendir( + new_ir2( + IR_SETREG, EM_pointersize, + new_regir(IRR_SP), + new_ir2( + IR_ADD, EM_pointersize, + new_regir(IRR_SP), + new_wordir(value) + ) + ) + ); + break; + } + break; + } + + case op_ret: + { + if (value > 0) + { + left = pop(); + assert(left->size == value); + appendir( + new_ir2( + IR_SETREG, value, + new_regir(IRR_RR), + left + ) + ); + } + + appendir( + new_ir0( + IR_RET, 0 + ) + ); + break; + } + + default: + fatal("unknown insn_value instruction '%s'", + em_mnem[opcode - sp_fmnem]); + } } /* vim: set sw=4 ts=4 expandtab : */