int NAME##_count; \
int NAME##_max
+#define STATICARRAY(TYPE, NAME) \
+ static TYPE** NAME; \
+ static int NAME##_count; \
+ static int NAME##_max
+
#define APPEND(ARRAY, VALUE) \
array_append((void***) &ARRAY, &ARRAY##_count, &ARRAY##_max, VALUE)
tracef(k, "%c:\n", k);
tracef(k, "%c: BLOCK: %s\n", k, bb->name);
- tracef(k, "%c: from:", k);
- for (int j=0; j<bb->inblocks_count; j++)
- {
- struct basicblock* obb = bb->inblocks[j];
- tracef(k, " %s", obb->name);
- }
- tracef(k, "\n");
- tracef(k, "%c: to:", k);
- for (int j=0; j<bb->outblocks_count; j++)
- {
- struct basicblock* obb = bb->outblocks[j];
- tracef(k, " %s", obb->name);
- }
- tracef(k, "\n");
-
for (int j=0; j<bb->irs_count; j++)
ir_print(k, bb->irs[j]);
-
}
}
print_blocks('1', proc);
+ pass_eliminate_trivial_blocks(proc);
pass_remove_dead_blocks(proc);
pass_convert_stack_ops(proc);
- pass_splice_adjacent_blocks(proc);
print_blocks('2', proc);
}
return ir;
}
-struct ir* ir_find(struct ir* ir, int opcode)
+struct ir* ir_walk(struct ir* ir, ir_walker_t* cb, void* user)
{
- if (ir->opcode == opcode)
+ if (cb(ir, user))
return ir;
if (ir->left && !ir->left->is_sequence)
{
- struct ir* irr = ir_find(ir->left, opcode);
+ struct ir* irr = ir_walk(ir->left, cb, user);
if (irr)
return irr;
}
if (ir->right && !ir->right->is_sequence)
{
- struct ir* irr = ir_find(ir->right, opcode);
+ struct ir* irr = ir_walk(ir->right, cb, user);
if (irr)
return irr;
}
return NULL;
}
+static bool finder_cb(struct ir* ir, void* user)
+{
+ int opcode = *(int*)user;
+ if (ir->opcode == opcode)
+ return true;
+ return false;
+}
+
+struct ir* ir_find(struct ir* ir, int opcode)
+{
+ return ir_walk(ir, finder_cb, &opcode);
+}
+
static void print_expr(char k, const struct ir* ir)
{
tracef(k, "%s", ir_names[ir->opcode]);
tracef(k, "%s", ir->u.bvalue->name);
break;
- case IR_PHI:
- {
- int i;
-
- for (i=0; i<ir->u.phivalue.imports_count; i++)
- {
- if (i > 0)
- tracef(k, ", ");
- tracef(k, "$%d", ir->u.phivalue.imports[i]->id);
- }
- }
-
default:
if (ir->left)
{
#ifndef IR_H
#define IR_H
+#include "ircodes.h"
+
enum
{
IRR_LB = -1,
struct ir
{
int id;
- int opcode;
+ enum ir_opcode opcode;
int size;
struct ir* left;
struct ir* right;
int rvalue;
const char* lvalue;
struct basicblock* bvalue;
- struct
- {
- ARRAY(struct ir, imports);
- } phivalue;
} u;
bool is_sequence : 1;
};
extern struct ir* new_anyir(int size);
extern struct ir* new_localir(int offset);
+typedef bool ir_walker_t(struct ir* node, void* user);
+extern struct ir* ir_walk(struct ir* ir, ir_walker_t* callback, void* user);
extern struct ir* ir_find(struct ir* ir, int opcode);
extern void ir_print(char k, const struct ir* ir);
-#include "ircodes.h"
-
#endif
awk -f - $in >$header << "EOF"
BEGIN {
- print "enum {"
+ print "enum ir_opcode {"
}
/^[^#]+/ {
{
case 'E': return false;
case '0': return false;
- case '1': return true;
+ case '1': return false;
case '2': return true;
default: return true;
}
--- /dev/null
+#include "mcg.h"
+
+static void extend(struct map_node** map, int* count, int* max)
+{
+ if (*count == *max)
+ {
+ int newmax = (*max == 0) ? 8 : (*max * 2);
+ struct map_node* newmap = realloc(*map, newmax * sizeof(struct map_node));
+ if (!newmap)
+ fatal("memory allocation failure");
+
+ *max = newmax;
+ *map = newmap;
+ }
+}
+
+void map_set(struct map_node** map, int* count, int* max, void* left, void* right)
+{
+ int i;
+ struct map_node* node;
+
+ for (i=0; i<*count; i++)
+ {
+ node = &(*map)[i];
+ if (node->left == left)
+ {
+ node->right = right;
+ return;
+ }
+ }
+
+ extend(map, count, max);
+ node = &(*map)[*count];
+ node->left = left;
+ node->right = right;
+ (*count)++;
+}
+
+void map_add(struct map_node** map, int* count, int* max, void* left, void* right)
+{
+ int i;
+ struct map_node* node;
+
+ for (i=0; i<*count; i++)
+ {
+ node = &(*map)[i];
+ if ((node->left == left) && (node->right == right))
+ return;
+ }
+
+ extend(map, count, max);
+ node = &(*map)[*count];
+ node->left = left;
+ node->right = right;
+ (*count)++;
+}
+
+/* vim: set sw=4 ts=4 expandtab : */
--- /dev/null
+#ifndef MAP_H
+#define MAP_H
+
+struct map_node
+{
+ void* left;
+ void* right;
+};
+
+#define _MAP(MODIFIER, NAME) \
+ MODIFIER struct map_node* NAME; \
+ MODIFIER int NAME##_count; \
+ MODIFIER int NAME##_max
+
+#define MAP(NAME) _MAP(, NAME)
+#define STATICMAP(NAME) _MAP(static, NAME)
+
+#define MAP_SET(MAP, LEFT, RIGHT) \
+ map_set(&MAP, &MAP##_count, &MAP##_max, LEFT, RIGHT)
+
+extern void map_set(struct map_node** map, int* count, int* max, void* left, void* right);
+extern void map_add(struct map_node** map, int* count, int* max, void* left, void* right);
+
+#endif
+
+
#include "em_flag.h"
#include "em_ptyp.h"
#include "array.h"
+#include "map.h"
#include "ir.h"
extern char em_pseu[][4];
const char* name;
ARRAY(struct insn, insns);
ARRAY(struct ir, irs);
- ARRAY(struct basicblock, inblocks);
- ARRAY(struct basicblock, outblocks);
- ARRAY(struct ir, inparams);
- ARRAY(struct ir, outparams);
+ bool is_fake : 1;
bool is_root : 1;
bool is_terminated : 1;
};
extern void pass_convert_stack_ops(struct procedure* proc);
extern void pass_remove_dead_blocks(struct procedure* proc);
-extern void pass_splice_adjacent_blocks(struct procedure* proc);
+extern void pass_eliminate_trivial_blocks(struct procedure* proc);
extern void compile(struct procedure* proc);
insn->u.bvalue.right = right;
APPEND(code_bb->insns, insn);
- APPENDU(code_bb->outblocks, left);
- APPENDU(left->inblocks, code_bb);
- if (right)
- {
- APPENDU(code_bb->outblocks, right);
- APPENDU(right->inblocks, code_bb);
- }
-
terminate_block();
}
*/
if (data_bb)
- APPENDU(data_bb->outblocks, bb_get(label));
+ {
+ struct insn* insn = new_insn(op_bra);
+ insn->paramtype = PARAM_BVALUE;
+ insn->u.bvalue.left = bb_get(label);
+ APPEND(data_bb->insns, insn);
+ }
data_offset(label, 0, ro);
break;
const char* label = dlabel_to_str(insn.em_dlb);
data_label(label);
data_bb = bb_get(label);
+ data_bb->is_fake = true;
break;
}
#include "mcg.h"
+STATICMAP(graph);
+STATICARRAY(struct ir, pops);
+STATICARRAY(struct ir, pushes);
+
static struct ir* get_last_push(struct basicblock* bb)
{
int i;
return NULL;
}
-static void convert_block(struct basicblock* bb)
+static bool collect_outputs_cb(struct ir* ir, void* user)
+{
+ struct basicblock* caller = user;
+
+ if (ir->opcode == IR_BLOCK)
+ MAP_SET(graph, caller, ir->u.bvalue);
+ return false;
+}
+
+static void make_bb_graph(struct procedure* proc)
+{
+ int i, j;
+
+ graph_count = 0;
+ for (i=0; i<proc->blocks_count; i++)
+ {
+ struct basicblock* bb = proc->blocks[i];
+ for (j=0; j<bb->irs_count; j++)
+ ir_walk(bb->irs[j], collect_outputs_cb, bb);
+ }
+}
+
+static void convert_block(struct procedure* proc, struct basicblock* bb)
{
int i, j;
struct ir* ir;
+ pushes_count = pops_count = 0;
for (;;)
{
struct ir* lastpush = get_last_push(bb);
if (!lastpush)
return;
- /* Abort unless *every* success block of this one starts with a pop
+ /* Abort unless *every* successor block of this one starts with a pop
* of the same size... */
- for (i=0; i<bb->outblocks_count; i++)
+ for (i=0; i<graph_count; i++)
{
- struct basicblock* outbb = bb->outblocks[i];
-
- ir = get_first_pop(outbb);
- if (!ir || (ir->size != lastpush->size))
- return;
-
- /* Also abort unless *every* predecessor block of the one we've
- * just found *also* ends in a push of the same size. */
-
- for (j=0; j<outbb->inblocks_count; j++)
+ if (graph[i].left == bb)
{
- struct basicblock* inbb = outbb->inblocks[i];
+ struct basicblock* outbb = graph[i].right;
- ir = get_last_push(inbb);
+ ir = get_first_pop(outbb);
if (!ir || (ir->size != lastpush->size))
return;
+ APPENDU(pops, ir);
+
+ /* Also abort unless *every* predecessor block of the one we've
+ * just found *also* ends in a push of the same size. */
+
+ for (j=0; j<graph_count; j++)
+ {
+ if (graph[j].right == outbb)
+ {
+ struct basicblock* inbb = graph[j].left;
+
+ ir = get_last_push(inbb);
+ if (!ir || (ir->size != lastpush->size))
+ return;
+ APPENDU(pushes, ir);
+ }
+ }
}
}
/* Okay, now we can wire them all up. */
- for (i=0; i<bb->outblocks_count; i++)
+ for (i=0; i<pushes_count; i++)
{
- struct basicblock* outbb = bb->outblocks[i];
- struct ir* phi = get_first_pop(outbb);
- phi->opcode = IR_PHI;
+ struct ir* ir = pushes[i];
+ assert(ir->is_sequence);
+ *ir = *ir->left;
+ ir->is_sequence = true;
+ }
- /* Also abort unless *every* predecessor block of the one we've
- * just found *also* ends in a push of the same size. */
+ for (i=0; i<pops_count; i++)
+ {
+ struct ir* ir = pops[i];
+ struct ir* pushir = pushes[0];
+ struct ir* phi = new_ir1(IR_PHI, ir->size, pushir);
- for (j=0; j<outbb->inblocks_count; j++)
- {
- struct basicblock* inbb = outbb->inblocks[j];
+ for (j=1; j<pushes_count; j++)
+ phi = new_ir2(IR_PHI, ir->size, phi, pushes[j]);
- ir = get_last_push(inbb);
- *ir = *ir->left;
- ir->is_sequence = true;
- APPEND(phi->u.phivalue.imports, ir);
- }
+ phi->is_sequence = ir->is_sequence;
+ *ir = *phi;
}
}
}
{
int i;
+ make_bb_graph(proc);
+
for (i=0; i<proc->blocks_count; i++)
- convert_block(proc->blocks[i]);
+ convert_block(proc, proc->blocks[i]);
}
/* vim: set sw=4 ts=4 expandtab : */
+++ /dev/null
-#include "mcg.h"
-
-void pass_remove_dead_blocks(struct procedure* proc)
-{
- int i, j;
-
-again:
- /* Starts at 1 because we don't want to remove the root block! */
- for (i=1; i<proc->blocks_count; i++)
- {
- struct basicblock* bb = proc->blocks[i];
-
- if (bb->inblocks_count == 0)
- {
- /* Nobody uses this block; disconnect it from its output
- * blocks. */
- for (j=0; j<bb->outblocks_count; j++)
- REMOVE(bb->outblocks[j]->inblocks, bb);
-
- REMOVE(proc->blocks, bb);
- goto again;
- }
- }
-}
-
-/* vim: set sw=4 ts=4 expandtab : */
-
--- /dev/null
+#include "mcg.h"
+
+static bool rewrite_jumps_cb(struct ir* ir, void* user)
+{
+ if (ir->opcode == IR_BLOCK)
+ {
+ struct basicblock* bb = ir->u.bvalue;
+ if ((bb->irs_count > 0)
+ && (bb->irs[0]->opcode == IR_JUMP)
+ && (bb->irs[0]->left->opcode == IR_BLOCK))
+ {
+ ir->u.bvalue = bb->irs[0]->left->u.bvalue;
+ }
+ }
+
+ return false;
+}
+
+static void rewrite_jumps(struct basicblock* bb)
+{
+ int i;
+
+ for (i=0; i<bb->irs_count; i++)
+ {
+ struct ir* ir = bb->irs[i];
+ ir_walk(ir, rewrite_jumps_cb, NULL);
+ }
+}
+
+void pass_eliminate_trivial_blocks(struct procedure* proc)
+{
+ int i;
+
+ for (i=0; i<proc->blocks_count; i++)
+ {
+ struct basicblock* bb = proc->blocks[i];
+ rewrite_jumps(bb);
+ }
+}
+
+/* vim: set sw=4 ts=4 expandtab : */
--- /dev/null
+#include "mcg.h"
+
+STATICARRAY(struct basicblock, used);
+
+static void walk_blocks(struct basicblock* bb);
+
+static bool walk_blocks_cb(struct ir* ir, void* user)
+{
+ if (ir->opcode == IR_BLOCK)
+ walk_blocks(ir->u.bvalue);
+ return false;
+}
+
+static void walk_blocks(struct basicblock* bb)
+{
+ int i;
+
+ if (!CONTAINS(used, bb))
+ {
+ APPENDU(used, bb);
+
+ for (i=0; i<bb->irs_count; i++)
+ ir_walk(bb->irs[i], walk_blocks_cb, NULL);
+ }
+}
+
+void pass_remove_dead_blocks(struct procedure* proc)
+{
+ int i, j;
+
+ used_count = 0;
+ walk_blocks(proc->blocks[0]);
+
+ proc->blocks_count = 0;
+ for (i=0; i<used_count; i++)
+ APPEND(proc->blocks, used[i]);
+}
+
+/* vim: set sw=4 ts=4 expandtab : */
+
+++ /dev/null
-#include "mcg.h"
-
-void pass_splice_adjacent_blocks(struct procedure* proc)
-{
- int i, j;
-
-again:
- for (i=0; i<proc->blocks_count; i++)
- {
- struct basicblock* bb = proc->blocks[i];
- if (bb->outblocks_count == 1)
- {
- struct basicblock* outbb = bb->outblocks[0];
- if (outbb->inblocks_count == 1)
- {
- struct ir* lastir = bb->irs[bb->irs_count-1];
-
- if ((lastir->opcode == IR_JUMP)
- && (lastir->left->opcode == IR_BLOCK)
- && (lastir->left->u.bvalue == outbb))
- {
- /* Remove jump instruction. */
-
- bb->irs_count--;
-
- REMOVE(bb->outblocks, outbb);
- REMOVE(outbb->inblocks, bb);
-
- for (j=0; j<outbb->irs_count; j++)
- APPEND(bb->irs, outbb->irs[j]);
- for (j=0; j<outbb->outblocks_count; j++)
- {
- APPENDU(bb->outblocks, outbb->outblocks[j]);
- APPENDU(outbb->outblocks[j]->inblocks, bb);
- REMOVE(outbb->outblocks[j]->inblocks, outbb);
- }
-
- REMOVE(proc->blocks, outbb);
- goto again;
- }
- }
- }
- }
-}
-
-/* vim: set sw=4 ts=4 expandtab : */
-
case op_csa:
case op_csb:
{
- struct basicblock* data_bb;
- int i;
const char* helper = aprintf(".%s%d",
(opcode == op_csa) ? "csa" : "csb",
value);
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. */
+ /* Turn the label reference into a block. */
- 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);
- }
+ descriptor->opcode = IR_BLOCK;
+ descriptor->u.bvalue = bb_get(descriptor->u.lvalue);
push(descriptor);
materialise_stack();