Commit 8e4997d4 authored by Matthias Braun's avatar Matthias Braun
Browse files

Add loop attribute to Phi node

This makes our usage of PhiMs to represent the observable behaviour of
non-terminating loops more obvious.
Having an explicit loop Phi constructor also fixes problems with Phi
getting optimized before the keep edge was added.
parent 618f76da
......@@ -353,6 +353,25 @@ FIRM_API ir_node *new_Const_long(ir_mode *mode, long value);
/** @} */
/** @addtogroup Phi
* @{
*/
/** Constructor for memory Phi with keep-alive edge. */
FIRM_API ir_node *new_rd_Phi_loop(dbg_info *db, ir_node *block,
int arity, ir_node *in[]);
/** Constructor for memory Phi with keep-alive edge. */
FIRM_API ir_node *new_r_Phi_loop(ir_node *block, int arity, ir_node *in[]);
/** Constructor for memory Phi with keep-alive edge. */
FIRM_API ir_node *new_d_Phi_loop(dbg_info *db, int arity, ir_node *in[]);
/** Constructor for memory Phi with keep-alive edge. */
FIRM_API ir_node *new_Phi_loop(int arity, ir_node *in[]);
/** @} */
/** @addtogroup Div
* @{
*/
......
......@@ -175,8 +175,10 @@ static ir_node *set_phi_arguments(ir_node *phi, int pos)
/* To solve the problem of (potentially) endless loops being observable
* behaviour we add a keep-alive edge too all PhiM nodes. */
if (mode == mode_M && !is_Id(phi))
if (mode == mode_M && !is_Id(phi)) {
phi->attr.phi.loop = true;
keep_alive(phi);
}
return phi;
}
......@@ -333,6 +335,37 @@ ir_node *new_DivRL(ir_node * irn_mem, ir_node * irn_left, ir_node * irn_right, i
return new_d_DivRL(NULL, irn_mem, irn_left, irn_right, resmode, pin_state);
}
ir_node *new_rd_Phi_loop(dbg_info *db, ir_node *block, int arity,
ir_node *in[])
{
ir_graph *const irg = get_Block_irg(block);
ir_node *res = new_ir_node(db, irg, block, op_Phi, mode_M, arity, in);
res->attr.phi.u.backedge = new_backedge_arr(get_irg_obstack(irg), arity);
res->attr.phi.loop = true;
verify_new_node(irg, res);
ir_node *optimized = optimize_node(res);
if (optimized == res)
keep_alive(optimized);
return optimized;
}
ir_node *new_r_Phi_loop(ir_node *block, int arity, ir_node *in[])
{
return new_rd_Phi_loop(NULL, block, arity, in);
}
ir_node *new_d_Phi_loop(dbg_info *db, int arity, ir_node *in[])
{
assert(irg_is_constrained(current_ir_graph, IR_GRAPH_CONSTRAINT_CONSTRUCTION));
return new_rd_Phi_loop(db, current_ir_graph->current_block, arity, in);
}
ir_node *new_Phi_loop(int arity, ir_node *in[])
{
assert(irg_is_constrained(current_ir_graph, IR_GRAPH_CONSTRAINT_CONSTRUCTION));
return new_rd_Phi_loop(NULL, current_ir_graph->current_block, arity, in);
}
ir_node *new_rd_immBlock(dbg_info *dbgi, ir_graph *irg)
{
assert(irg_is_constrained(irg, IR_GRAPH_CONSTRAINT_CONSTRUCTION));
......
......@@ -675,6 +675,12 @@ void dump_node_opcode(FILE *F, const ir_node *n)
fprintf(F, "[%s]", get_mode_name(get_Div_resmode(n)));
break;
case iro_Phi:
fprintf(F, "%s", name);
if (get_Phi_loop(n))
fprintf(F, "[loop]");
break;
case iro_Load: {
char const *const prefix = get_Load_unaligned(n) == align_non_aligned ? "ua" : "";
fprintf(F, "%s%s[%s]", prefix, name, get_mode_name(get_Load_mode(n)));
......
......@@ -38,8 +38,8 @@ void exchange(ir_node *old, ir_node *nw)
/* When replacing a PhiM node, it must not be hold by a keep-alive edge.
* => Keep-alive edges are not normal users and should not move along when
* exchanging. */
if (is_Phi(old) && get_irn_mode(old) == mode_M && !is_Bad(nw)
&& (!is_Phi(nw) || get_nodes_block(old) != get_nodes_block(nw))) {
if (is_Phi(old) && get_Phi_loop(old) && !(is_Phi(nw) && get_Phi_loop(nw))
&& !is_Bad(nw)) {
ir_node *end = get_irg_end(irg);
foreach_irn_in(end, i, kept) {
assert(kept != old);
......
......@@ -602,23 +602,20 @@ void remove_End_keepalive(ir_node *end, const ir_node *irn)
remove_irn_n(end, idx);
}
bool remove_keep_alive(const ir_node *irn)
void remove_keep_alive(const ir_node *irn)
{
ir_graph *irg = get_irn_irg(irn);
ir_node *end = get_irg_end(irg);
bool found = false;
for (int i = get_End_n_keepalives(end);;) {
if (i-- == 0)
return found;
return;
ir_node *old_ka = end->in[1 + END_KEEPALIVE_OFFSET + i];
/* find irn */
if (old_ka == irn) {
if (old_ka == irn)
set_irn_n(end, END_KEEPALIVE_OFFSET+i, new_r_Bad(irg, get_irn_mode(irn)));
found = true;
}
}
}
......
......@@ -540,9 +540,8 @@ void ir_register_getter_ops(void);
/** remove keep alive edge to node by rerouting the edge to a Bad node.
* (rerouting is preferable to removing when we are in a walker which also
* accesses the End node)
* @return true if an edge was removed */
bool remove_keep_alive(const ir_node *kept_node);
* accesses the End node) */
void remove_keep_alive(const ir_node *kept_node);
/**
* Create a node similar to @p old. Except for @p block and @p in all aspects
......
......@@ -1382,17 +1382,6 @@ static ir_node *equivalent_node_Bitcast(ir_node *n)
return n;
}
static bool is_kept_alive(const ir_node *node)
{
const ir_graph *const irg = get_irn_irg(node);
const ir_node *const end = get_irg_end(irg);
foreach_irn_in(end, i, kept) {
if (node == kept)
return true;
}
return false;
}
/**
* - fold Phi-nodes, iff they have only one predecessor except
* themselves.
......@@ -1443,13 +1432,13 @@ static ir_node *equivalent_node_Phi(ir_node *n)
* and must be part of the memory chain. If there are no other memory
* operations in a loop we still are not allowed to remove the PhiM unless
* we can prove that the loop terminates. */
if (get_irn_mode(n) == mode_M) {
if (get_Phi_loop(n)) {
assert(get_irn_mode(n) == mode_M);
/* We currently assume that PhiMs that have a keep-alive edge are in a
* potentially endless loops. PhiM without a keep alive edge is a sign
* that we are sure that the loop terminates. */
if (had_self_loop && is_kept_alive(n)) {
if (had_self_loop)
return n;
}
/* The PhiM will be removed, we can remove keep-alive edges to it as
* well. */
remove_keep_alive(n);
......@@ -5372,10 +5361,10 @@ static ir_node *transform_node_Phi(ir_node *phi)
return phi;
/* Move the Pin nodes "behind" the Phi. */
bool kept = remove_keep_alive(phi);
ir_node *new_phi = new_r_Phi(block, n, in, mode_M);
if (kept)
keep_alive(new_phi);
ir_node *new_phi = get_Phi_loop(phi) ? new_r_Phi_loop(block, n, in)
: new_r_Phi(block, n, in, mode_M);
if (get_Phi_loop(phi))
remove_keep_alive(phi);
return new_r_Pin(block, new_phi);
} else if (mode_is_reference(mode)) {
/* Move Confirms down through Phi nodes. */
......
......@@ -300,6 +300,7 @@ typedef struct phi_attr {
* the role of the obsolete Phi0 node, therefore the name. */
int pos;
} u;
unsigned loop:1; /**< Set to true if this is a loop PhiM node. */
} phi_attr;
/** Attributes for Cmp nodes. */
......
......@@ -426,14 +426,16 @@ static int verify_node_End(const ir_node *n)
if (!irg_is_constrained(irg, IR_GRAPH_CONSTRAINT_BACKEND)) {
foreach_irn_in(n, i, kept) {
/* endless loop handling may keep PhiM and Block nodes */
if (is_Block(kept) || (is_Phi(kept) && get_irn_mode(kept) == mode_M))
if (is_Block(kept))
continue;
if (is_Phi(kept) && get_Phi_loop(kept))
continue;
/* noreturn calls are currently kept with keep-alive edges */
if (is_Call(kept))
continue;
if (is_Bad(kept))
continue;
warn(n, "keep-alive edge only allowed on Block, PhiM and Call node, found %+F",
warn(n, "keep-alive edge only allowed on Block, PhiLoop and Call node, found %+F",
kept);
fine = false;
}
......@@ -877,6 +879,9 @@ static int verify_node_Phi(const ir_node *n)
for (int i = 0, n_preds = get_Phi_n_preds(n); i < n_preds; ++i) {
fine &= check_mode_same_input(n, i, NULL);
}
if (get_Phi_loop(n))
check_mode(n, mode_M);
return fine;
}
......
......@@ -69,12 +69,12 @@ static void block_remove_bads(ir_node *block)
/* shortcut if only 1 phi input is left */
if (new_max == 1) {
if (get_irn_mode(phi) == mode_M)
remove_keep_alive(phi);
ir_node *new_node = new_in[0];
/* can happen inside unreachable endless loops */
if (new_node == phi)
return;
if (get_Phi_loop(phi))
remove_keep_alive(phi);
exchange(phi, new_node);
} else {
set_irn_in(phi, new_max, new_in);
......
......@@ -111,7 +111,6 @@ struct node_t {
bool on_cprop:1; /**< Set, if this node is on the partition.cprop list. */
bool on_fallen:1; /**< Set, if this node is on the fallen list. */
bool is_follower:1; /**< Set, if this node is a follower. */
bool is_kept_alive:1;/**< node has a keep-alive edge. */
unsigned flagged:2; /**< 2 Bits, set if this node was visited by race 1 or 2. */
};
......@@ -2344,7 +2343,7 @@ static node_t *identity_Phi(node_t *node)
/* special rule: kept PhiM nodes have to create their own partition
* (as they represent the observable behaviour of a loop running endless) */
if (node->is_kept_alive) {
if (get_Phi_loop(phi)) {
assert(get_irn_mode(phi) == mode_M);
return node;
}
......@@ -2883,9 +2882,8 @@ static void apply_cf(ir_node *block, void *ctx)
ir_node *s = ins[0];
node_t *phi_node = get_irn_node(phi);
if (get_irn_mode(phi) == mode_M) {
if (get_Phi_loop(phi))
remove_keep_alive(phi);
}
node->node = s;
DB((dbg, LEVEL_1, "%+F is replaced by %+F because of cf change\n", phi, s));
......@@ -3287,13 +3285,6 @@ void combo(ir_graph *irg)
add_to_worklist(env.initial, &env);
irg_walk_graph(irg, create_initial_partitions, init_block_phis, &env);
/* mark all kept PhiM nodes, as we must not remove them */
ir_node *end = get_irg_end(irg);
for (int i = 0, n_keeps = get_End_n_keepalives(end); i < n_keeps; ++i) {
ir_node *kept = get_End_keepalive(end, i);
get_irn_node(kept)->is_kept_alive = true;
}
/* set the hook: from now, every node has a partition and a type */
DEBUG_ONLY(set_dump_node_vcgattr_hook(dump_partition_hook);)
......@@ -3325,6 +3316,7 @@ void combo(ir_graph *irg)
/* Kill keep-alives of dead blocks: this speeds up apply_result()
* and fixes assertion because dead cf to dead blocks is NOT removed by
* apply_cf(). */
ir_node *end = get_irg_end(irg);
apply_end(end, &env);
/* need a freshly computed dominance tree (after killing unreachable code
......
......@@ -193,7 +193,7 @@ static void split_block(ir_node *block, int i, int j)
for (k = 0; k != j; ++k) pred_ins[k] = get_irn_n(phi, k);
for (; k != new_pred_arity; ++k) pred_ins[k] = get_irn_n(phi, k + 1);
if (k == 1) {
if (get_irn_mode(phi) == mode_M)
if (get_Phi_loop(phi))
remove_keep_alive(phi);
exchange(phi, pred_ins[0]);
} else {
......@@ -223,7 +223,7 @@ static void prepare_path(ir_node *block, int i, const ir_node *dependency)
next = get_Phi_next(phi);
ir_node *operand = get_irn_n(phi, 0);
if (get_irn_mode(phi) == mode_M)
if (get_Phi_loop(phi))
remove_keep_alive(phi);
exchange(phi, operand);
}
......@@ -335,7 +335,7 @@ restart:;
if (val_i == val_j) {
mux = val_i;
DB((dbg, LEVEL_2, "Generating no Mux, because both values are equal\n"));
if (get_irn_mode(phi) == mode_M)
if (get_Phi_loop(phi))
remove_keep_alive(phi);
} else {
ir_node *t, *f;
......
......@@ -113,8 +113,10 @@ static ir_node *search_def_and_create_phis(ir_node *block, ir_mode *mode,
set_irn_n(phi, i, pred_val);
}
/* we might have created a potential endless loop, so keep the Phi */
if (get_irn_mode(phi) == mode_M)
if (get_irn_mode(phi) == mode_M) {
keep_alive(phi);
set_Phi_loop(phi, true);
}
return phi;
}
......
......@@ -1266,8 +1266,9 @@ static changes_t optimize_phi(ir_node *phi, walk_env_t *wenv)
idx[i] = info->exc_idx;
}
/* second step: create a new memory Phi */
ir_node *phiM = new_r_Phi(phi_block, n, inM, mode_M);
/* second step: remove keep edge from old Phi and create a new memory Phi */
ir_node *phiM = get_Phi_loop(phi) ? new_r_Phi_loop(phi_block, n, inM)
: new_r_Phi(phi_block, n, inM, mode_M);
/* third step: create a new data Phi */
ir_node *phiD = new_r_Phi(phi_block, n, inD, mode);
......@@ -1310,9 +1311,8 @@ static changes_t optimize_phi(ir_node *phi, walk_env_t *wenv)
}
/* sixth step: replace old Phi */
bool kept = remove_keep_alive(phi);
if (kept && is_Phi(phiM))
keep_alive(phiM);
if (get_Phi_loop(phi))
remove_keep_alive(phi);
exchange(phi, projM);
return res | DF_CHANGED;
......
......@@ -650,6 +650,10 @@ class Phi:
arity = "variable"
input_name = "pred"
flags = []
attrs = [
Attribute("loop", type="int", init="0",
comment="wether Phi represents the observable effect of a (possibly) nonterminating loop"),
]
attr_struct = "phi_attr"
init = '''
res->attr.phi.u.backedge = new_backedge_arr(get_irg_obstack(irg), arity);'''
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment