ARRAYOF(struct basicblock) nexts;
int order; /* used by dominance graph code */
- PMAPOF(struct vreg, struct phi) phis;
-
- /* Used by liveness calculation. */
- ARRAYOF(struct vreg) liveins;
- ARRAYOF(struct vreg) liveouts;
-
- /* Register assignments on entry and exit. */
- register_assignment_t regsin;
- register_assignment_t* regsout; /* points at regsout of the last insn. */
+ PMAPOF(struct ir, struct ir) imports;
+ PMAPOF(struct ir, struct ir) exports;
bool is_fake : 1;
bool is_root : 1;
return hop;
}
-struct hop* new_copy_hop(struct basicblock* bb, struct vreg* src, struct vreg* dest)
+struct hop* new_move_hop(struct basicblock* bb)
{
struct hop* hop = heap_alloc(&proc_heap, 1, sizeof(*hop));
hop->id = hop_count++;
hop->bb = bb;
hop->is_move = true;
- array_append(&hop->ins, src);
- array_append(&hop->outs, dest);
return hop;
}
void hop_add_string_insel(struct hop* hop, const char* string)
{
- struct insel* insel = new_insel(INSEL_STRING);
- insel->u.string = string;
- array_append(&hop->insels, insel);
+ struct insel* insel = new_insel(INSEL_STRING);
+ insel->u.string = string;
+ array_append(&hop->insels, insel);
}
void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg, int index)
array_append(&hop->insels, insel);
}
-void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg, int index)
+void hop_add_vreg_insel(struct hop* hop, struct value* value, int index)
{
struct insel* insel = new_insel(INSEL_VREG);
- insel->u.vreg = vreg;
+ insel->u.value = value;
insel->index = index;
array_append(&hop->insels, insel);
}
void hop_add_value_insel(struct hop* hop, struct ir* ir)
{
struct insel* insel = new_insel(INSEL_VALUE);
- insel->u.value = ir;
+ insel->u.ir = ir;
array_append(&hop->insels, insel);
}
void hop_add_eoi_insel(struct hop* hop)
{
- struct insel* insel = new_insel(INSEL_EOI);
- array_append(&hop->insels, insel);
+ struct insel* insel = new_insel(INSEL_EOI);
+ array_append(&hop->insels, insel);
}
void hop_add_insel(struct hop* hop, const char* fmt, ...)
break;
case 'V':
- hop_add_vreg_insel(hop, va_arg(ap, struct vreg*), index);
+ hop_add_vreg_insel(hop, va_arg(ap, struct value*), index);
break;
}
}
tracef(k, " from $%d", hop->ir->id);
tracef(k, ":");
- for (i=0; i<hop->ins.count; i++)
- tracef(k, " r%%%d", hop->ins.item[i]->id);
+ for (i=0; i<hop->inputs.count; i++)
+ {
+ struct value* value = hop->inputs.item[i];
+ tracef(k, " r$%d:%d", value->ir->id, value->subid);
+ }
+
+ for (i=0; i<hop->outputs.count; i++)
+ {
+ struct value* value = hop->outputs.item[i];
+ tracef(k, " w$%d:%d", value->ir->id, value->subid);
+ }
+
for (i=0; i<hop->throughs.count; i++)
- tracef(k, " =%%%d", hop->throughs.item[i]->id);
- for (i=0; i<hop->outs.count; i++)
- tracef(k, " w%%%d", hop->outs.item[i]->id);
+ {
+ struct value* value = hop->throughs.item[i];
+ tracef(k, " =$%d:%d", value->ir->id, value->subid);
+ }
+
tracef(k, " ");
}
bufferlen = 0;
buffer[0] = '\0';
+ if (hop->pseudo)
+ appendf("@");
+
if (hop->is_move && (hop->insels.count == 0))
- appendf("(move %%%d -> %%%d)\n", hop->ins.item[0]->id, hop->outs.item[0]->id);
+ appendf("(move)\n");
for (i=0; i<hop->insels.count; i++)
{
case INSEL_VREG:
{
- struct vreg* vreg = insel->u.vreg;
+ struct value* value = insel->u.value;
+ #if 0
struct hreg* hreg = pmap_findright(&hop->regsin, vreg);
if (!hreg)
hreg = pmap_findright(&hop->regsout, vreg);
appendf("%s", hreg->brd->names[insel->index]);
else
appendf("%%%d.%d", vreg->id, insel->index);
+ #endif
+ appendf("$%d:%d", value->ir->id, value->subid);
+ if (insel->index)
+ appendf(".%d", insel->index);
break;
}
case INSEL_VALUE:
{
- struct ir* ir = insel->u.value;
+ struct ir* ir = insel->u.ir;
switch (ir->opcode)
{
case IR_BLOCK:
default:
assert(false);
}
+
+ if (hop->pseudo)
+ appendf(" ");
}
return buffer;
{
const char* string;
struct hreg* hreg;
- struct vreg* vreg;
- struct ir* value;
+ struct value* value;
+ struct ir* ir;
int offset;
}
u;
};
-struct constraint
-{
- uint32_t attrs;
- bool preserved;
- struct vreg* equals_to;
-};
-
struct hop
{
int id;
struct ir* ir;
const struct burm_instruction_data* insndata;
ARRAYOF(struct insel) insels;
- struct vreg* output;
+ struct value* value;
bool is_move;
+ const char* pseudo;
+ PMAPOF(struct value, struct value) equals_constraint;
- PMAPOF(struct vreg, struct constraint) constraints;
-
- ARRAYOF(struct vreg) ins;
- ARRAYOF(struct vreg) outs;
- ARRAYOF(struct vreg) throughs;
- register_assignment_t regsin;
- register_assignment_t regsout;
+ ARRAYOF(struct value) inputs;
+ ARRAYOF(struct value) outputs;
+ ARRAYOF(struct value) throughs;
};
extern struct hop* new_hop(struct basicblock* bb, struct ir* ir);
-extern struct hop* new_copy_hop(struct basicblock* bb, struct vreg* src, struct vreg* dest);
+extern struct hop* new_move_hop(struct basicblock* bb);
extern void hop_add_string_insel(struct hop* hop, const char* string);
extern void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg, int index);
-extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg, int index);
+extern void hop_add_vreg_insel(struct hop* hop, struct value* value, int index);
extern void hop_add_value_insel(struct hop* hop, struct ir* ir);
extern void hop_add_st_offset_insel(struct hop* hop, struct hreg* hreg);
extern void hop_add_ab_offset_insel(struct hop* hop, int offset);
static int next_id = 0;
+uint32_t value_hash_function(void* key)
+{
+ struct value* value = key;
+ /* This is the standard C++ std::hash_combine. */
+ return value->ir->id + 0x9e3779b9 + (value->subid << 6) + (value->subid >> 2);
+}
+
+bool value_comparison_function(void* key1, void* key2)
+{
+ struct value* val1 = key1;
+ struct value* val2 = key2;
+ return (val1->ir->id == val2->ir->id) && (val1->subid == val2->subid);
+}
+
struct ir* new_ir0(int opcode, int size)
{
struct ir* ir = calloc(1, sizeof(struct ir));
+ ir->value.ir = ir;
ir->id = next_id++;
ir->opcode = opcode;
ir->size = size;
#include "ircodes.h"
+struct value
+{
+ struct ir* ir;
+ int subid;
+ uint32_t attrs;
+};
+
+extern uint32_t value_hash_function(void* key);
+extern bool value_comparison_function(void* key1, void* key2);
+#define HASHTABLE_OF_VALUES \
+ { value_hash_function, value_comparison_function }
+
struct ir
{
+ /* A struct ir must be castable to a struct value */
+ struct value value;
+
int id;
enum ir_opcode opcode;
int size;
struct basicblock* bvalue;
PMAPOF(struct basicblock, struct ir) phivalue;
} u;
-
- struct vreg* result; /* vreg containing IR result */
};
extern const char* ir_names[];
#include "em_flag.h"
#include "em_ptyp.h"
#include "array.h"
-#include "imap.h"
#include "pmap.h"
#include "heap.h"
#include "diagnostics.h"
} bvalue;
} u;
};
-
+
extern const char* aprintf(const char* fmt, ...);
extern void tracef(char k, const char* fmt, ...);
extern bool tracing(char k);
extern void pass_infer_types(void);
extern void pass_insert_moves(void);
extern void pass_instruction_selector(void);
-extern void pass_live_vreg_analysis(void);
+extern void pass_live_value_analysis(void);
extern void pass_add_prologue_epilogue(void);
extern void pass_register_allocator(void);
extern void pass_remove_dead_blocks(void);
struct insn
{
+ /* struct insn must be castable to a struct value */
+ struct value value;
+
struct ir* ir;
struct hop* hop;
const struct burm_instruction_data* insndata;
};
static struct basicblock* current_bb;
+static struct ir* root_ir;
+static int hop_id;
static struct hop* current_hop;
static struct ir* current_ir;
static struct insn* current_insn;
static void emit_return_reg(int index)
{
- hop_add_vreg_insel(current_hop, current_hop->output, index);
+ hop_add_vreg_insel(current_hop, ¤t_insn->value, index);
}
-static struct vreg* find_vreg_of_child(int child)
+static struct value* find_value_of_child(int child)
{
struct insn* insn = current_insn->children[child];
if (insn->hop)
- return insn->hop->output;
+ return insn->hop->value;
else
- return insn->ir->result;
+ return &insn->ir->value;
}
static void emit_reg(int child, int index)
{
- struct vreg* vreg = find_vreg_of_child(child);
+ struct value* value = find_value_of_child(child);
- if (vreg)
- {
- hop_add_vreg_insel(current_hop, vreg, index);
- }
+ assert(value);
+ hop_add_vreg_insel(current_hop, value, index);
}
static void emit_string(const char* data)
hop_add_eoi_insel(current_hop);
}
-static struct constraint* get_constraint(struct vreg* vreg)
-{
- struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg);
- if (!c)
- {
- c = heap_alloc(&proc_heap, 1, sizeof(*c));
- pmap_put(¤t_hop->constraints, vreg, c);
- }
- return c;
-}
-
static void constrain_input_reg(int child, uint32_t attr)
{
- struct vreg* vreg = find_vreg_of_child(child);
+ struct value* value = find_value_of_child(child);
struct constraint* c;
- assert(vreg);
-
- array_appendu(¤t_hop->ins, vreg);
- get_constraint(vreg)->attrs = attr;
+ array_appendu(¤t_hop->inputs, value);
+ value->attrs = attr;
}
static void constrain_input_reg_preserved(int child)
{
- struct vreg* vreg = find_vreg_of_child(child);
+ struct value* value = find_value_of_child(child);
struct constraint* c;
- assert(vreg);
- array_appendu(¤t_hop->throughs, vreg);
- get_constraint(vreg)->preserved = true;
+ array_appendu(¤t_hop->throughs, value);
}
static uint32_t find_type_from_constraint(uint32_t attr)
{
if (brd->attrs & attr)
{
- const uint32_t type_attrs =
+ const uint32_t type_attrs =
(burm_int_ATTR | burm_float_ATTR |
burm_long_ATTR | burm_double_ATTR);
static void constrain_output_reg(uint32_t attr)
{
- struct vreg* vreg = current_hop->output;
-
- if (!vreg)
- current_hop->output = vreg = new_vreg();
+ struct value* value = ¤t_insn->value;
- array_appendu(¤t_hop->outs, vreg);
- vreg->type = find_type_from_constraint(attr);
-
- get_constraint(vreg)->attrs = attr;
+ array_appendu(¤t_hop->outputs, value);
+ value->attrs = find_type_from_constraint(attr);
}
static void constrain_output_reg_equal_to(int child)
{
- struct vreg* vreg = find_vreg_of_child(child);
-
- get_constraint(current_hop->output)->equals_to = vreg;
+ struct value* value = find_value_of_child(child);
+ pmap_add(¤t_hop->equals_constraint, ¤t_hop->value, value);
}
static const struct burm_emitter_data emitter_data =
struct insn* insn = heap_alloc(&proc_heap, 1, sizeof(*insn));
int i;
+ insn->value.ir = current_ir;
+ /* hop IDs count in preorder, so the result is always in $thing:0. */
+ insn->value.subid = hop_id++;
+
insn->ir = node->ir;
insn->num_children = 0;
i++;
}
- tracef('I', "I: $%d goal %d %s selected %d: %s\n",
+ tracef('I', "I: $%d:%d for node $%d goal %d %s selected %d: %s\n",
+ insn->value.ir->id, insn->value.subid,
node->ir->id,
goal,
insn->insndata->is_fragment ? "fragment" : "instruction",
current_hop->insndata = insn->insndata;
emit(insn);
- if (!current_hop->output)
+ current_hop->value = &insn->value;
+ switch (node->label)
{
- switch (node->label)
- {
- case ir_to_esn(IR_REG, 0):
- current_hop->output = node->ir->result;
- assert(current_hop->output != NULL);
- break;
-
- case ir_to_esn(IR_NOP, 'I'):
- case ir_to_esn(IR_NOP, 'F'):
- case ir_to_esn(IR_NOP, 'L'):
- case ir_to_esn(IR_NOP, 'D'):
- current_hop->output = node->left->ir->result;
- assert(current_hop->output != NULL);
- break;
- }
+ case ir_to_esn(IR_REG, 0):
+ current_hop->value = &node->ir->value;
+ break;
+
+ case ir_to_esn(IR_NOP, 'I'):
+ case ir_to_esn(IR_NOP, 'F'):
+ case ir_to_esn(IR_NOP, 'L'):
+ case ir_to_esn(IR_NOP, 'D'):
+ array_appendu(¤t_hop->inputs, &insn->children[0]->value);
+ array_appendu(¤t_hop->outputs, current_hop->value);
+ hop_add_insel(current_hop, "@copy %V %V", &insn->children[0]->value, current_hop->value);
+ break;
}
hop_print('I', current_hop);
array_append(¤t_bb->hops, current_hop);
-
- if ((goal != burm_stmt_NT) && !insn->ir->result)
- insn->ir->result = insn->hop->output;
}
}
static void select_instructions(void)
{
- int i;
+ int i, j;
tracef('I', "I: BLOCK: %s\n", current_bb->name);
- for (i=0; i<current_bb->irs.count; i++)
- {
- struct burm_node* shadow;
- int insnno;
-
+ for (i=0; i<current_bb->irs.count; i++)
+ {
current_ir = current_bb->irs.item[i];
+ if (current_ir->opcode != IR_PHI)
+ break;
- if (current_ir->opcode == IR_PHI)
+ tracef('I', "I: $%d is phi:", current_ir->id);
+ for (j=0; j<current_ir->u.phivalue.count; j++)
{
- int j;
+ struct basicblock* parentbb = current_ir->u.phivalue.item[j].left;
+ struct ir* parentir = current_ir->u.phivalue.item[j].right;
+ tracef('I', " %s=>$%d", parentbb->name, parentir->id);
- current_ir->result = new_vreg();
- tracef('I', "I: $%d is phi:", current_ir->result->id);
- for (j=0; j<current_ir->u.phivalue.count; j++)
- {
- struct basicblock* parentbb = current_ir->u.phivalue.item[j].left;
- struct ir* parentir = current_ir->u.phivalue.item[j].right;
- struct phi* phi = calloc(1, sizeof(*phi));
- tracef('I', " %s=>$%d", parentbb->name, parentir->id);
-
- phi->prev = parentbb;
- phi->ir = parentir;
- pmap_add(¤t_bb->phis, current_ir->result, phi);
- }
- tracef('I', "\n");
+ pmap_add(¤t_bb->imports, parentir, current_ir);
+ pmap_add(&parentbb->exports, parentir, current_ir);
}
- else
- {
- ir_print('I', current_ir);
- shadow = build_shadow_tree(current_ir, current_ir);
- burm_label(shadow);
+ tracef('I', "\n");
+ }
- insnno = burm_rule(shadow->state_label, 1);
- if (!insnno)
- burm_panic_cannot_match(shadow);
+ for (; i<current_bb->irs.count; i++)
+ {
+ struct burm_node* shadow;
+ int insnno;
- walk_instructions(shadow, burm_stmt_NT);
- }
+ current_ir = current_bb->irs.item[i];
+ assert(current_ir->opcode != IR_PHI);
+
+ ir_print('I', current_ir);
+ shadow = build_shadow_tree(current_ir, current_ir);
+ burm_label(shadow);
+
+ insnno = burm_rule(shadow->state_label, 1);
+ if (!insnno)
+ burm_panic_cannot_match(shadow);
+
+ hop_id = 0;
+ walk_instructions(shadow, burm_stmt_NT);
}
}
--- /dev/null
+#include "mcg.h"
+
+static struct set known_live = { HASHTABLE_OF_VALUES };
+
+static void propagate_liveness(struct basicblock* bb)
+{
+ static struct set current;
+ int i, j;
+
+ set_empty(&known_live);
+
+ for (i=0; i<bb->exports.count; i++)
+ set_add(&known_live, bb->exports.item[i].left);
+
+ for (i=bb->hops.count-1; i>=0; i--)
+ {
+ struct hop* hop = bb->hops.item[i];
+
+ /* Values are only ever written once, so if we see a write then we
+ * know the value was not live before this. */
+
+ for (j=0; j<hop->outputs.count; j++)
+ {
+ struct value* value = hop->outputs.item[j];
+ set_remove(&known_live, value);
+ }
+
+ /* Propagate the set of live values across this hop. */
+
+ {
+ struct set_iterator si = {};
+ while (set_next(&known_live, &si))
+ {
+ struct value* value = si.item;
+ array_appendu(&hop->throughs, value);
+ }
+ }
+
+ /* Values which are read from must have come from somewhere, and so
+ * become live. */
+
+ for (j=0; j<hop->inputs.count; j++)
+ {
+ struct value* value = hop->inputs.item[j];
+ set_add(&known_live, value);
+ }
+ }
+}
+
+void pass_live_value_analysis(void)
+{
+ int i;
+
+ for (i=0; i<dominance.postorder.count; i++)
+ propagate_liveness(dominance.postorder.item[i]);
+}
+
+/* vim: set sw=4 ts=4 expandtab : */
+
+++ /dev/null
-#include "mcg.h"
-
-static bool finished;
-
-static void preload_blocks(void)
-{
- /* Any variable referenced in a phi *must* be a liveout of one of our
- * predecessors. */
-
- int i, j;
- for (i=0; i<cfg.preorder.count; i++)
- {
- struct basicblock* bb = cfg.preorder.item[i];
-
- for (j=0; j<bb->phis.count; j++)
- {
- struct vreg* vreg = bb->phis.item[j].left;
- struct phi* phi = bb->phis.item[j].right;
-
- assert(array_contains(&bb->prevs, phi->prev));
- array_appendu(&phi->prev->liveouts, phi->ir->result);
- }
- }
-}
-
-static bool add_set_to_array(struct set* set, void* arrayp)
-{
- bool nochange = true;
- struct array* array = arrayp;
- struct set_iterator sit = {};
-
- while (set_next(set, &sit))
- nochange &= array_appendu(array, sit.item);
-
- return nochange;
-}
-
-static void add_array_to_set(void* arrayp, struct set* set)
-{
- struct array* array = arrayp;
- int i;
-
- for (i=0; i<array->count; i++)
- set_add(set, array->item[i]);
-}
-
-static void remove_array_from_set(void* arrayp, struct set* set)
-{
- struct array* array = arrayp;
- int i;
-
- for (i=0; i<array->count; i++)
- set_remove(set, array->item[i]);
-}
-
-static void propagate_liveness(struct basicblock* bb)
-{
- static struct set current;
- int i, j;
-
- set_empty(¤t);
-
- add_array_to_set(&bb->liveouts, ¤t);
-
- for (i=bb->hops.count-1; i>=0; i--)
- {
- struct hop* hop = bb->hops.item[i];
-
- remove_array_from_set(&hop->outs, ¤t);
- finished &= add_set_to_array(¤t, &hop->throughs);
- add_array_to_set(&hop->ins, ¤t);
- }
-
- for (i=0; i<bb->phis.count; i++)
- set_remove(¤t, bb->phis.item[i].left);
-
- finished &= add_set_to_array(¤t, &bb->liveins);
-
- for (i=0; i<bb->prevs.count; i++)
- {
- struct basicblock* prev = bb->prevs.item[i];
- finished &= add_set_to_array(¤t, &prev->liveouts);
- }
-}
-
-void pass_live_vreg_analysis(void)
-{
- int i;
-
- preload_blocks();
-
- do
- {
- finished = true;
-
- tracef('L', "L: beginning liveness pass\n");
- for (i=0; i<dominance.postorder.count; i++)
- propagate_liveness(dominance.postorder.item[i]);
- }
- while (!finished);
-}
-
-/* vim: set sw=4 ts=4 expandtab : */
-
tracef(k, "\n");
}
- if (bb->liveins.count > 0)
+ if (bb->imports.count > 0)
{
tracef(k, "%c: INS:", k);
- for (j=0; j<bb->liveins.count; j++)
- tracef(k, " %%%d", bb->liveins.item[j]->id);
+ for (j=0; j<bb->imports.count; j++)
+ tracef(k, " $%d->$%d",
+ bb->imports.item[j].left->id, bb->imports.item[j].right->id);
tracef(k, "\n");
}
- if (bb->liveouts.count > 0)
+ if (bb->exports.count > 0)
{
tracef(k, "%c: OUTS:", k);
- for (j=0; j<bb->liveouts.count; j++)
- tracef(k, " %%%d", bb->liveouts.item[j]->id);
- tracef(k, "\n");
- }
-
- if (bb->phis.count > 0)
- {
- tracef(k, "%c: PHIS:", k);
- for (j=0; j<bb->phis.count; j++)
- {
- struct vreg* vreg = bb->phis.item[j].left;
- struct phi* phi = bb->phis.item[j].right;
-
- tracef(k, " %%%d(via %s)=>%%%d",
- phi->ir->result->id,
- phi->prev->name,
- vreg->id);
- }
+ for (j=0; j<bb->exports.count; j++)
+ tracef(k, " $%d->$%d",
+ bb->exports.item[j].left->id, bb->exports.item[j].right->id);
tracef(k, "\n");
}
for (i=0; i<dominance.preorder.count; i++)
{
struct basicblock* bb = dominance.preorder.item[i];
-
+
fprintf(outputfile, "%s:\n", platform_label(bb->name));
for (j=0; j<bb->hops.count; j++)
{
print_blocks('6');
pass_instruction_selector();
print_hops('7');
+ pass_live_value_analysis();
+ print_hops('8');
+#if 0
pass_split_live_ranges();
pass_determine_vreg_usage();
- print_hops('8');
- pass_live_vreg_analysis();
pass_register_allocator();
pass_add_prologue_epilogue();
print_hops('9');
emit_procedure(proc);
heap_free(&proc_heap);
+#endif
}
/* vim: set sw=4 ts=4 expandtab : */
int fp_to_sb; /* spill base (indexes up) */
int fp_to_rb; /* saved registers base (indexes up) */
ARRAYOF(struct basicblock) blocks;
- IMAPOF(struct local) locals;
+ PMAPOF(void, struct local) locals;
ARRAYOF(struct hreg) usedregs;
};
#include "mcg.h"
-static int vreg_count = 1;
-
-struct vreg* new_vreg(void)
-{
- struct vreg* vreg = heap_alloc(&proc_heap, 1, sizeof *vreg);
- vreg->id = vreg_count++;
- return vreg;
-}
-
struct hreg* new_hreg(const struct burm_register_data* brd)
{
struct hreg* hreg = heap_alloc(&proc_heap, 1, sizeof *hreg);
ARRAYOF(struct hreg) aliases;
};
-struct vreg
-{
- int id;
- uint32_t type;
- struct anode* anode;
- bool is_spillable;
- struct hop* defined;
- ARRAYOF(struct hop) usedhops;
- ARRAYOF(struct basicblock) usedphis;
-};
-
-typedef PMAPOF(struct hreg, struct vreg) register_assignment_t;
-
-extern struct vreg* new_vreg(void);
-
extern struct hreg* new_hreg(const struct burm_register_data* brd);
extern struct hreg* new_stacked_hreg(uint32_t type);
local->size = size;
local->offset = offset;
local->is_register = true;
- imap_put(&procedure->locals, offset, local);
+
+ pmap_put(&procedure->locals, (void*)(intptr_t)offset, local);
}
static struct ir* address_of_external(const char* label, arith offset)