- walk_env_t *wenv = env;
- int i, n;
- 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)
- return 0;
-
- n = get_Phi_n_preds(phi);
- if (n <= 0)
- return 0;
-
- store = skip_Proj(get_Phi_pred(phi, 0));
- 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));
- 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 (mode != get_irn_mode(get_Store_value(pred)) || ptr != get_Store_ptr(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 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;
- }
-
- /*
- * 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:
- *
- * val1 val2 val3 val1 val2 val3
- * | | | \ | /
- * | Str | | Str | | Str | \ | /
- * \ | / Phi
- * \ | / |
- * \ | / Str
- * Phi
- *
- * 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);
- 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 */
- }
- }
-
- /* sixt step: replace old Phi */
- exchange(phi, projM);
-
- return 1;
-}
+ int i, n;
+ ir_node *store, *old_store, *ptr, *block, *phi_block, *phiM, *phiD, *exc, *projM;
+ ir_mode *mode;
+ ir_node **inM, **inD, **stores;
+ 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;
+
+ block = get_nodes_block(store);
+
+ /* abort on dead blocks */
+ if (is_Block_dead(block))
+ return 0;
+
+ /* check if the block is post dominated by Phi-block
+ and has no exception exit */
+ bl_info = get_irn_link(block);
+ if (bl_info->flags & BLOCK_HAS_EXC)
+ return 0;
+
+ phi_block = get_nodes_block(phi);
+ if (! block_postdominates(phi_block, block))
+ 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 */
+ block = get_nodes_block(pred);
+ if (is_Block_dead(block))
+ return 0;
+
+ /* check if the block is post dominated by Phi-block
+ and has no exception exit. Note that block must be different from
+ Phi-block, else we would move a Store from end End of a block to its
+ Start... */
+ bl_info = get_irn_link(block);
+ if (bl_info->flags & BLOCK_HAS_EXC)
+ return 0;
+ if (block == phi_block || ! block_postdominates(phi_block, block))
+ 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.
+ */
+
+ NEW_ARR_A(ir_node *, stores, n);
+ NEW_ARR_A(ir_node *, inM, n);
+ NEW_ARR_A(ir_node *, inD, n);
+ NEW_ARR_A(int, idx, n);
+
+ /* Prepare: Collect all Store nodes. We must do this
+ first because we otherwise may loose a store when exchanging its
+ memory Proj.
+ */
+ for (i = 0; i < n; ++i)
+ stores[i] = skip_Proj(get_Phi_pred(phi, i));
+
+ /* Prepare: Skip the memory Proj: we need this in the case some stores
+ are cascaded.
+ Beware: One Store might be included more than once in the stores[]
+ list, so we must prevent to do the exchange more than once.
+ */
+ for (i = 0; i < n; ++i) {
+ ir_node *store = stores[i];
+ ir_node *proj_m;
+
+ info = get_irn_link(store);
+ proj_m = info->projs[pn_Store_M];
+
+ if (is_Proj(proj_m) && get_Proj_pred(proj_m) == store)
+ exchange(proj_m, get_Store_mem(store));
+ }
+
+ /* first step: collect all inputs */
+ for (i = 0; i < n; ++i) {
+ ir_node *store = stores[i];
+ info = get_irn_link(store);
+
+ inM[i] = get_Store_mem(store);
+ inD[i] = get_Store_value(store);
+ 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;
+} /* optimize_phi */