into the value_map */
reg_flag_t *regs; /**< registers (and memory values) that form a
state */
- ir_node *last_barrier;
} register_state_mapping_t;
/**
* Add a register and its constraint flags to a register state map
* and return its index inside the map.
*/
-static int rsm_add_reg(register_state_mapping_t *rsm,
- const arch_register_t *reg,
- arch_register_req_type_t flags)
+static size_t rsm_add_reg(register_state_mapping_t *rsm,
+ const arch_register_t *reg,
+ arch_register_req_type_t flags)
{
size_t input_idx = ARR_LEN(rsm->regs);
int cls_idx = reg->reg_class->index;
rsm_set_value(rsm, input_idx, value);
}
-/**
- * Create a Barrier from the registers stored at a register state map.
- *
- * @param rsm the register state map
- * @param block the block to create the Barrier on
- */
-static ir_node *rsm_create_barrier(register_state_mapping_t *rsm,
- ir_node *block)
-{
- size_t n_barrier_outs = ARR_LEN(rsm->regs);
- ir_node **in = rsm->value_map;
- ir_node *barrier;
- size_t o;
-
- assert(ARR_LEN(rsm->value_map) == n_barrier_outs);
-
- barrier = be_new_Barrier(block, n_barrier_outs, in);
-
- for (o = 0; o < n_barrier_outs; ++o) {
- const reg_flag_t *regflag = &rsm->regs[o];
- const arch_register_t *reg = regflag->reg;
- ir_node *proj;
- if (reg == NULL) {
- arch_set_out_register_req(barrier, o, arch_no_register_req);
- proj = new_r_Proj(barrier, mode_M, o);
- } else {
- be_set_constr_single_reg_in(barrier, o, reg, arch_register_req_type_none);
- be_set_constr_single_reg_out(barrier, o, reg, regflag->flags);
- proj = new_r_Proj(barrier, reg->reg_class->mode, o);
- }
- rsm->value_map[o] = proj;
- }
-
- rsm->last_barrier = barrier;
-
- return barrier;
-}
-
-
-
-
beabi_helper_env_t *be_abihelper_prepare(ir_graph *irg)
{
env->prolog.value_map[o] = proj;
}
- /* start node should really be the first thing constructed */
- assert(env->prolog.last_barrier == NULL);
- env->prolog.last_barrier = start;
-
return start;
}
-ir_node *be_prolog_create_barrier(beabi_helper_env_t *env, ir_node *block)
-{
- return rsm_create_barrier(&env->prolog, block);
-}
-
ir_node *be_prolog_get_reg_value(beabi_helper_env_t *env,
const arch_register_t *reg)
{
void be_epilog_add_reg(beabi_helper_env_t *env, const arch_register_t *reg,
arch_register_req_type_t flags, ir_node *value)
{
- int index = rsm_add_reg(&env->epilog, reg, flags);
+ size_t index = rsm_add_reg(&env->epilog, reg, flags);
rsm_set_value(&env->epilog, index, value);
}
return rsm_get_value(&env->epilog, 0);
}
-ir_node *be_epilog_create_barrier(beabi_helper_env_t *env, ir_node *block)
-{
- return rsm_create_barrier(&env->epilog, block);
-}
-
ir_node *be_epilog_create_return(beabi_helper_env_t *env, dbg_info *dbgi,
ir_node *block)
{
}
rsm_clear_regs(&env->epilog, be_get_irg_arch_env(env->irg));
- env->epilog.last_barrier = NULL;
return ret;
}
+/**
+ * Tests whether a node has a real user and is not just kept by the End or
+ * Anchor node
+ */
+static bool has_real_user(const ir_node *node)
+{
+ const ir_edge_t *edge;
+ foreach_out_edge(node, edge) {
+ ir_node *user = get_edge_src_irn(edge);
+ if (!is_End(user) && !is_Anchor(user))
+ return true;
+ }
+ return false;
+}
+
+static ir_node *add_to_keep(ir_node *last_keep,
+ const arch_register_class_t *cls, ir_node *node)
+{
+ if (last_keep != NULL) {
+ be_Keep_add_node(last_keep, cls, node);
+ } else {
+ ir_node *in[1] = { node };
+ ir_node *block = get_nodes_block(node);
+ ir_node *schedpoint;
+ last_keep = be_new_Keep(block, 1, in);
+
+ schedpoint = skip_Proj(node);
+ if (sched_is_scheduled(schedpoint)) {
+ sched_add_after(schedpoint, last_keep);
+ }
+ }
+ return last_keep;
+}
+
static void add_missing_keep_walker(ir_node *node, void *data)
{
int n_outs, i;
const ir_edge_t *edge;
ir_mode *mode = get_irn_mode(node);
ir_node *last_keep;
+ ir_node **existing_projs;
(void) data;
- if (mode != mode_T)
+ if (mode != mode_T) {
+ if (!has_real_user(node)) {
+ const arch_register_req_t *req = arch_get_register_req_out(node);
+ const arch_register_class_t *cls = req->cls;
+ if (cls == NULL
+ || (cls->flags & arch_register_class_flag_manual_ra)) {
+ return;
+ }
+
+ add_to_keep(NULL, cls, node);
+ }
return;
+ }
n_outs = arch_irn_get_n_outs(node);
if (n_outs <= 0)
return;
rbitset_alloca(found_projs, n_outs);
+ existing_projs = ALLOCANZ(ir_node*, n_outs);
foreach_out_edge(node, edge) {
ir_node *succ = get_edge_src_irn(edge);
ir_mode *mode = get_irn_mode(succ);
/* The node could be kept */
if (is_End(succ) || is_Anchor(succ))
continue;
-
if (mode == mode_M || mode == mode_X)
continue;
+ pn = get_Proj_proj(succ);
+ existing_projs[pn] = succ;
+ if (!has_real_user(succ))
+ continue;
- pn = get_Proj_proj(succ);
assert(pn < n_outs);
rbitset_set(found_projs, pn);
}
-
/* are keeps missing? */
last_keep = NULL;
for (i = 0; i < n_outs; ++i) {
- ir_node *block;
- ir_node *in[1];
+ ir_node *value;
const arch_register_req_t *req;
const arch_register_class_t *cls;
continue;
}
- block = get_nodes_block(node);
- in[0] = new_r_Proj(node, arch_register_class_mode(cls), i);
- if (last_keep != NULL) {
- be_Keep_add_node(last_keep, cls, in[0]);
- } else {
- last_keep = be_new_Keep(block, 1, in);
- if (sched_is_scheduled(node)) {
- sched_add_after(node, last_keep);
- }
- }
+ value = existing_projs[i];
+ if (value == NULL)
+ value = new_r_Proj(node, arch_register_class_mode(cls), i);
+ last_keep = add_to_keep(last_keep, cls, value);
}
}