Commit 255a9cc7 authored by Matthias Braun's avatar Matthias Braun
Browse files

cleanup/fix optimize_graph_df flag handling

parent 6c1b0479
......@@ -97,17 +97,6 @@ FIRM_API int get_opt_cse(void);
*/
FIRM_API void set_opt_global_cse(int value);
/** Enables/Disables unreachable code elimination.
*
* If set, evaluate conditions of conditional branch and replace the
* branch with a Jmp/Bad Tuple.
*
* If opt_unreachable_code == 1 replace nodes (except Block,
* Phi and Tuple) with a Bad predecessor by the Bad node.
* Default: opt_unreachable_code == 1.
*/
FIRM_API void set_opt_unreachable_code(int value);
/** Enable/Disable optimization of dynamic method dispatch.
*
* This flag enables/disables the optimization of dynamic method dispatch.
......
......@@ -475,35 +475,69 @@ FIRM_API ir_resources_t ir_resources_reserved(const ir_graph *irg);
#endif
/**
* Graph State
* graph state. This is used for 2 things:
* - stating properties about a graph
* - disallow certain transformations for the graph (typically highlevel
* constructs are disallowed after lowering them)
*/
typedef enum {
IR_GRAPH_STATE_ARCH_DEP = 1U << 0, /**< should not construct more nodes which irarch potentially breaks down */
IR_GRAPH_STATE_MODEB_LOWERED = 1U << 1, /**< the only node which may produce mode_b is Cmp */
/**
* Should not construct more nodes which irarch potentially breaks down
*/
IR_GRAPH_STATE_ARCH_DEP = 1U << 0,
/**
* mode_b nodes have been lowered so you should not create any new nodes
* with mode_b (except for Cmp)
*/
IR_GRAPH_STATE_MODEB_LOWERED = 1U << 1,
/**
* There are normalisations where there is no "best" representative.
* In this case we first normalise into 1 direction (!NORMALISATION2) and
* later in the other (NORMALISATION2).
*/
IR_GRAPH_STATE_NORMALISATION2 = 1U << 2,
IR_GRAPH_STATE_NORMALISATION2 = 1U << 2,
/**
* Define the semantic of Load(Sel(x)), if x has a bit offset (Bitfields!).
* Normally, the frontend is responsible for bitfield masking operations.
* Set IMPLICIT_BITFIELD_MASKING, if the lowering phase must insert masking operations.
* Set IMPLICIT_BITFIELD_MASKING, if the lowering phase must insert masking
* operations.
*/
IR_GRAPH_STATE_IMPLICIT_BITFIELD_MASKING = 1U << 3,
/**
* Allow localopts to remove edges to unreachable code.
* Warning: It is only safe to enable this when you are sure that you
* apply all localopts to the fixpunkt. (=in optimize_graph_df)
*/
IR_GRAPH_STATE_OPTIMIZE_UNREACHABLE_CODE = 1U << 4,
/** graph contains no critical edges */
IR_GRAPH_STATE_NO_CRITICAL_EDGES = 1U << 5,
/** graph contains no Bads */
IR_GRAPH_STATE_NO_BAD_BLOCKS = 1U << 6,
/**
* there exists no (obviously) unreachable code in the graph.
* Unreachable in this context is code that you can't reach by following
* execution flow from the start block.
*/
IR_GRAPH_STATE_NO_UNREACHABLE_CODE = 1U << 7,
/** graph contains at most one return */
IR_GRAPH_STATE_ONE_RETURN = 1U << 8,
/** dominance information about the graph is valid */
IR_GRAPH_STATE_CONSISTENT_DOMINANCE = 1U << 9,
/** postdominance information about the graph is valid */
IR_GRAPH_STATE_CONSISTENT_POSTDOMINANCE = 1U << 10,
/**
* out edges (=iredges) are enable and there is no dead code that can be
* reached by following them
*/
IR_GRAPH_STATE_IMPLICIT_BITFIELD_MASKING = 1U << 3,
IR_GRAPH_STATE_NO_CRITICAL_EDGES = 1U << 4, /**< irg contains no critical edges */
IR_GRAPH_STATE_NO_BAD_BLOCKS = 1U << 5, /**< irg contains no Bads */
IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS = 1U << 6, /**< irg contains no unreachable code */
IR_GRAPH_STATE_ONE_RETURN = 1U << 7, /**< irg contains at most one return */
IR_GRAPH_STATE_CONSISTENT_DOMINANCE = 1U << 8, /**< dominance information is consistent */
IR_GRAPH_STATE_CONSISTENT_POSTDOMINANCE = 1U << 9, /**< post-dominance information is consistent */
IR_GRAPH_STATE_CONSISTENT_OUT_EDGES = 1U << 10, /**< out edges are activated and up to date */
IR_GRAPH_STATE_CONSISTENT_OUTS = 1U << 11, /**< outs are computed and up to date */
IR_GRAPH_STATE_CONSISTENT_LOOPINFO = 1U << 12, /**< loopinfo is computed and up to date */
IR_GRAPH_STATE_CONSISTENT_ENTITY_USAGE = 1U << 13, /**< entity usage is computed and up to date */
IR_GRAPH_STATE_VALID_EXTENDED_BLOCKS = 1U << 14, /**< extend block info is computed and up to date */
IR_GRAPH_STATE_CONSISTENT_OUT_EDGES = 1U << 11,
/** outs (irouts) are computed and up to date */
IR_GRAPH_STATE_CONSISTENT_OUTS = 1U << 12,
/** loopinfo is computed and up to date */
IR_GRAPH_STATE_CONSISTENT_LOOPINFO = 1U << 13,
/** entity usage information is computed and up to date */
IR_GRAPH_STATE_CONSISTENT_ENTITY_USAGE = 1U << 14,
/** extended basic blocks have been formed and are up to date */
IR_GRAPH_STATE_VALID_EXTENDED_BLOCKS = 1U << 15,
IR_GRAPH_STATE_BROKEN_FOR_VERIFIER = 1U << 15, /**< verifier would unecessarily complain about the graph */
} ir_graph_state_t;
ENUM_BITSET(ir_graph_state_t)
......
......@@ -46,35 +46,32 @@ I_FLAG(global_cse , 2, OFF)
/** Evaluate operations. */
I_FLAG(constant_folding , 3, ON)
/** Bad node propagation. */
I_FLAG(unreachable_code , 4, ON)
/** Algebraic simplifications. */
I_FLAG(algebraic_simplification , 5, ON)
I_FLAG(algebraic_simplification , 4, ON)
/** Use Global Null Pointer Test elimination. */
I_FLAG(global_null_ptr_elimination , 6, ON)
I_FLAG(global_null_ptr_elimination , 5, ON)
/** Remove dynamic method dispatch. */
E_FLAG(dyn_meth_dispatch , 7, ON)
E_FLAG(dyn_meth_dispatch , 6, ON)
/** Optimize cast nodes. */
E_FLAG(suppress_downcast_optimization , 8, OFF)
E_FLAG(suppress_downcast_optimization , 7, OFF)
/** Load and Store have only Null exceptions. */
I_FLAG(ldst_only_null_ptr_exceptions , 9, ON)
I_FLAG(ldst_only_null_ptr_exceptions , 8, ON)
/** Sel-based Null-pointer check elimination. */
I_FLAG(sel_based_null_check_elim , 10, OFF)
I_FLAG(sel_based_null_check_elim , 9, OFF)
/** Automatically create Sync node during construction. */
I_FLAG(auto_create_sync , 11, OFF)
I_FLAG(auto_create_sync , 10, OFF)
/** Enable Alias-analysis. */
I_FLAG(alias_analysis , 12, ON)
I_FLAG(alias_analysis , 11, ON)
/** Closed world assumption. */
I_FLAG(closed_world , 13, OFF)
I_FLAG(closed_world , 12, OFF)
/* -------------------- RUNNING flags ------------------- */
......
......@@ -182,44 +182,31 @@ static void opt_walker(ir_node *n, void *env)
}
}
/* Applies local optimizations to all nodes in the graph until fixpoint. */
int optimize_graph_df(ir_graph *irg)
{
pdeq *waitq = new_pdeq();
ir_graph *rem = current_ir_graph;
ir_node *end;
int state, changed;
current_ir_graph = irg;
state = edges_assure(irg);
/* Clean the value_table in irg for the CSE. */
new_identities(irg);
if (get_opt_global_cse()) {
if (get_opt_global_cse())
set_irg_pinned(irg, op_pin_state_floats);
}
/* The following enables unreachable code elimination (=Blocks may be
* Bad). */
clear_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS);
/* enable unreachable code elimination */
assert(!is_irg_state(irg, IR_GRAPH_STATE_OPTIMIZE_UNREACHABLE_CODE));
set_irg_state(irg, IR_GRAPH_STATE_OPTIMIZE_UNREACHABLE_CODE);
/* invalidate info */
clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_DOMINANCE);
ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
/* Calculate dominance so we can kill unreachable code */
new_identities(irg);
edges_assure(irg);
assure_doms(irg);
/* walk over the graph, but don't touch keep-alives */
ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
irg_walk_graph(irg, NULL, opt_walker, waitq);
/* any optimized nodes are stored in the wait queue,
* so if it's not empty, the graph has been changed */
changed = !pdeq_empty(waitq);
while (!pdeq_empty(waitq)) {
/* finish the wait queue */
while (! pdeq_empty(waitq)) {
......@@ -231,32 +218,33 @@ int optimize_graph_df(ir_graph *irg)
compute_doms(irg);
irg_block_walk_graph(irg, NULL, find_unreachable_blocks, waitq);
}
clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_DOMINANCE);
del_pdeq(waitq);
ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
if (! state)
edges_deactivate(irg);
/* disable unreachable code elimination */
clear_irg_state(irg, IR_GRAPH_STATE_OPTIMIZE_UNREACHABLE_CODE);
set_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_CODE);
if (remove_bads(irg)) {
edges_deactivate(irg);
}
/* invalidate infos */
clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_DOMINANCE);
clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_LOOPINFO);
clear_irg_state(irg, IR_GRAPH_STATE_VALID_EXTENDED_BLOCKS);
edges_deactivate(irg);
/* Finally kill BAD and doublets from the keep alives.
Doing this AFTER edges where deactivated saves cycles */
* Doing this AFTER edges where deactivated saves cycles */
end = get_irg_end(irg);
remove_End_Bads_and_doublets(end);
set_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS);
current_ir_graph = rem;
return changed;
/* Note we do not have a reliable way to detect changes, since some
* localopt rules change the inputs of a node and do not return a new
* node, so we conservatively say true here */
return true;
}
/* Creates an ir_graph pass for optimize_graph_df. */
ir_graph_pass_t *optimize_graph_df_pass(const char *name)
{
return def_graph_pass_ret(name ? name : "optimize_graph_df", optimize_graph_df);
} /* optimize_graph_df_pass */
}
......@@ -2790,8 +2790,7 @@ static ir_node *transform_node_Cond(ir_node *n)
return n;
if ((ta != tarval_bad) &&
(get_irn_mode(a) == mode_b) &&
(get_opt_unreachable_code())) {
(get_irn_mode(a) == mode_b)) {
/* It's a boolean Cond, branching on a boolean constant.
Replace it by a tuple (Bad, Jmp) or (Jmp, Bad) */
ir_node *blk = get_nodes_block(n);
......@@ -3731,9 +3730,6 @@ static ir_node *transform_node_Proj_Cond(ir_node *proj)
ir_node *n = get_Proj_pred(proj);
ir_node *b = get_Cond_selector(n);
if (!get_opt_unreachable_code())
return n;
if (mode_is_int(get_irn_mode(b))) {
ir_tarval *tb = value_of(b);
......@@ -4595,10 +4591,21 @@ static ir_node *transform_node_Proj(ir_node *proj)
return proj;
} /* transform_node_Proj */
/**
* Test wether a block is unreachable
* Note: That this only returns true when
* IR_GRAPH_STATE_OPTIMIZE_UNREACHABLE_CODE is set.
* This is important, as you easily end up producing invalid constructs in the
* unreachable code when optimizing away edges into the unreachable code.
* So only set this flag when you iterate localopts to the fixpoint.
* When you reach the fixpoint then all unreachable code is dead
* (= can't be reached by firm edges) and you won't see the invalid constructs
* anymore.
*/
static bool is_block_unreachable(const ir_node *block)
{
const ir_graph *irg = get_irn_irg(block);
if (is_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS))
if (!is_irg_state(irg, IR_GRAPH_STATE_OPTIMIZE_UNREACHABLE_CODE))
return false;
return get_Block_dom_depth(block) < 0;
}
......@@ -4610,7 +4617,7 @@ static ir_node *transform_node_Block(ir_node *block)
ir_node *bad = NULL;
int i;
if (is_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS))
if (!is_irg_state(irg, IR_GRAPH_STATE_OPTIMIZE_UNREACHABLE_CODE))
return block;
for (i = 0; i < arity; ++i) {
......
......@@ -52,25 +52,20 @@ static int count_non_bads(ir_node *node)
* Block-walker, remove Bad block predecessors and shorten Phis.
* Phi links must be uptodate.
*/
static void block_remove_bads(ir_node *block, void *env)
static void block_remove_bads(ir_node *block)
{
int *changed = (int *)env;
int i, j;
ir_node **new_in, *new_block, *phi;
ir_node *next;
ir_graph *irg = get_irn_irg(block);
const int max = get_irn_arity(block);
const int new_max = count_non_bads(block);
ir_node **new_in = ALLOCAN(ir_node*, new_max);
int i;
int j;
ir_node *new_block;
ir_node *phi;
ir_node *next;
ir_entity *block_entity;
const int max = get_irn_arity(block);
const int new_max = count_non_bads(block);
assert(max >= new_max);
if (is_Bad(block) || max == new_max)
return;
new_in = ALLOCAN(ir_node*, new_max);
*changed = 1;
assert(get_Block_dom_depth(block) >= 0);
/* 1. Create a new block without Bad inputs */
for (i = j = 0; i < max; ++i) {
ir_node *block_pred = get_irn_n(block, i);
......@@ -82,14 +77,14 @@ static void block_remove_bads(ir_node *block, void *env)
/* If the end block is unreachable, it might have zero predecessors. */
if (new_max == 0) {
ir_node *end_block = get_irg_end_block(get_irn_irg(block));
ir_node *end_block = get_irg_end_block(irg);
if (block == end_block) {
set_irn_in(block, new_max, new_in);
return;
}
}
new_block = new_r_Block(get_irn_irg(block), new_max, new_in);
new_block = new_r_Block(irg, new_max, new_in);
block_entity = get_Block_entity(block);
if (block_entity)
set_Block_entity(new_block, block_entity);
......@@ -118,6 +113,18 @@ static void block_remove_bads(ir_node *block, void *env)
exchange(block, new_block);
}
static void collect(ir_node *node, void *env)
{
firm_collect_block_phis(node, NULL);
if (is_Block(node)) {
ir_node ***blocks_to_process = (ir_node***)env;
int arity = get_irn_arity(node);
int non_bads = count_non_bads(node);
if (arity != non_bads)
ARR_APP1(ir_node*, *blocks_to_process, node);
}
}
/* Remove Bad nodes from Phi and Block inputs.
*
* This does NOT remove unreachable code.
......@@ -126,18 +133,26 @@ static void block_remove_bads(ir_node *block, void *env)
*/
int remove_bads(ir_graph *irg)
{
int changed = 0;
size_t i;
size_t n_to_process;
ir_node **blocks_to_process = NEW_ARR_F(ir_node*, 0);
/* build phi list per block */
irg_walk_graph(irg, firm_clear_block_phis, firm_collect_block_phis, NULL);
irg_walk_graph(irg, firm_clear_block_phis, collect, &blocks_to_process);
/* actually remove Bads */
irg_block_walk_graph(irg, NULL, block_remove_bads, (void *)&changed);
n_to_process = ARR_LEN(blocks_to_process);
for (i = 0; i < n_to_process; ++i) {
ir_node *block = blocks_to_process[i];
block_remove_bads(block);
}
DEL_ARR_F(blocks_to_process);
if (changed) {
if (n_to_process > 0) {
edges_deactivate(irg);
clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_OUTS);
clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_DOMINANCE);
return 1;
}
return changed;
return 0;
}
......@@ -68,5 +68,5 @@ void remove_unreachable_blocks(ir_graph *irg)
clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_OUTS);
clear_irg_state(irg, IR_GRAPH_STATE_NO_BAD_BLOCKS);
}
set_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS);
set_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_CODE);
}
......@@ -972,7 +972,7 @@ static ir_graph_state_t do_cfopt(ir_graph *irg)
optdesc_t opt_cf = {
"control-flow",
IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS,
IR_GRAPH_STATE_NO_UNREACHABLE_CODE,
do_cfopt,
};
......
......@@ -868,7 +868,7 @@ static ir_graph_state_t do_fixpoint_vrp(ir_graph* const irg)
optdesc_t opt_fpvrp = {
"fp-vrp",
IR_GRAPH_STATE_NO_BAD_BLOCKS | IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS | IR_GRAPH_STATE_CONSISTENT_DOMINANCE | IR_GRAPH_STATE_CONSISTENT_OUT_EDGES,
IR_GRAPH_STATE_NO_BAD_BLOCKS | IR_GRAPH_STATE_NO_UNREACHABLE_CODE | IR_GRAPH_STATE_CONSISTENT_DOMINANCE | IR_GRAPH_STATE_CONSISTENT_OUT_EDGES,
do_fixpoint_vrp,
};
......
......@@ -499,7 +499,7 @@ static ir_graph_state_t do_ifconv(ir_graph *irg)
optdesc_t opt_ifconv = {
"if-conversion",
IR_GRAPH_STATE_NO_CRITICAL_EDGES | IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS | IR_GRAPH_STATE_NO_BAD_BLOCKS | IR_GRAPH_STATE_ONE_RETURN,
IR_GRAPH_STATE_NO_CRITICAL_EDGES | IR_GRAPH_STATE_NO_UNREACHABLE_CODE | IR_GRAPH_STATE_NO_BAD_BLOCKS | IR_GRAPH_STATE_ONE_RETURN,
do_ifconv,
};
......
......@@ -783,7 +783,7 @@ static ir_graph_state_t do_jumpthread(ir_graph* irg)
optdesc_t opt_jumpthread = {
"jumpthreading",
IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS | IR_GRAPH_STATE_CONSISTENT_OUT_EDGES | IR_GRAPH_STATE_NO_CRITICAL_EDGES,
IR_GRAPH_STATE_NO_UNREACHABLE_CODE | IR_GRAPH_STATE_CONSISTENT_OUT_EDGES | IR_GRAPH_STATE_NO_CRITICAL_EDGES,
do_jumpthread,
};
......
......@@ -2304,7 +2304,7 @@ static ir_graph_state_t do_loadstore_opt(ir_graph *irg)
optdesc_t opt_loadstore = {
"load-store",
IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS | IR_GRAPH_STATE_CONSISTENT_OUT_EDGES | IR_GRAPH_STATE_NO_CRITICAL_EDGES | IR_GRAPH_STATE_CONSISTENT_DOMINANCE | IR_GRAPH_STATE_CONSISTENT_ENTITY_USAGE,
IR_GRAPH_STATE_NO_UNREACHABLE_CODE | IR_GRAPH_STATE_CONSISTENT_OUT_EDGES | IR_GRAPH_STATE_NO_CRITICAL_EDGES | IR_GRAPH_STATE_CONSISTENT_DOMINANCE | IR_GRAPH_STATE_CONSISTENT_ENTITY_USAGE,
do_loadstore_opt,
};
......
......@@ -27,7 +27,7 @@ void perform_irg_optimization(ir_graph *irg, optdesc_t *opt)
/* no bad block requires no unreachable code */
if (required & IR_GRAPH_STATE_NO_BAD_BLOCKS)
required |= IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS;
required |= IR_GRAPH_STATE_NO_UNREACHABLE_CODE;
/** Some workarounds because information is currently duplicated */
// FIXME should not be necessary!
......@@ -38,7 +38,7 @@ void perform_irg_optimization(ir_graph *irg, optdesc_t *opt)
#define PREPARE(st,func) if (st & (required ^ irg->state)) {func(irg); set_irg_state(irg,st);}
PREPARE(IR_GRAPH_STATE_ONE_RETURN, normalize_one_return)
PREPARE(IR_GRAPH_STATE_NO_CRITICAL_EDGES, remove_critical_cf_edges)
PREPARE(IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS, remove_unreachable_blocks)
PREPARE(IR_GRAPH_STATE_NO_UNREACHABLE_CODE, remove_unreachable_blocks)
PREPARE(IR_GRAPH_STATE_NO_BAD_BLOCKS, remove_bads)
PREPARE(IR_GRAPH_STATE_CONSISTENT_DOMINANCE, assure_doms)
PREPARE(IR_GRAPH_STATE_CONSISTENT_POSTDOMINANCE, assure_postdoms)
......@@ -63,7 +63,7 @@ void perform_irg_optimization(ir_graph *irg, optdesc_t *opt)
*/
#define INVALIDATE(state,func) if (!(state & new_irg_state)) {clear_irg_state(irg,state); func(irg);}
INVALIDATE(IR_GRAPH_STATE_NO_CRITICAL_EDGES, nop)
INVALIDATE(IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS, nop)
INVALIDATE(IR_GRAPH_STATE_NO_UNREACHABLE_CODE, nop)
INVALIDATE(IR_GRAPH_STATE_NO_BAD_BLOCKS, nop)
INVALIDATE(IR_GRAPH_STATE_ONE_RETURN, nop)
INVALIDATE(IR_GRAPH_STATE_CONSISTENT_DOMINANCE, nop)
......
......@@ -771,7 +771,7 @@ static ir_graph_state_t do_scalar_replacement(ir_graph *irg)
optdesc_t opt_scalar_rep = {
"scalar-replace",
IR_GRAPH_STATE_NO_UNREACHABLE_BLOCKS | IR_GRAPH_STATE_CONSISTENT_OUTS,
IR_GRAPH_STATE_NO_UNREACHABLE_CODE | IR_GRAPH_STATE_CONSISTENT_OUTS,
do_scalar_replacement,
};
......
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