per-hop value metadata.
return hop;
}
+struct valueusage* hop_get_value_usage(struct hop* hop, struct value* value)
+{
+ struct valueusage* usage;
+
+ if (!hop->valueusage)
+ {
+ hop->valueusage = heap_alloc(&proc_heap, 1, sizeof(struct hashtable));
+ *hop->valueusage = empty_hashtable_of_values;
+ }
+
+ usage = hashtable_get(hop->valueusage, value);
+ if (!usage)
+ {
+ usage = heap_alloc(&proc_heap, 1, sizeof(struct hashtable));
+ hashtable_put(hop->valueusage, value, usage);
+ }
+
+ return usage;
+}
+
static struct insel* new_insel(enum insel_type type)
{
struct insel* insel = heap_alloc(&proc_heap, 1, sizeof(*insel));
appendf(" from $%d", hop->ir->id);
appendf(":");
- for (i=0; i<hop->inputs.count; i++)
{
- struct value* value = hop->inputs.item[i];
- appendf(" r");
- appendvalue(hop, value);
- }
-
- for (i=0; i<hop->outputs.count; i++)
- {
- struct value* value = hop->outputs.item[i];
- appendf(" w");
- appendvalue(hop, value);
- }
+ struct hashtable_iterator hit = {};
+ while (hashtable_next(hop->valueusage, &hit))
+ {
+ struct value* value = hit.key;
+ struct valueusage* usage = hit.value;
- for (i=0; i<hop->throughs.count; i++)
- {
- struct value* value = hop->throughs.item[i];
- appendf(" =");
- appendvalue(hop, value);
+ appendf(" ");
+ if (usage->input)
+ appendf("r");
+ if (usage->output)
+ appendf("w");
+ if (usage->through)
+ appendf("=");
+ if (usage->corrupted)
+ appendf("!");
+ appendvalue(hop, value);
+ }
}
appendf(" ");
u;
};
+struct valueusage
+{
+ struct vreg* vreg;
+ bool input : 1;
+ bool output : 1;
+ bool through : 1;
+ bool corrupted : 1;
+};
+
struct hop
{
int id;
const char* pseudo;
PMAPOF(struct value, struct value) equals_constraint;
- ARRAYOF(struct value) inputs;
- ARRAYOF(struct value) outputs;
- ARRAYOF(struct value) throughs;
- ARRAYOF(struct value) corrupted;
+ struct hashtable* valueusage;
- struct hashtable* vregmapping;
+ struct hashtable* vregmapping; /* value -> vreg */
PMAPOF(struct vreg, struct vreg) copies;
};
extern struct hop* new_hop(struct basicblock* bb, struct ir* ir);
extern struct hop* new_move_hop(struct basicblock* bb);
+extern struct valueusage* hop_get_value_usage(struct hop* hop, struct value* value);
+
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 value* value, int index);
static int next_id = 0;
+const struct hashtable empty_hashtable_of_values = HASHTABLE_OF_VALUES;
+
uint32_t value_hash_function(void* key)
{
struct value* value = key;
extern bool value_comparison_function(void* key1, void* key2);
#define HASHTABLE_OF_VALUES \
{ value_hash_function, value_comparison_function }
+extern const struct hashtable empty_hashtable_of_values;
struct ir
{
#include "mcg.h"
-static const struct hashtable empty_hashtable_of_values = HASHTABLE_OF_VALUES;
-
static struct basicblock* current_bb;
static int vregcount = 0;
static bool hop_reads_value(struct hop* hop, struct value* value)
{
- int i;
-
- for (i=0; i<hop->inputs.count; i++)
- if (value_comparison_function(hop->inputs.item[i], value))
- return true;
-
- for (i=0; i<hop->throughs.count; i++)
- if (value_comparison_function(hop->throughs.item[i], value))
- return true;
-
- return false;
+ struct valueusage* usage = hop_get_value_usage(hop, value);
+ return usage->input || usage->through;
}
static void assign_vregs(void)
current_bb->inputmapping = heap_alloc(&proc_heap, 1, sizeof(struct hashtable));
*current_bb->inputmapping = empty_hashtable_of_values;
hashtable_empty(current_bb->inputmapping);
- for (i=0; i<hop->inputs.count; i++)
- create_and_map_vreg(current_bb->inputmapping, hop->inputs.item[i]);
- for (i=0; i<hop->throughs.count; i++)
- create_and_map_vreg(current_bb->inputmapping, hop->throughs.item[i]);
+
+ {
+ struct hashtable_iterator hit = {};
+ while (hashtable_next(hop->valueusage, &hit))
+ {
+ struct value* value = hit.key;
+ struct valueusage* usage = hit.value;
+
+ if (usage->input || usage->through)
+ create_and_map_vreg(current_bb->inputmapping, value);
+ }
+ }
previous_mapping = current_bb->inputmapping;
for (i=0; i<current_bb->hops.count; i++)
/* Create vregs for any new outputs. */
- for (j=0; j<hop->outputs.count; j++)
- create_and_map_vreg(current_mapping, hop->outputs.item[j]);
+ {
+ struct hashtable_iterator hit = {};
+ while (hashtable_next(hop->valueusage, &hit))
+ {
+ struct value* value = hit.key;
+ struct valueusage* usage = hit.value;
+
+ if (usage->output)
+ create_and_map_vreg(current_mapping, value);
+ }
+ }
/* And move on to the next one. */
struct value* value = find_value_of_child(child);
struct constraint* c;
- array_appendu(¤t_hop->inputs, value);
+ hop_get_value_usage(current_hop, value)->input = true;
value->attrs = attr;
}
struct value* value = find_value_of_child(child);
struct constraint* c;
- array_appendu(¤t_hop->corrupted, value);
+ hop_get_value_usage(current_hop, value)->corrupted = true;
}
static uint32_t find_type_from_constraint(uint32_t attr)
{
struct value* value = ¤t_insn->value;
- array_appendu(¤t_hop->outputs, value);
+ hop_get_value_usage(current_hop, value)->output = true;
value->attrs = find_type_from_constraint(attr);
}
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_get_value_usage(current_hop, &insn->children[0]->value)->input = true;
+ hop_get_value_usage(current_hop, current_hop->value)->output = true;
hop_add_insel(current_hop, "@copy %V %V", &insn->children[0]->value, current_hop->value);
break;
}
/* 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);
+ struct hashtable_iterator hit = {};
+ while (hashtable_next(hop->valueusage, &hit))
+ {
+ struct value* value = hit.key;
+ struct valueusage* usage = hit.value;
+
+ if (usage->output)
+ set_remove(&known_live, value);
+ }
}
/* Propagate the set of live values across this hop. */
while (set_next(&known_live, &si))
{
struct value* value = si.item;
- array_appendu(&hop->throughs, value);
+ hop_get_value_usage(hop, value)->through = true;
}
}
/* 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);
+ struct hashtable_iterator hit = {};
+ while (hashtable_next(hop->valueusage, &hit))
+ {
+ struct value* value = hit.key;
+ struct valueusage* usage = hit.value;
+
+ if (usage->input)
+ set_remove(&known_live, value);
+ }
}
}
}