- /*
- * If this block has already been visited, don't recurse to its
- * children.
- */
- if(get_irn_visited(block) < visited_nr) {
-
- /* Mark the block visited. */
- set_irn_visited(block, visited_nr);
-
- /* Search recursively from this cond. */
- for(i = 0, n = get_irn_arity(block); i < n; ++i) {
- ir_node *pred = get_irn_n(block, i);
-
- /*
- * If the depth is 0 (the first recursion), we set the pos to
- * the current viewed predecessor, else we adopt the position
- * as given by the caller. We also increase the depth for the
- * recursively called functions.
- */
- _find_conds(pred, visited_nr, dominator, cond, depth == 0 ? i : pos, depth + 1, conds);
+ /* Bail out, if there are no Phis at all */
+ if (get_Block_phis(block) == NULL) return;
+
+restart:
+ arity = get_irn_arity(block);
+ for (i = 0; i < arity; ++i) {
+ ir_node* pred0;
+ ir_cdep* cdep;
+
+ pred0 = get_Block_cfgpred_block(block, i);
+ for (cdep = find_cdep(pred0); cdep != NULL; cdep = cdep->next) {
+ const ir_node* dependency = cdep->node;
+ ir_node* projx0 = walk_to_projx(pred0, dependency);
+ ir_node* cond;
+ int j;
+
+ if (projx0 == NULL) continue;
+
+ cond = get_Proj_pred(projx0);
+ if (! is_Cond(cond))
+ continue;
+
+ /* We only handle boolean decisions, no switches */
+ if (get_irn_mode(get_Cond_selector(cond)) != mode_b) continue;
+
+ for (j = i + 1; j < arity; ++j) {
+ ir_node* projx1;
+ ir_node* sel;
+ ir_node* mux_block;
+ ir_node* phi;
+ ir_node* p;
+ ir_node* pred1;
+ bool supported;
+ bool negated;
+ dbg_info* cond_dbg;
+
+ pred1 = get_Block_cfgpred_block(block, j);
+
+ if (!is_cdep_on(pred1, dependency)) continue;
+
+ projx1 = walk_to_projx(pred1, dependency);
+
+ if (projx1 == NULL) continue;
+
+ sel = get_Cond_selector(cond);
+ phi = get_Block_phis(block);
+ supported = true;
+ negated = get_Proj_proj(projx0) == pn_Cond_false;
+ for (p = phi; p != NULL; p = get_Phi_next(p)) {
+ ir_node *mux_false;
+ ir_node *mux_true;
+ if (negated) {
+ mux_true = get_Phi_pred(p, j);
+ mux_false = get_Phi_pred(p, i);
+ } else {
+ mux_true = get_Phi_pred(p, i);
+ mux_false = get_Phi_pred(p, j);
+ }
+ if (!env->allow_ifconv(sel, mux_false, mux_true)) {
+ supported = false;
+ break;
+ }
+ }
+ if (!supported)
+ continue;
+
+ DB((dbg, LEVEL_1, "Found Cond %+F with proj %+F and %+F\n",
+ cond, projx0, projx1
+ ));
+
+ /* remove critical edges */
+ env->changed = true;
+ prepare_path(block, i, dependency);
+ prepare_path(block, j, dependency);
+ arity = get_irn_arity(block);
+
+ mux_block = get_nodes_block(cond);
+ cond_dbg = get_irn_dbg_info(cond);
+ do { /* generate Mux nodes in mux_block for Phis in block */
+ ir_node* val_i = get_irn_n(phi, i);
+ ir_node* val_j = get_irn_n(phi, j);
+ ir_node* mux;
+ ir_node* next_phi;
+
+ if (val_i == val_j) {
+ mux = val_i;
+ DB((dbg, LEVEL_2, "Generating no Mux, because both values are equal\n"));
+ } else {
+ ir_node *t, *f;
+
+ /* Something is very fishy if two predecessors of a PhiM point into
+ * one block, but not at the same memory node
+ */
+ assert(get_irn_mode(phi) != mode_M);
+ if (negated) {
+ t = val_j;
+ f = val_i;
+ } else {
+ t = val_i;
+ f = val_j;
+ }
+
+ mux = new_rd_Mux(cond_dbg, mux_block, sel, f, t, get_irn_mode(phi));
+ DB((dbg, LEVEL_2, "Generating %+F for %+F\n", mux, phi));
+ }
+
+ next_phi = get_Phi_next(phi);
+
+ if (arity == 2) {
+ exchange(phi, mux);
+ } else {
+ rewire(phi, i, j, mux);
+ }
+ phi = next_phi;
+ } while (phi != NULL);
+
+ /* move mux operands into mux_block */
+ exchange(get_nodes_block(get_irn_n(block, i)), mux_block);
+ exchange(get_nodes_block(get_irn_n(block, j)), mux_block);
+
+ if (arity == 2) {
+ unsigned mark;
+#if 1
+ DB((dbg, LEVEL_1, "Welding block %+F and %+F\n", block, mux_block));
+ /* copy the block-info from the Mux-block to the block before merging */
+
+ mark = get_Block_mark(mux_block) | get_Block_mark(block);
+ set_Block_mark(block, mark);
+ set_Block_phis(block, get_Block_phis(mux_block));
+
+ set_irn_in(block, get_irn_arity(mux_block), get_irn_in(mux_block) + 1);
+ exchange_cdep(mux_block, block);
+ exchange(mux_block, block);
+#else
+ DB((dbg, LEVEL_1, "Welding block %+F to %+F\n", block, mux_block));
+ mark = get_Block_mark(mux_block) | get_Block_mark(block);
+ /* mark both block just to be sure, should be enough to mark mux_block */
+ set_Block_mark(mux_block, mark);
+ exchange(block, mux_block);
+#endif
+ return;
+ } else {
+ rewire(block, i, j, new_r_Jmp(mux_block));
+ goto restart;
+ }