Create hacky fake basic blocks for data fragments, used to track which
authorDavid Given <dg@cowlark.com>
Mon, 19 Sep 2016 22:19:39 +0000 (00:19 +0200)
committerDavid Given <dg@cowlark.com>
Mon, 19 Sep 2016 22:19:39 +0000 (00:19 +0200)
instruction labels descriptor blocks refer to; this allows csa and csb to know
where they're going.

mach/proto/mcg/basicblock.c
mach/proto/mcg/mcg.h
mach/proto/mcg/parse_em.c
mach/proto/mcg/treebuilder.c

index 74d5e8a..0ac2a55 100644 (file)
@@ -39,32 +39,4 @@ void bb_alias(struct basicblock* block, const char* name)
        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 ce332ff..997ae53 100644 (file)
@@ -82,7 +82,7 @@ struct basicblock
     ARRAY(struct basicblock, outblocks);
     ARRAY(struct ir, outs);
     ARRAY(struct ir, ins);
-    bool is_wired : 1;
+    bool is_root : 1;
     bool is_terminated : 1;
 };
 
@@ -105,7 +105,6 @@ 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);
index 13320fe..a1c9889 100644 (file)
@@ -2,7 +2,8 @@
 
 static struct e_instr insn;
 static struct procedure* current_proc;
-static struct basicblock* current_bb;
+static struct basicblock* code_bb;
+static struct basicblock* data_bb;
 
 static void queue_insn_label(int opcode, const char* label, arith offset);
 
@@ -61,8 +62,8 @@ static const char* dlabel_to_str(label l)
 
 static void terminate_block(void)
 {
-    current_bb->is_terminated = true;
-    current_bb = NULL;
+    code_bb->is_terminated = true;
+    code_bb = NULL;
 }
 
 static struct insn* new_insn(int opcode)
