ir_node *exc_block; /**< the exception block if available */
int exc_idx; /**< predecessor index in the exception block */
unsigned flags; /**< flags */
+ unsigned visited; /**< visited counter for breaking loops */
} ldst_info_t;
/**
unsigned flags; /**< flags for the block */
} block_info_t;
+/** the master visited flag for loop detection. */
+static unsigned master_visited = 0;
+
+#define INC_MASTER() ++master_visited
+#define MARK_NODE(info) (info)->visited = master_visited
+#define NODE_VISITED(info) (info)->visited >= master_visited
+
/**
* get the Load/Store info of a node
*/
if (get_irn_out_n(ptr) <= 1)
return res;
- /* follow the memory chain as long as there are only Loads
- * and try to replace current Load or Store by a previous one
+ /*
+ * follow the memory chain as long as there are only Loads
+ * and try to replace current Load or Store by a previous one.
+ * Note that in unreachable loops it might happen that we reach
+ * load again, as well as we can fall into a cycle.
+ * We break such cycles using a special visited flag.
*/
- for (pred = skip_Proj(mem); ; pred = skip_Proj(get_Load_mem(pred))) {
+ INC_MASTER();
+ for (pred = skip_Proj(mem); load != pred; pred = skip_Proj(get_Load_mem(pred))) {
+ ldst_info_t *info;
+
/*
* BEWARE: one might think that checking the modes is useless, because
* if the pointers are identical, they refer to the same object.
/* follow only Load chains */
if (get_irn_op(pred) != op_Load)
break;
- }
+
+ /* check for cycles */
+ info = get_irn_link(pred);
+ if (NODE_VISITED(info))
+ break;
+ MARK_NODE(info);
+ }
return res;
}
mode = get_irn_mode(value);
/* follow the memory chain as long as there are only Loads */
- for (pred = skip_Proj(mem); ; pred = skip_Proj(get_Load_mem(pred))) {
+ INC_MASTER();
+ for (pred = skip_Proj(mem); pred != store; pred = skip_Proj(get_Load_mem(pred))) {
ldst_info_t *pred_info = get_irn_link(pred);
if (get_irn_op(pred) == op_Store && get_Store_ptr(pred) == ptr &&
/* follow only Load chains */
if (get_irn_op(pred) != op_Load)
break;
+
+ /* check for cycles */
+ info = get_irn_link(pred);
+ if (NODE_VISITED(info))
+ break;
+ MARK_NODE(info);
}
return res;
}
/**
- * walker, optimizes Phi after Stores:
+ * walker, optimizes Phi after Stores to identical places:
* Does the following optimization:
+ * @verbatim
*
* val1 val2 val3 val1 val2 val3
* | | | \ | /
* Str Str Str \ | /
- * \ | / Phi
+ * \ | / PhiData
* \ | / |
* \ | / Str
- * Phi
+ * PhiM
*
+ * @endverbatim
* This reduces the number of stores and allows for predicated execution.
* Moves Stores back to the end of a function which may be bad.
*
if (get_irn_op(pred) != op_Store)
return 0;
- if (mode != get_irn_mode(get_Store_value(pred)) || ptr != get_Store_ptr(pred))
+ if (ptr != get_Store_ptr(pred) || mode != get_irn_mode(get_Store_value(pred)))
return 0;
info = get_irn_link(pred);
/*
* ok, when we are here, we found all predecessors of a Phi that
- * are Stores to the same address. That means whatever we do before
- * we enter the block of the Phi, we do a Store.
- * So, we can move the store to the current block:
+ * are Stores to the same address and size. That means whatever
+ * we do before we enter the block of the Phi, we do a Store.
+ * So, we can move the Store to the current block:
*
* val1 val2 val3 val1 val2 val3
* | | | \ | /
* | Str | | Str | | Str | \ | /
- * \ | / Phi
+ * \ | / PhiData
* \ | / |
* \ | / Str
- * Phi
+ * PhiM
*
* Is only allowed if the predecessor blocks have only one successor.
*/
}
/**
- * walker, collects all Load/Store/Proj nodes
+ * walker, do the optiimizations
*/
static void do_load_store_optimize(ir_node *n, void *env)
{
env.changes = 0;
/* init the links, then collect Loads/Stores/Proj's in lists */
+ master_visited = 0;
irg_walk_graph(irg, firm_clear_link, collect_nodes, &env);
/* now we have collected enough information, optimize */