--- /dev/null
+#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<count; i++)
+ if (array[i] == value)
+ return true;
+
+ return false;
+}
+
+void array_appendu(void*** array, int* count, int* max, void* value)
+{
+ if (!array_contains(*array, *count, value))
+ array_append(array, count, max, value);
+}
+
+/* vim: set sw=4 ts=4 expandtab : */
+
--- /dev/null
+#ifndef ARRAY_H
+#define ARRAY_H
+
+#define ARRAY(TYPE, NAME) \
+ TYPE** NAME; \
+ int NAME##_count; \
+ int NAME##_max
+
+#define APPEND(ARRAY, VALUE) \
+ array_append((void***) &ARRAY, &ARRAY##_count, &ARRAY##_max, VALUE)
+
+#define CONTAINS(ARRAY, VALUE) \
+ array_contains((void**) ARRAY, ARRAY##_count, VALUE)
+
+#define APPENDU(ARRAY, VALUE) \
+ array_appendu((void***) &ARRAY, &ARRAY##_count, &ARRAY##_max, VALUE)
+
+extern void array_append(void*** array, int* count, int* max, void* value);
+extern bool array_contains(void** array, int count, void* value);
+extern void array_appendu(void*** array, int* count, int* max, void* value);
+
+#endif
+
--- /dev/null
+#include "mcg.h"
+
+static void init_idf();
+static struct idf* str2idf(char* tg, int cp);
+
+#define IDF_TYPE struct basicblock*
+#define IDF_NAME block
+#include <idf_pkg.spec>
+#include <idf_pkg.body>
+
+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; i<inblock->outs_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; i<inblock->outs_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 : */
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]}"
}
}
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"}
}
}
--- /dev/null
+#include "mcg.h"
+#include <ctype.h>
+
+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 : */
--- /dev/null
+#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; i<sizeof(ir->children)/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; i<sizeof(ir->children)/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 : */
--- /dev/null
+# 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
+
--- /dev/null
+#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
+
--- /dev/null
+#!/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
+
#include "mcg.h"
-#include "em_comp.h"
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);
#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);
#include "mcg.h"
static struct e_instr insn;
+static const char* current_proc;
static const char* type_to_str(int type)
{
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)
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:
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:
switch (insn.em_arg.ema_argtype)
{
case cst_ptyp:
- tb_bss(EM_bsssize, EM_bssinit);
+ data_bss(EM_bsssize, insn.em_cst);
break;
default:
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:
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:
{
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:
+++ /dev/null
-BEGIN {
- print "#include <stdbool.h>"
- 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<count; i++)
- print "\tso_" opcode[i] ","
- print "};"
-}
-
+++ /dev/null
-#ifndef PUSH_POP_H
-#define PUSH_POP_H
-
-struct stackop {
- bool push : 1;
- char type : 7;
-};
-
-extern const struct stackop* const stackops[];
-
-#endif
-
--- /dev/null
+#include "mcg.h"
+
+static void init_idf();
+static struct idf* str2idf(char* tg, int cp);
+
+#define IDF_TYPE struct symbol
+#define IDF_NAME symbol
+#include <idf_pkg.spec>
+#include <idf_pkg.body>
+
+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);
+ }
+}
+
#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<stackptr; i++)
+ appendir(stack[i]);
}
-void tb_data_offset(const char* label, arith offset, bool is_ro)
+static void changeblock(struct basicblock* bb)
{
- printf("; data label=%s offset=%d ro=%s\n",
- label, offset,
- is_ro ? "yes" : "no");
+ int i;
+
+ if (stackptr > 0)
+ {
+ printf("\t; block exiting with %d on stack:\n", stackptr);
+ for (i=0; i<stackptr; i++)
+ {
+ struct ir* ir = stack[i];
+ printf("\t; $%d size %d\n", ir->id, ir->size);
+ APPENDU(currentbb->outs, ir);
+ }
+ }
+
+ for (i=0; i<currentbb->outblocks_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; i<currentbb->ins_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 : */