@@ -76,7 +77,7 @@ static void queue_insn_simple(int opcode)
 {
     struct insn* insn = new_insn(opcode);
     insn->paramtype = PARAM_NONE;
-    APPEND(current_bb->insns, insn);
+    APPEND(code_bb->insns, insn);
 
     switch (opcode)
     {
@@ -88,29 +89,17 @@ static void queue_insn_simple(int opcode)
 
 static void queue_insn_value(int opcode, arith value)
 {
+    struct insn* insn = new_insn(opcode);
+    insn->paramtype = PARAM_IVALUE;
+    insn->u.ivalue = value;
+    APPEND(code_bb->insns, insn);
+
     switch (opcode)
     {
         case op_csa:
         case op_csb:
-        {
-            const char* helper = aprintf(".%s%d",
-                (opcode == op_csa) ? "csa" : "csb",
-                value);
-
-            queue_insn_label(op_cal, helper, 0);
-            queue_insn_value(op_asp, value + EM_pointersize);
-            queue_insn_value(op_lfr, value);
-            queue_insn_simple(op_bra);
+            terminate_block();
             break;
-        }
-
-        default:
-        {
-            struct insn* insn = new_insn(opcode);
-            insn->paramtype = PARAM_IVALUE;
-            insn->u.ivalue = value;
-            APPEND(current_bb->insns, insn);
-        }
     }
 }
 
@@ -120,7 +109,14 @@ static void queue_insn_label(int opcode, const char* label, arith offset)
     insn->paramtype = PARAM_LVALUE;
     insn->u.lvalue.label = label;
     insn->u.lvalue.offset = offset;
-    APPEND(current_bb->insns, insn);
+    APPEND(code_bb->insns, insn);
+
+    switch (opcode)
+    {
+        case op_bra:
+            terminate_block();
+            break;
+    }
 }
 
 static void queue_insn_block(int opcode, struct basicblock* left, struct basicblock* right)
@@ -129,12 +125,15 @@ static void queue_insn_block(int opcode, struct basicblock* left, struct basicbl
     insn->paramtype = PARAM_BVALUE;
     insn->u.bvalue.left = left;
     insn->u.bvalue.right = right;
-    APPEND(current_bb->insns, insn);
+    APPEND(code_bb->insns, insn);
     
-    APPENDU(current_bb->outblocks, left);
+    APPENDU(code_bb->outblocks, left);
+    APPENDU(left->inblocks, code_bb);
     if (right)
-        APPENDU(current_bb->outblocks, right);
-    APPENDU(current_bb->inblocks, current_bb);
+    {
+        APPENDU(code_bb->outblocks, right);
+        APPENDU(right->inblocks, code_bb);
+    }
 
     terminate_block();
 }
@@ -169,10 +168,10 @@ static void change_basicblock(struct basicblock* newbb)
 {
     APPENDU(current_proc->blocks, newbb);
 
-    if (current_bb && !current_bb->is_terminated)
+    if (code_bb && !code_bb->is_terminated)
         queue_insn_block(op_bra, newbb, NULL);
 
-    current_bb = newbb;
+    code_bb = newbb;
 }
 
 static void queue_ilabel(arith label)
@@ -242,8 +241,21 @@ static void parse_pseu(void)
                     break;
 
                 case ilb_ptyp:
-                    data_offset(ilabel_to_str(insn.em_ilb), 0, ro);
+                {
+                    const char* label = ilabel_to_str(insn.em_ilb);
+
+                    /* This is really hacky; to handle basic block flow
+                     * descriptor blocks, we need to track which bbs a descriptor
+                     * can exit to. So we create fake bb objects for each
+                     * block, purely to track this.
+                     */
+
+                    if (data_bb)
+                        APPENDU(data_bb->outblocks, bb_get(label));
+
+                    data_offset(label, 0, ro);
                     break;
+                }
 
                                default:
                     unknown_type("con, rom");
@@ -270,15 +282,16 @@ static void parse_pseu(void)
             current_proc->name = strdup(insn.em_pnam);
             current_proc->root_bb = bb_get(current_proc->name);
             current_proc->nlocals = insn.em_nlocals;
-            current_bb = current_proc->root_bb;
-            APPEND(current_proc->blocks, current_bb);
+            code_bb = current_proc->root_bb;
+            code_bb->is_root = true;
+            APPEND(current_proc->blocks, code_bb);
             break;
 
                case ps_end: /* procedure end */
             tb_procedure(current_proc);
 
             current_proc = NULL;
-            current_bb = NULL;
+            code_bb = NULL;
                        break;
 
                default:
@@ -338,8 +351,12 @@ void parse_em(void)
                 break;
 
             case EM_DEFDLB:
-                data_label(dlabel_to_str(insn.em_dlb));
+            {
+                const char* label = dlabel_to_str(insn.em_dlb);
+                data_label(label);
+                data_bb = bb_get(label);
                 break;
+            }
 
             case EM_DEFDNAM:
                 data_label(strdup(insn.em_dnam));
@@ -350,7 +367,7 @@ void parse_em(void)
                 break;
 
             case EM_MNEM:
-                if (current_bb)
+                if (code_bb)
                 {
                     int flags = em_flag[insn.em_opcode - sp_fmnem];
 
index bf57026..5b014ec 100644 (file)
@@ -85,7 +85,7 @@ static void materialise_stack(void)
 {
     int i;
 
-    for (i=stackptr-1; i>=0; i--)
+    for (i=0; i<stackptr; i++)
     {
         struct ir* ir = stack[i];
         appendir(
@@ -122,6 +122,20 @@ static struct ir* address_of_local(int index)
         );
 }
 
+static struct ir* address_of_external(const char* label, arith offset)
+{
+    if (offset != 0)
+        return
+            new_ir2(
+                IR_ADD, EM_pointersize,
+                new_labelir(label),
+                new_wordir(offset)
+            );
+    else
+        return
+            new_labelir(label);
+}
+
 static struct ir* convert(struct ir* src, int destsize, int opcode)
 {
     switch (src->size)
@@ -153,7 +167,7 @@ static struct ir* tristate_compare(int size, int opcode)
         );
 }
 
-static void simple_convert(opcode)
+static void simple_convert(int opcode)
 {
     struct ir* destsize = pop(EM_wordsize);
     struct ir* srcsize = pop(EM_wordsize);
@@ -513,6 +527,42 @@ static void insn_ivalue(int opcode, arith value)
             break;
         }
 
+        case op_csa:
+        case op_csb:
+        {
+            struct basicblock* data_bb;
+            int i;
+            const char* helper = aprintf(".%s%d",
+                (opcode == op_csa) ? "csa" : "csb",
+                value);
+            struct ir* descriptor = pop(EM_pointersize);
+
+            if (descriptor->opcode != IR_LABEL)
+                fatal("csa/csb are only supported if they refer "
+                    "directly to a descriptor block");
+
+            /* Splice the outgoing bbs in the data block into our own. */
+
+            data_bb = bb_get(descriptor->u.lvalue);
+            for (i=0; i<data_bb->outblocks_count; i++)
+            {
+                struct basicblock* bb = data_bb->outblocks[i];
+                printf("\t;   may jump to %s\n", bb->name);
+                APPENDU(current_bb->outblocks, bb);
+                APPENDU(bb->inblocks, current_bb);
+            }
+
+            push(descriptor);
+            materialise_stack();
+            appendir(
+                new_ir1(
+                    IR_JUMP, 0,
+                    new_labelir(helper)
+                )
+            );
+            break;
+        }
+
         default:
             fatal("treebuilder: unknown ivalue instruction '%s'",
                 em_mnem[opcode - sp_fmnem]);
@@ -525,11 +575,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
     {
         case op_lae:
             push(
-                new_ir2(
-                    IR_ADD, EM_pointersize,
-                    new_labelir(label),
-                    new_wordir(offset)
-                )
+                address_of_external(label, offset)
             );
             break;
 
@@ -537,11 +583,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
             push(
                 new_ir1(
                     IR_LOAD, EM_wordsize,
-                    new_ir2(
-                        IR_ADD, EM_pointersize,
-                        new_labelir(label),
-                        new_wordir(offset)
-                    )
+                    address_of_external(label, offset)
                 )
             );
             break;
@@ -550,11 +592,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
             appendir(
                 new_ir2(
                     IR_STORE, EM_wordsize,
-                    new_ir2(
-                        IR_ADD, EM_pointersize,
-                        new_labelir(label),
-                        new_wordir(offset)
-                    ),
+                    address_of_external(label, offset),
                     pop(EM_wordsize)
                 )
             );
@@ -570,6 +608,17 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
                 )
             );
             break;
+
+        case op_bra:
+            assert(offset == 0);
+            materialise_stack();
+            appendir(
+                new_ir1(
+                    IR_JUMP, 0,
+                    new_labelir(label)
+                )
+            );
+            break;
                     
         default:
             fatal("treebuilder: unknown lvalue instruction '%s'",
@@ -582,6 +631,13 @@ static void generate_tree(struct basicblock* bb)
     int i;
 
     printf("; BLOCK %s\n", bb->name);
+    if (bb->inblocks_count > 0)
+    {
+        printf("; Entered from:\n");
+        for (i=0; i<bb->inblocks_count; i++)
+            printf(";    %s\n", bb->inblocks[i]->name);
+    }
+
     current_bb = bb;
     reset_stack();
 
@@ -623,6 +679,14 @@ static void generate_tree(struct basicblock* bb)
     }
 
     assert(stackptr == 0);
+
+    if (bb->outblocks_count > 0)
+    {
+        printf("; Exiting to:\n");
+        for (i=0; i<bb->outblocks_count; i++)
+            printf(";    %s\n", bb->outblocks[i]->name);
+    }
+    printf("\n");
 }
 
 void tb_procedure(struct procedure* current_proc)