Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Zwinkau
libfirm
Commits
a95c36ee
Commit
a95c36ee
authored
Jul 29, 2014
by
Matthias Braun
Browse files
redo endless loop/keep handling
For details see endless loops section on the homepage.
parent
02ae8c66
Changes
12
Show whitespace changes
Inline
Side-by-side
ir/ir/ircons.c
View file @
a95c36ee
...
...
@@ -104,9 +104,12 @@ static void try_remove_unnecessary_phi(ir_node *phi)
/* See if all inputs are either pointing to a single value or
* are self references. */
bool
have_self_loop
=
false
;
foreach_irn_in
(
phi
,
i
,
in
)
{
if
(
in
==
phi
)
if
(
in
==
phi
)
{
have_self_loop
=
true
;
continue
;
}
if
(
in
==
phi_value
)
continue
;
/** found a different value from the one we already found, can't remove
...
...
@@ -118,6 +121,11 @@ static void try_remove_unnecessary_phi(ir_node *phi)
if
(
phi_value
==
NULL
)
return
;
/* Do not remove PhiM with self-loops as potentially endless loops are
* observable, see comment in equivalent_node_Phi() to learn more. */
if
(
have_self_loop
&&
get_irn_mode
(
phi
)
==
mode_M
)
return
;
/* if we're here then all phi inputs have been either phi_value
* or self-references, we can replace the phi by phi_value. */
exchange
(
phi
,
phi_value
);
...
...
@@ -164,6 +172,12 @@ static ir_node *set_phi_arguments(ir_node *phi, int pos)
verify_new_node
(
irg
,
phi
);
try_remove_unnecessary_phi
(
phi
);
/* 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
))
keep_alive
(
phi
);
return
phi
;
}
...
...
ir/ir/irnode.c
View file @
a95c36ee
...
...
@@ -602,6 +602,23 @@ void remove_End_keepalive(ir_node *end, const ir_node *irn)
remove_irn_n
(
end
,
idx
);
}
void
remove_keep_alive
(
const
ir_node
*
irn
)
{
ir_graph
*
irg
=
get_irn_irg
(
irn
);
ir_node
*
end
=
get_irg_end
(
irg
);
for
(
int
i
=
get_End_n_keepalives
(
end
);;)
{
if
(
i
--
==
0
)
return
;
ir_node
*
old_ka
=
end
->
in
[
1
+
END_KEEPALIVE_OFFSET
+
i
];
/* find irn */
if
(
old_ka
==
irn
)
set_irn_n
(
end
,
END_KEEPALIVE_OFFSET
+
i
,
new_r_Bad
(
irg
,
get_irn_mode
(
irn
)));
}
}
void
remove_End_Bads_and_doublets
(
ir_node
*
end
)
{
pset_new_t
keeps
;
...
...
@@ -1128,20 +1145,3 @@ ir_switch_table *ir_switch_table_duplicate(ir_graph *irg,
}
return
res
;
}
bool
only_used_by_keepalive
(
const
ir_node
*
node
)
{
bool
kept
=
false
;
foreach_out_edge
(
node
,
edge
)
{
ir_node
*
succ
=
get_edge_src_irn
(
edge
);
if
(
is_End
(
succ
)
||
(
is_Proj
(
succ
)
&&
only_used_by_keepalive
(
succ
)))
{
kept
=
true
;
continue
;
}
/* found a real user */
return
false
;
}
return
kept
;
}
ir/ir/irnode_t.h
View file @
a95c36ee
...
...
@@ -538,12 +538,10 @@ static inline const ir_switch_table_entry *ir_switch_table_get_entry_const(
void
ir_register_getter_ops
(
void
);
/**
* because firm keepalive edges are a broken concept, we have to make sure that
* nodes which are only held by a keepalive edges are never moved again.
* This function returns true in this case.
*/
bool
only_used_by_keepalive
(
const
ir_node
*
node
);
/** 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) */
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
...
...
ir/ir/iropt.c
View file @
a95c36ee
...
...
@@ -1382,26 +1382,34 @@ 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.
*/
static
ir_node
*
equivalent_node_Phi
(
ir_node
*
n
)
{
ir_node
*
oldn
=
n
;
ir_node
*
first_val
=
NULL
;
/* to shutup gcc */
if
(
!
get_opt_optimize
()
&&
!
irg_is_constrained
(
get_irn_irg
(
n
),
IR_GRAPH_CONSTRAINT_CONSTRUCTION
))
return
n
;
int
n_preds
=
get_Phi_n_preds
(
n
);
/* Phi of dead Region without predecessors. */
int
n_preds
=
get_Phi_n_preds
(
n
);
if
(
n_preds
==
0
)
return
n
;
/* Find first non-self-referencing input */
ir_node
*
first_val
=
NULL
;
int
i
;
for
(
i
=
0
;
i
<
n_preds
;
++
i
)
{
first_val
=
get_Phi_pred
(
n
,
i
);
...
...
@@ -1413,20 +1421,40 @@ static ir_node *equivalent_node_Phi(ir_node *n)
}
/* search for rest of inputs, determine if any of these
are non-self-referencing */
while
(
++
i
<
n_preds
)
{
* are non-self-referencing */
bool
had_self_loop
=
false
;
for
(
++
i
;
i
<
n_preds
;
++
i
)
{
const
ir_node
*
scnd_val
=
get_Phi_pred
(
n
,
i
);
if
(
scnd_val
!=
n
&&
scnd_val
!=
first_val
)
{
break
;
if
(
scnd_val
==
n
)
{
had_self_loop
=
true
;
continue
;
}
/* more than 1 unique value found? abort */
if
(
scnd_val
!=
first_val
)
return
n
;
}
if
(
i
>=
n_preds
&&
!
is_Dummy
(
first_val
))
{
/* Fold, if no multiple distinct non-self-referencing inputs */
n
=
first_val
;
DBG_OPT_PHI
(
oldn
,
n
);
}
/* if we are here then all inputs are either self-loops or first_val */
if
(
is_Dummy
(
first_val
))
return
n
;
/* Subtle special case: (Potentially) endless loops are observable behaviour
* 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
)
{
/* 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
))
{
return
n
;
}
/* The PhiM will be removed, we can remove keep-alive edges to it as
* well. */
remove_keep_alive
(
n
);
}
DBG_OPT_PHI
(
n
,
first_val
);
return
first_val
;
}
/**
...
...
@@ -3775,8 +3803,6 @@ static ir_node *transform_node_Cond(ir_node *n)
};
turn_into_tuple
(
n
,
ARRAY_SIZE
(
in
),
in
);
/* Since we may produce an endless loop, we have to keep the block. */
keep_alive
(
blk
);
clear_irg_properties
(
irg
,
IR_GRAPH_PROPERTY_NO_UNREACHABLE_CODE
);
}
return
n
;
...
...
@@ -7409,10 +7435,6 @@ int identities_cmp(const void *elt, const void *key)
if
(
!
block_dominates
(
block_a
,
block_b
)
&&
!
block_dominates
(
block_b
,
block_a
))
return
1
;
/* respect the workaround rule: do not move nodes which are only
* held by keepalive edges */
if
(
only_used_by_keepalive
(
a
)
||
only_used_by_keepalive
(
b
))
return
1
;
}
}
...
...
ir/ir/irverify.c
View file @
a95c36ee
...
...
@@ -417,6 +417,30 @@ static int verify_node_Start(const ir_node *n)
return
check_mode
(
n
,
mode_T
);
}
static
int
verify_node_End
(
const
ir_node
*
n
)
{
bool
fine
=
check_mode
(
n
,
mode_X
);
/* check that only blocks, PhiM and (noreturn) Call nodes are connected
* by keep-alive edges */
ir_graph
*
irg
=
get_irn_irg
(
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
))
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"
,
kept
);
fine
=
false
;
}
}
return
fine
;
}
static
int
verify_node_Jmp
(
const
ir_node
*
n
)
{
return
check_mode
(
n
,
mode_X
);
...
...
@@ -1297,6 +1321,7 @@ void ir_register_verify_node_ops(void)
register_verify_node_func
(
op_CopyB
,
verify_node_CopyB
);
register_verify_node_func
(
op_Deleted
,
verify_node_Deleted
);
register_verify_node_func
(
op_Div
,
verify_node_Div
);
register_verify_node_func
(
op_End
,
verify_node_End
);
register_verify_node_func
(
op_Eor
,
verify_node_Eor
);
register_verify_node_func
(
op_Free
,
verify_node_Free
);
register_verify_node_func
(
op_IJmp
,
verify_node_IJmp
);
...
...
ir/ir/rm_bads.c
View file @
a95c36ee
...
...
@@ -69,6 +69,8 @@ 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
)
...
...
@@ -114,6 +116,8 @@ void remove_bads(ir_graph *irg)
}
DEL_ARR_F
(
blocks_to_process
);
remove_End_Bads_and_doublets
(
get_irg_end
(
irg
));
if
(
n_to_process
>
0
)
{
confirm_irg_properties
(
irg
,
IR_GRAPH_PROPERTY_NO_UNREACHABLE_CODE
...
...
ir/opt/code_placement.c
View file @
a95c36ee
...
...
@@ -58,7 +58,7 @@ static void place_floats_early(ir_node *n, waitq *worklist)
* This works because in firm each cycle contains a Phi or Block node
* (which are pinned)
*/
if
(
get_irn_pinned
(
n
)
!=
op_pin_state_floats
||
only_used_by_keepalive
(
n
)
)
{
if
(
get_irn_pinned
(
n
)
!=
op_pin_state_floats
)
{
/* we cannot move pinned nodes */
foreach_irn_in
(
n
,
i
,
pred
)
{
pdeq_putr
(
worklist
,
pred
);
...
...
@@ -255,12 +255,8 @@ static ir_node *get_deepest_common_dom_ancestor(ir_node *node, ir_node *dca)
dca
=
consumer_dom_dca
(
dca
,
succ
,
node
);
}
}
/* respect the keepalive rule: if our only user is a keepalive, then we must
* not move the node any further */
if
(
dca
==
NULL
)
{
assert
(
only_used_by_keepalive
(
node
));
if
(
dca
==
NULL
)
return
get_nodes_block
(
node
);
}
foreach_out_edge_kind
(
node
,
edge
,
EDGE_KIND_DEP
)
{
ir_node
*
succ
=
get_edge_src_irn
(
edge
);
...
...
ir/opt/combo.c
View file @
a95c36ee
...
...
@@ -111,6 +111,7 @@ 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. */
};
...
...
@@ -2341,6 +2342,13 @@ static node_t *identity_Phi(node_t *node)
ir_node
*
block
=
get_nodes_block
(
phi
);
node_t
*
n_part
=
NULL
;
/* 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
)
{
assert
(
get_irn_mode
(
phi
)
==
mode_M
);
return
node
;
}
for
(
int
i
=
get_Phi_n_preds
(
phi
);
i
--
>
0
;
)
{
node_t
*
pred_X
=
get_irn_node
(
get_Block_cfgpred
(
block
,
i
));
if
(
pred_X
->
type
.
tv
==
tarval_bottom
)
...
...
@@ -2789,15 +2797,6 @@ static void apply_cf(ir_node *block, void *ctx)
if
(
pred_bl
->
flagged
==
0
)
{
pred_bl
->
flagged
=
3
;
if
(
is_reachable
(
pred_bl
))
{
/*
* We will remove an edge from block to its pred.
* This might leave the pred block as an endless loop
*/
if
(
!
is_backedge
(
block
,
i
))
keep_alive
(
pred_bl
->
node
);
}
}
}
}
...
...
@@ -2844,15 +2843,6 @@ static void apply_cf(ir_node *block, void *ctx)
if
(
!
is_Bad
(
pred_bl
->
node
)
&&
pred_bl
->
flagged
==
0
)
{
pred_bl
->
flagged
=
3
;
if
(
is_reachable
(
pred_bl
))
{
/*
* We will remove an edge from block to its pred.
* This might leave the pred block as an endless loop
*/
if
(
!
is_backedge
(
block
,
i
))
keep_alive
(
pred_bl
->
node
);
}
}
}
}
...
...
@@ -2862,6 +2852,7 @@ static void apply_cf(ir_node *block, void *ctx)
return
;
/* fix Phi's */
ir_graph
*
irg
=
get_Block_irg
(
block
);
ir_node
**
ins
=
ALLOCAN
(
ir_node
*
,
n
);
for
(
ir_node
*
next
,
*
phi
=
get_Block_phis
(
block
);
phi
!=
NULL
;
phi
=
next
)
{
node_t
*
node
=
get_irn_node
(
phi
);
...
...
@@ -2870,7 +2861,6 @@ static void apply_cf(ir_node *block, void *ctx)
if
(
is_tarval
(
node
->
type
.
tv
)
&&
tarval_is_constant
(
node
->
type
.
tv
))
{
/* this Phi is replaced by a constant */
ir_tarval
*
tv
=
node
->
type
.
tv
;
ir_graph
*
irg
=
get_Block_irg
(
block
);
ir_node
*
c
=
new_r_Const
(
irg
,
tv
);
set_irn_node
(
c
,
node
);
...
...
@@ -2893,6 +2883,10 @@ 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
)
{
remove_keep_alive
(
phi
);
}
node
->
node
=
s
;
DB
((
dbg
,
LEVEL_1
,
"%+F is replaced by %+F because of cf change
\n
"
,
phi
,
s
));
DBG_OPT_COMBO
(
phi
,
s
,
FS_OPT_COMBO_FOLLOWER
);
...
...
@@ -3293,6 +3287,13 @@ 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
);)
...
...
@@ -3324,7 +3325,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(). */
apply_end
(
get_irg_end
(
irg
)
,
&
env
);
apply_end
(
end
,
&
env
);
/* need a freshly computed dominance tree (after killing unreachable code
* it is not valid anymore) */
...
...
ir/opt/ifconv.c
View file @
a95c36ee
...
...
@@ -193,6 +193,8 @@ 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
)
remove_keep_alive
(
phi
);
exchange
(
phi
,
pred_ins
[
0
]);
}
else
{
set_irn_in
(
phi
,
k
,
pred_ins
);
...
...
@@ -221,6 +223,8 @@ 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
)
remove_keep_alive
(
phi
);
exchange
(
phi
,
operand
);
}
...
...
@@ -331,6 +335,8 @@ 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
)
remove_keep_alive
(
phi
);
}
else
{
ir_node
*
t
,
*
f
;
...
...
ir/opt/jumpthreading.c
View file @
a95c36ee
...
...
@@ -311,7 +311,7 @@ static void copy_and_fix(const jumpthreading_env_t *env, ir_node *block,
construct_ssa
(
block
,
node
,
copy_block
,
copy_node
);
}
/* make sure
new
nodes are kept alive if old nodes were */
/* make sure
copied PhiM
nodes are kept alive if old nodes were */
ir_graph
*
irg
=
get_irn_irg
(
block
);
ir_node
*
end
=
get_irg_end
(
irg
);
for
(
int
i
=
0
,
arity
=
get_End_n_keepalives
(
end
);
i
<
arity
;
++
i
)
{
...
...
@@ -319,8 +319,11 @@ static void copy_and_fix(const jumpthreading_env_t *env, ir_node *block,
if
(
get_irn_visited
(
keep
)
<
env
->
visited_nr
||
is_Block
(
keep
))
continue
;
ir_node
*
copy
=
get_irn_link
(
keep
);
if
(
is_Phi
(
keep
)
&&
is_Phi
(
copy
))
{
assert
(
get_irn_mode
(
keep
)
==
mode_M
);
add_End_keepalive
(
end
,
copy
);
}
}
}
/**
...
...
ir/opt/ldstopt.c
View file @
a95c36ee
...
...
@@ -1310,6 +1310,7 @@ static changes_t optimize_phi(ir_node *phi, walk_env_t *wenv)
}
/* sixth step: replace old Phi */
remove_keep_alive
(
phi
);
exchange
(
phi
,
projM
);
return
res
|
DF_CHANGED
;
...
...
ir/opt/opt_osr.c
View file @
a95c36ee
...
...
@@ -737,7 +737,7 @@ static void classify_iv(scc *pscc, iv_env *env)
}
/* found an induction variable */
DB
((
dbg
,
LEVEL_2
,
" Found an induction variable:
\n
"
));
if
(
only_phi
&&
num_outside
==
1
)
{
if
(
only_phi
&&
num_outside
==
1
&&
get_irn_mode
(
pscc
->
head
)
!=
mode_M
)
{
/* a phi cycle with only one real predecessor can be collapsed */
DB
((
dbg
,
LEVEL_2
,
" Found an USELESS Phi cycle:
\n
"
));
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment