* - think about a smarter sequence of visiting the blocks. Sorted by
* execfreq might be good, or looptree from inner to outermost loops going
* over blocks in a reverse postorder
+ * - propagate preferences through Phis
*/
#include "config.h"
#include <float.h>
#include <stdbool.h>
-#include "obst.h"
-#include "irnode_t.h"
-#include "irgraph_t.h"
-#include "iredges_t.h"
+#include "error.h"
+#include "execfreq.h"
#include "ircons.h"
-#include "irgwalk.h"
#include "irdom.h"
-#include "execfreq.h"
-#include "error.h"
+#include "iredges_t.h"
+#include "irgraph_t.h"
+#include "irgwalk.h"
+#include "irnode_t.h"
+#include "obst.h"
+#include "beabi.h"
+#include "bechordal_t.h"
#include "be.h"
-#include "bera.h"
+#include "beirg.h"
#include "belive_t.h"
#include "bemodule.h"
-#include "bechordal_t.h"
-#include "besched.h"
-#include "beirg.h"
#include "benode_t.h"
+#include "bera.h"
+#include "besched.h"
#include "bespill.h"
#include "bespillutil.h"
#include "beverify.h"
unsigned r = arch_register_get_index(reg);
assignment_t *assignment = &assignments[r];
- assert(assignment->value == NULL);
+ //assert(assignment->value == NULL);
assignment->value = node;
arch_set_irn_register(node, reg);
static void permutate_values(ir_nodeset_t *live_nodes, ir_node *before,
unsigned *permutation)
{
- ir_node *block;
ir_node **ins = ALLOCANZ(ir_node*, n_regs);
unsigned *n_used = ALLOCANZ(unsigned, n_regs);
+ ir_node *block;
unsigned r;
/* create a list of permutations. Leave out fix points. */
ins[old_reg] = value;
++n_used[old_reg];
- free_reg_of_value(value);
+ //free_reg_of_value(value);
/* free occupation infos, we'll add the values back later */
if (live_nodes != NULL) {
/**
* Enforce constraints at a node by live range splits.
*
- * @param live_nodes the set of live nodes, might be changed
- * @param node the current node
+ * @param live_nodes the set of live nodes, might be changed
+ * @param node the current node
*/
static void enforce_constraints(ir_nodeset_t *live_nodes, ir_node *node)
{
&& rbitset_is_set(output_regs, r))
continue;
- hungarian_add(bp, l, r, l == r ? 9 : 8);
+ hungarian_add(bp, r, l, l == r ? 9 : 8);
}
}
for (r = 0; r < n_regs; ++r) {
if (rbitset_is_set(limited, r))
continue;
- hungarian_remv(bp, current_reg, r);
+ hungarian_remv(bp, r, current_reg);
}
}
static bool is_copy_of(ir_node *value, ir_node *test_value)
{
allocation_info_t *test_info;
+ allocation_info_t *info;
- if (value == NULL)
- return false;
if (value == test_value)
return true;
+ info = get_allocation_info(value);
test_info = get_allocation_info(test_value);
- return test_info->original_value == value;
+ return test_info->original_value == info->original_value;
}
/**
assignment_t *assignments = info->assignments;
for (r = 0; r < n_regs; ++r) {
const assignment_t *assignment = &assignments[r];
- if (is_copy_of(assignment->value, value))
+ ir_node *a_value = assignment->value;
+
+ if (a_value == NULL)
+ continue;
+ if (is_copy_of(a_value, value))
return (int) r;
}
continue;
op = get_Phi_pred(node, p);
- a = find_value_in_block_info(pred_info, op);
+ a = find_value_in_block_info(pred_info, op);
assert(a >= 0);
- reg = arch_get_irn_register(node);
+ reg = arch_get_irn_register(node);
regn = arch_register_get_index(reg);
if (regn != a) {
permutation[regn] = a;
- need_permutation = true;
+ need_permutation = true;
}
}
- if (!need_permutation)
- return;
-
- /* permutate values at end of predecessor */
- old_assignments = assignments;
- assignments = pred_info->assignments;
- permutate_values(NULL, be_get_end_of_block_insertion_point(pred),
- permutation);
- assignments = old_assignments;
+ if (need_permutation) {
+ /* permutate values at end of predecessor */
+ old_assignments = assignments;
+ assignments = pred_info->assignments;
+ permutate_values(NULL, be_get_end_of_block_insertion_point(pred),
+ permutation);
+ assignments = old_assignments;
+ }
/* change phi nodes to use the copied values */
node = sched_first(block);
}
}
+/**
+ * change inputs of a node to the current value (copies/perms)
+ */
+static void rewire_inputs(ir_node *node)
+{
+ int i;
+ int arity = get_irn_arity(node);
+
+ for (i = 0; i < arity; ++i) {
+ ir_node *op = get_irn_n(node, i);
+ allocation_info_t *info;
+
+ if (!arch_irn_consider_in_reg_alloc(cls, op))
+ continue;
+
+ info = get_allocation_info(op);
+ if (info->current_value != op) {
+ set_irn_n(node, i, info->current_value);
+ }
+ }
+}
+
/**
* Walker: assign registers to all nodes of a block that
* need registers from the currently considered register class.
ir_node *node, *start;
int n_preds;
block_info_t *block_info;
- block_info_t *processed_pred_info;
block_info_t **pred_block_infos;
- bool all_preds_processed;
+ ir_node **phi_ins;
(void) data;
DB((dbg, LEVEL_2, "* Block %+F\n", block));
/* gather regalloc infos of predecessor blocks */
n_preds = get_Block_n_cfgpreds(block);
pred_block_infos = ALLOCAN(block_info_t*, n_preds);
- all_preds_processed = true;
for (i = 0; i < n_preds; ++i) {
ir_node *pred = get_Block_cfgpred_block(block, i);
block_info_t *pred_info = get_block_info(pred);
pred_block_infos[i] = pred_info;
-
- if (!pred_info->processed) {
- all_preds_processed = false;
- } else {
- /* we need 1 (arbitrary) processed predecessor */
- processed_pred_info = pred_info;
- }
}
+ phi_ins = ALLOCAN(ir_node*, n_preds);
+
/* collect live-in nodes and preassigned values */
be_lv_foreach(lv, block, be_lv_state_in, i) {
const arch_register_t *reg;
+ int p;
node = be_lv_get_irn(lv, block, i);
if (!arch_irn_consider_in_reg_alloc(cls, node))
continue;
- /* if we don't know all predecessors, then we have no idea which values
- are copied, so we have to pessimistically construct phi-nodes for all
- of them */
- if (!all_preds_processed) {
+ /* check all predecessors for this value, if it is not everywhere the
+ same or unknown then we have to construct a phi
+ (we collect the potential phi inputs here) */
+ bool need_phi = false;
+ for (p = 0; p < n_preds; ++p) {
+ block_info_t *pred_info = pred_block_infos[p];
+
+ if (!pred_info->processed) {
+ /* use node for now, it will get fixed later */
+ phi_ins[p] = node;
+ need_phi = true;
+ } else {
+ int a = find_value_in_block_info(pred_info, node);
+
+ /* must live out of predecessor */
+ assert(a >= 0);
+ phi_ins[p] = pred_info->assignments[a].value;
+ /* different value from last time? then we need a phi */
+ if (p > 0 && phi_ins[p-1] != phi_ins[p]) {
+ need_phi = true;
+ }
+ }
+ }
+
+ if (need_phi) {
ir_mode *mode = get_irn_mode(node);
- ir_node **ins = ALLOCAN(ir_node*, n_preds);
const arch_register_req_t *req = get_default_req_current_cls();
ir_node *phi;
- int i2;
- for (i2 = 0; i2 < n_preds; ++i2) {
- ins[i2] = node;
- }
- phi = new_r_Phi(block, n_preds, ins, mode);
+ phi = new_r_Phi(block, n_preds, phi_ins, mode);
be_set_phi_reg_req(phi, req);
- DB((dbg, LEVEL_3, "Pessimistic Phi %+F (for %+F)\n", phi, node));
+ DB((dbg, LEVEL_3, "Create Phi %+F (for %+F)\n", phi, node));
- /* TODO: if node had a register assigned use that as a strong
- preference */
mark_as_copy_of(phi, node);
sched_add_after(block, phi);
node = phi;
} else {
- /* check wether the value is the same in all predecessors,
- if not construct a phi node */
+ /* Grab 1 of the inputs we constructed (might not be the same as
+ * "node" as we could see the same copy of the value in all
+ * predecessors */
+ node = phi_ins[0];
}
/* if the node already has a register assigned use it */
/* assign instructions in the block */
for (node = start; !sched_is_end(node); node = sched_next(node)) {
- int arity = get_irn_arity(node);
- int i;
-
/* enforce use constraints */
enforce_constraints(&live_nodes, node);
- /* exchange values to copied values where needed */
- for (i = 0; i < arity; ++i) {
- ir_node *op = get_irn_n(node, i);
- allocation_info_t *info;
-
- if (!arch_irn_consider_in_reg_alloc(cls, op))
- continue;
-
- info = get_allocation_info(op);
- if (info->current_value != op) {
- set_irn_n(node, i, info->current_value);
- }
- }
+ rewire_inputs(node);
/* free registers of values last used at this instruction */
free_last_uses(&live_nodes, node);
/* verify schedule and register pressure */
BE_TIMER_PUSH(t_verify);
- if (birg->main_env->options->vrfy_option == BE_CH_VRFY_WARN) {
+ if (birg->main_env->options->vrfy_option == BE_VRFY_WARN) {
be_verify_schedule(birg);
be_verify_register_pressure(birg, cls, irg);
- } else if (birg->main_env->options->vrfy_option == BE_CH_VRFY_ASSERT) {
+ } else if (birg->main_env->options->vrfy_option == BE_VRFY_ASSERT) {
assert(be_verify_schedule(birg) && "Schedule verification failed");
assert(be_verify_register_pressure(birg, cls, irg)
&& "Register pressure verification failed");
be_straight_alloc_cls();
BE_TIMER_POP(t_ra_color);
+ /* we most probably constructed new Phis so liveness info is invalid
+ * now */
+ /* TODO: test liveness_introduce */
+ be_liveness_invalidate(lv);
+
bitset_free(ignore_regs);
stat_ev_ctx_pop("regcls");
}
+ BE_TIMER_PUSH(t_ra_spill_apply);
+ be_abi_fix_stack_nodes(birg->abi);
+ BE_TIMER_POP(t_ra_spill_apply);
+
BE_TIMER_PUSH(t_verify);
- if (birg->main_env->options->vrfy_option == BE_CH_VRFY_WARN) {
+ if (birg->main_env->options->vrfy_option == BE_VRFY_WARN) {
be_verify_register_allocation(birg);
- } else if(birg->main_env->options->vrfy_option == BE_CH_VRFY_ASSERT) {
+ } else if (birg->main_env->options->vrfy_option == BE_VRFY_ASSERT) {
assert(be_verify_register_allocation(birg)
&& "Register allocation invalid");
}