int exc_idx; /**< predecessor index in the exception block */
} ldst_info_t;
+/**
+ * flags for control flow
+ */
+enum block_flags_t {
+ BLOCK_HAS_COND = 1, /**< Block has conditional control flow */
+ BLOCK_HAS_EXC = 2 /**< Block has exceptionl control flow */
+};
+
+/**
+ * a Block info
+ */
+typedef struct _block_info_t {
+ unsigned flags; /**< flags for the block */
+} block_info_t;
+
/**
* walker, clears all links first
*/
/**
* get the Load/Store info of a node
*/
-static ldst_info_t *get_info(ir_node *node, walk_env_t *env)
+static ldst_info_t *get_ldst_info(ir_node *node, walk_env_t *env)
{
ldst_info_t *info = get_irn_link(node);
return info;
}
+/**
+ * get the Block info of a node
+ */
+static block_info_t *get_block_info(ir_node *node, walk_env_t *env)
+{
+ block_info_t *info = get_irn_link(node);
+
+ if (! info) {
+ info = obstack_alloc(&env->obst, sizeof(*info));
+
+ memset(info, 0, sizeof(*info));
+
+ set_irn_link(node, info);
+ }
+ return info;
+}
+
/**
* update the projection info for a Load/Store
*/
/**
* walker, collects all Load/Store/Proj nodes
+ *
+ * walks form Start -> End
*/
static void collect_nodes(ir_node *node, void *env)
{
ir_node *pred;
- ldst_info_t *info;
+ ldst_info_t *ldst_info;
walk_env_t *wenv = env;
if (get_irn_op(node) == op_Proj) {
pred = get_Proj_pred(node);
if (get_irn_op(pred) == op_Load || get_irn_op(pred) == op_Store) {
- info = get_info(pred, wenv);
+ ldst_info = get_ldst_info(pred, wenv);
- wenv->changes |= update_projs(info, node);
+ wenv->changes |= update_projs(ldst_info, node);
}
}
else if (get_irn_op(node) == op_Block) { /* check, if it's an exception block */
int i, n;
for (i = 0, n = get_Block_n_cfgpreds(node); i < n; ++i) {
+ ir_node *pred_block;
+ block_info_t *bl_info;
+
pred = skip_Proj(get_Block_cfgpred(node, i));
+ /* ignore Bad predecessors, they will be removed later */
+ if (is_Bad(pred))
+ continue;
+
+ pred_block = get_nodes_block(pred);
+ bl_info = get_block_info(pred_block, wenv);
+
+ if (is_fragile_op(pred))
+ bl_info->flags |= BLOCK_HAS_EXC;
+ else if (is_forking_op(pred))
+ bl_info->flags |= BLOCK_HAS_COND;
+
if (get_irn_op(pred) == op_Load || get_irn_op(pred) == op_Store) {
- info = get_info(pred, wenv);
+ ldst_info = get_ldst_info(pred, wenv);
- wenv->changes |= update_exc(info, node, i);
+ wenv->changes |= update_exc(ldst_info, node, i);
}
}
}
* throw an exception when the previous Store was quiet.
*/
if (! info->projs[pn_Load_X_except] || get_nodes_block(load) == get_nodes_block(pred)) {
+ DBG_OPT_RAW(pred, load);
exchange( info->projs[pn_Load_res], get_Store_value(pred) );
+
if (info->projs[pn_Load_M])
exchange(info->projs[pn_Load_M], mem);
if (! info->projs[pn_Load_X_except] || get_nodes_block(load) == get_nodes_block(pred)) {
ldst_info_t *pred_info = get_irn_link(pred);
+ DBG_OPT_RAR(pred, load);
+
if (pred_info->projs[pn_Load_res]) {
/* we need a data proj from the previous load for this optimization */
exchange( info->projs[pn_Load_res], pred_info->projs[pn_Load_res] );
* TODO: What, if both have the same exception handler ???
*/
if (get_Store_volatility(pred) != volatility_is_volatile && !pred_info->projs[pn_Store_X_except]) {
+ DBG_OPT_WAW(pred, store);
exchange( pred_info->projs[pn_Store_M], get_Store_mem(pred) );
res = 1;
}
* We may remove the second Store, if it does not have an exception handler.
*/
if (! info->projs[pn_Store_X_except]) {
+ DBG_OPT_WAR(pred, store);
exchange( info->projs[pn_Store_M], mem );
res = 1;
}
* \ | / Str
* Phi
*
- * This removes teh number of stores and allows for predicated execution.
+ * This removes the number of stores and allows for predicated execution.
* Moves Stores back to the end of a function which may be bad
*
- * Note: that even works, if one of the Stores is already in our current block
+ * Is only allowed if the predecessor blocks have only one successor.
*/
-static int optimize_phi(ir_node *phi)
+static int optimize_phi(ir_node *phi, void *env)
{
+ walk_env_t *wenv = env;
int i, n;
- ir_node *store, *ptr, *block, *phiM, *phiD, *exc;
+ ir_node *store, *ptr, *block, *phiM, *phiD, *exc, *projM;
ir_mode *mode;
ir_node **inM, **inD;
int *idx;
dbg_info *db = NULL;
ldst_info_t *info;
+ block_info_t *bl_info;
/* Must be a memory Phi */
if (get_irn_mode(phi) != mode_M)
if (get_irn_op(store) != op_Store)
return 0;
+ /* abort on bad blocks */
+ if (is_Bad(get_nodes_block(store)))
+ return 0;
+
+ /* check if the block has only one output */
+ bl_info = get_irn_link(get_nodes_block(store));
+ if (bl_info->flags)
+ return 0;
+
/* this is the address of the store */
ptr = get_Store_ptr(store);
mode = get_irn_mode(get_Store_value(store));
/* check, if all stores have the same exception flow */
if (exc != info->exc_block)
return 0;
+
+ /* abort on bad blocks */
+ if (is_Bad(get_nodes_block(store)))
+ return 0;
+
+ /* check if the block has only one output */
+ bl_info = get_irn_link(get_nodes_block(store));
+ if (bl_info->flags)
+ return 0;
}
/*
* \ | / Str
* Phi
*
- * Note: that even works, if one of the Stores is already in our current block
+ * Is only allowed if the predecessor blocks have only one successor.
*/
/* first step: collect all inputs */
/* fourth step: create the Store */
store = new_rd_Store(db, current_ir_graph, block, phiM, ptr, phiD);
+ projM = new_rd_Proj(NULL, current_ir_graph, block, store, mode_M, pn_Store_M);
+
+ info = get_ldst_info(store, wenv);
+ info->projs[pn_Store_M] = projM;
/* fifths step: repair exception flow */
if (exc) {
ir_node *projX = new_rd_Proj(NULL, current_ir_graph, block, store, mode_X, pn_Store_X_except);
+ info->projs[pn_Store_X_except] = projX;
+ info->exc_block = exc;
+ info->exc_idx = idx[0];
+
for (i = 0; i < n; ++i) {
set_Block_cfgpred(exc, idx[i], projX);
}
}
/* sixt step: replace old Phi */
- exchange(phi, new_rd_Proj(NULL, current_ir_graph, block, store, mode_M, pn_Store_M));
+ exchange(phi, projM);
return 1;
}
break;
case iro_Phi:
- wenv->changes |= optimize_phi(n);
+ wenv->changes |= optimize_phi(n, env);
default:
;