Archival checking of the half-written IR treebuilder.
authorDavid Given <dg@cowlark.com>
Sun, 18 Sep 2016 21:24:54 +0000 (23:24 +0200)
committerDavid Given <dg@cowlark.com>
Sun, 18 Sep 2016 21:24:54 +0000 (23:24 +0200)
16 files changed:
mach/proto/mcg/array.c [new file with mode: 0644]
mach/proto/mcg/array.h [new file with mode: 0644]
mach/proto/mcg/basicblock.c [new file with mode: 0644]
mach/proto/mcg/build.lua
mach/proto/mcg/data.c [new file with mode: 0644]
mach/proto/mcg/ir.c [new file with mode: 0644]
mach/proto/mcg/ir.dat [new file with mode: 0644]
mach/proto/mcg/ir.h [new file with mode: 0644]
mach/proto/mcg/ircodes.sh [new file with mode: 0755]
mach/proto/mcg/main.c
mach/proto/mcg/mcg.h
mach/proto/mcg/parse_em.c
mach/proto/mcg/push_pop.awk [deleted file]
mach/proto/mcg/push_pop.h [deleted file]
mach/proto/mcg/symbol.c [new file with mode: 0644]
mach/proto/mcg/treebuilder.c

diff --git a/mach/proto/mcg/array.c b/mach/proto/mcg/array.c
new file mode 100644 (file)
index 0000000..1b72352
--- /dev/null
@@ -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<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 : */
+
diff --git a/mach/proto/mcg/array.h b/mach/proto/mcg/array.h
new file mode 100644 (file)
index 0000000..4d9badb
--- /dev/null
@@ -0,0 +1,23 @@
+#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
+
diff --git a/mach/proto/mcg/basicblock.c b/mach/proto/mcg/basicblock.c
new file mode 100644 (file)
index 0000000..74d5e8a
--- /dev/null
@@ -0,0 +1,70 @@
+#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 : */
index ef53f28..5db304b 100644 (file)
@@ -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 (file)
index 0000000..acc14c0
--- /dev/null
@@ -0,0 +1,113 @@
+#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 : */
diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c
new file mode 100644 (file)
index 0000000..8973bfc
--- /dev/null
@@ -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; 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 : */
diff --git a/mach/proto/mcg/ir.dat b/mach/proto/mcg/ir.dat
new file mode 100644 (file)
index 0000000..044f9c0
--- /dev/null
@@ -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 (file)
index 0000000..33b8925
--- /dev/null
@@ -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 (executable)
index 0000000..8f88b8b
--- /dev/null
@@ -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
+
index 035259d..a89b5a7 100644 (file)
@@ -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);
        
index e008249..06e8160 100644 (file)
 #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);
index 11aeb5c..22ac92e 100644 (file)
@@ -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 (file)
index 8356091..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-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 "};"
-}
-
diff --git a/mach/proto/mcg/push_pop.h b/mach/proto/mcg/push_pop.h
deleted file mode 100644 (file)
index 9f9b085..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef PUSH_POP_H
-#define PUSH_POP_H
-
-struct stackop {
-       bool push : 1;
-       char type : 7;
-};
-
-extern const struct stackop* const stackops[];
-
-#endif
-
diff --git a/mach/proto/mcg/symbol.c b/mach/proto/mcg/symbol.c
new file mode 100644 (file)
index 0000000..14ec4a9
--- /dev/null
@@ -0,0 +1,41 @@
+#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);
+       }
+}
+
index b8bff66..c7abd5c 100644 (file)
 #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 : */