+/**
+ * Block-walker: searches for the following construct
+ *
+ * Const or Phi with constants
+ * |
+ * Cmp
+ * |
+ * Cond
+ * /
+ * ProjX
+ * /
+ * Block
+ */
+static void cond_eval(ir_node* block, void* data)
+{
+ condeval_env_t env;
+ int *changed = data;
+ ir_graph *irg = current_ir_graph;
+ ir_node *copy_block;
+ ir_node *pred;
+ ir_node *projx;
+ ir_node *cond;
+ ir_node *cmp;
+ ir_node *left;
+ ir_node *right;
+ ir_node *cond_block;
+ pn_Cmp pnc;
+
+ if(get_Block_n_cfgpreds(block) != 1)
+ return;
+
+ projx = get_Block_cfgpred(block, 0);
+ if (!is_Proj(projx))
+ return;
+ assert(get_irn_mode(projx) == mode_X);
+
+ cond = get_Proj_pred(projx);
+ if (!is_Cond(cond))
+ return;
+
+ pred = get_Cond_selector(cond);
+ // TODO handle switches
+ if (get_irn_mode(pred) != mode_b)
+ return;
+ if (!is_Proj(pred))
+ return;
+ pnc = get_Proj_proj(pred);
+
+ cmp = get_Proj_pred(pred);
+ assert(is_Cmp(cmp));
+
+ left = get_Cmp_left(cmp);
+ right = get_Cmp_right(cmp);
+ assert(get_irn_mode(left) == get_irn_mode(right));
+
+ /* we assume that the cond_block is the true case */
+ if (get_Proj_proj(projx) == pn_Cond_false) {
+ pnc = get_negated_pnc(pnc, get_irn_mode(left));
+ }
+
+ /* we assume that the constant is on the right side, swap left/right
+ * if needed */
+ if(is_Const(left)) {
+ ir_node *t = left;
+ left = right;
+ right = t;
+
+ pnc = get_inversed_pnc(pnc);
+ }
+
+ if(!is_Const(right))
+ return;
+
+ cond_block = get_nodes_block(cond);
+
+ // special case: comparing a constant with a constant
+ if(is_Const(left)) {
+ tarval *tv1 = get_Const_tarval(left);
+ tarval *tv2 = get_Const_tarval(right);
+ ir_node *pred;
+ if(eval_cmp(pnc, tv1, tv2)) {
+ pred = new_r_Jmp(irg, cond_block);
+ } else {
+ pred = new_Bad();
+ }
+ set_Block_cfgpred(block, 0, pred);
+ *changed = 1;
+ set_irg_doms_inconsistent(irg);
+ set_irg_extblk_inconsistent(irg);
+ set_irg_loopinfo_inconsistent(irg);
+ } else {
+ if(get_nodes_block(left) != cond_block)
+ return;
+
+ // (recursively) look if a pred of a phi is a constant
+ env.true_block = block;
+ env.pnc = pnc;
+ env.cnst = right;
+ inc_irg_visited(current_ir_graph);
+ env.visited_nr = get_irg_visited(irg);
+
+ copy_block = find_phi_with_const(projx, left, &env);
+
+ if(copy_block != NULL) {
+ /* we have to remove the edge towards the pred as the pred now
+ * jumps into the true_block. We also have to shorten phis
+ * in our block because of this */
+ const ir_edge_t *edge, *next;
+
+ /* shorten phis */
+ foreach_out_edge_safe(env.cnst_pred, edge, next) {
+ ir_node *node = get_edge_src_irn(edge);
+
+ if(is_Phi(node))
+ remove_pred(node, env.cnst_pos);
+ }
+
+ remove_pred(env.cnst_pred, env.cnst_pos);
+
+ /* the graph is changed now */
+ *changed = 1;
+ }
+ }
+}
+