+ * walker, optimizes Phi after Stores to identical places:
+ * Does the following optimization:
+ * @verbatim
+ *
+ * val1 val2 val3 val1 val2 val3
+ * | | | \ | /
+ * Str Str Str \ | /
+ * \ | / PhiData
+ * \ | / |
+ * \ | / Str
+ * 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.
+ *
+ * This is only possible if the predecessor blocks have only one successor.
+ */
+static unsigned optimize_phi(ir_node *phi, void *env)
+{
+ walk_env_t *wenv = env;
+ int i, n;
+ ir_node *store, *old_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;
+ unsigned res = 0;
+
+ /* Must be a memory Phi */
+ if (get_irn_mode(phi) != mode_M)
+ return 0;
+
+ n = get_Phi_n_preds(phi);
+ if (n <= 0)
+ return 0;
+
+ store = skip_Proj(get_Phi_pred(phi, 0));
+ old_store = store;
+ if (get_irn_op(store) != op_Store)
+ return 0;
+
+ /* abort on dead blocks */
+ if (is_Block_dead(get_nodes_block(store)))
+ return 0;
+
+ /* check if the block has only one successor */
+ 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));
+ info = get_irn_link(store);
+ exc = info->exc_block;
+
+ for (i = 1; i < n; ++i) {
+ ir_node *pred = skip_Proj(get_Phi_pred(phi, i));
+
+ if (get_irn_op(pred) != op_Store)
+ return 0;
+
+ if (ptr != get_Store_ptr(pred) || mode != get_irn_mode(get_Store_value(pred)))
+ return 0;
+
+ info = get_irn_link(pred);
+
+ /* check, if all stores have the same exception flow */
+ if (exc != info->exc_block)
+ return 0;
+
+ /* abort on dead blocks */
+ if (is_Block_dead(get_nodes_block(store)))
+ return 0;
+
+ /* check if the block has only one successor */
+ bl_info = get_irn_link(get_nodes_block(store));
+ if (bl_info->flags)
+ return 0;
+ }
+
+ /*
+ * ok, when we are here, we found all predecessors of a Phi that
+ * 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 | \ | /
+ * \ | / PhiData
+ * \ | / |
+ * \ | / Str
+ * PhiM
+ *
+ * Is only allowed if the predecessor blocks have only one successor.
+ */
+
+ /* first step: collect all inputs */
+ NEW_ARR_A(ir_node *, inM, n);
+ NEW_ARR_A(ir_node *, inD, n);
+ NEW_ARR_A(int, idx, n);
+
+ for (i = 0; i < n; ++i) {
+ ir_node *pred = skip_Proj(get_Phi_pred(phi, i));
+ info = get_irn_link(pred);
+
+ inM[i] = get_Store_mem(pred);
+ inD[i] = get_Store_value(pred);
+ idx[i] = info->exc_idx;
+ }
+ block = get_nodes_block(phi);
+
+ /* second step: create a new memory Phi */
+ phiM = new_rd_Phi(get_irn_dbg_info(phi), current_ir_graph, block, n, inM, mode_M);
+
+ /* third step: create a new data Phi */
+ phiD = new_rd_Phi(get_irn_dbg_info(phi), current_ir_graph, block, n, inD, mode);
+
+ /* fourth step: create the Store */
+ store = new_rd_Store(db, current_ir_graph, block, phiM, ptr, phiD);
+#ifdef DO_CACHEOPT
+ co_set_irn_name(store, co_get_irn_ident(old_store));
+#endif
+
+ 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);
+ }
+
+ if (n > 1) {
+ /* the exception block should be optimized as some inputs are identical now */
+ }
+
+ res |= CF_CHANGED;
+ }
+
+ /* sixth step: replace old Phi */
+ exchange(phi, projM);
+
+ return res | DF_CHANGED;
+}
+
+/**
+ * walker, do the optimizations