+ FIRM_DBG_REGISTER(dbg, "firm.opt.remove_phi");
+
+ DB((dbg, LEVEL_1, "Doing Phi cycle removement for %+F\n", irg));
+
+ obstack_init(&env.obst);
+ env.stack = NEW_ARR_F(ir_node *, 128);
+ env.tos = 0;
+ env.nextDFSnum = 0;
+ env.POnum = 0;
+ env.quad_map = NULL;
+ env.lftr_edges = NULL;
+ env.replaced = 0;
+ env.lftr_replaced = 0;
+ env.osr_flags = 0;
+ env.need_postpass = 0;
+ env.process_scc = process_phi_only_scc;
+
+ /* Clear all links and move Proj nodes into the
+ * the same block as their predecessors.
+ * This can improve the placement of new nodes.
+ */
+ irg_walk_graph(irg, NULL, clear_and_fix, NULL);
+
+ /* we need outs for calculating the post order */
+ assure_irg_outs(irg);
+
+ /* calculate the post order number for blocks. */
+ irg_out_block_walk(get_irg_start_block(irg), NULL, assign_po, &env);
+
+ /* calculate the SCC's and drive OSR. */
+ ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
+ do_dfs(irg, &env);
+ ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
+
+ if (env.replaced) {
+ DB((dbg, LEVEL_1, "remove_phi_cycles: %u Cycles removed\n\n", env.replaced));
+ }
+
+ DEL_ARR_F(env.stack);
+ obstack_free(&env.obst, NULL);
+} /* remove_phi_cycles */
+
+ir_graph_pass_t *remove_phi_cycles_pass(const char *name)
+{
+ return def_graph_pass(name ? name : "remove_phi_cycles", remove_phi_cycles);
+} /* remove_phi_cycles_pass */
+
+/**
+ * Post-walker: fix Add and Sub nodes that where results of I<->P conversions.
+ */
+static void fix_adds_and_subs(ir_node *irn, void *ctx)
+{
+ (void) ctx;
+
+ if (is_Add(irn)) {
+ ir_mode *mode = get_irn_mode(irn);
+
+ if (mode_is_int(mode)) {
+ ir_node *pred;
+
+ pred = get_Add_left(irn);
+ if (get_irn_mode(pred) != mode) {
+ ir_node *block = get_nodes_block(pred);
+
+ pred = new_r_Conv(block, pred, mode);
+ set_Add_left(irn, pred);
+ }
+ pred = get_Add_right(irn);
+ if (get_irn_mode(pred) != mode) {
+ ir_node *block = get_nodes_block(pred);
+
+ pred = new_r_Conv(block, pred, mode);
+ set_Add_right(irn, pred);
+ }
+ }
+ } else if (is_Sub(irn)) {
+ ir_mode *mode = get_irn_mode(irn);
+
+ if (mode_is_int(mode)) {
+ ir_node *left = get_Sub_left(irn);
+ ir_node *right = get_Sub_right(irn);
+ ir_mode *l_mode = get_irn_mode(left);
+ ir_mode *r_mode = get_irn_mode(right);
+
+ if (mode_is_int(l_mode) && mode_is_int(r_mode)) {
+ if (l_mode != mode) {
+ ir_node *block = get_nodes_block(left);
+
+ left = new_r_Conv(block, left, mode);
+ set_Sub_left(irn, left);
+ }
+ if (r_mode != mode) {
+ ir_node *block = get_nodes_block(right);
+
+ right = new_r_Conv(block, right, mode);
+ set_Sub_right(irn, right);
+ }
+ }
+ } else if (mode_is_reference(mode)) {
+ ir_node *left = get_Sub_left(irn);
+ ir_node *right = get_Sub_right(irn);
+ ir_mode *l_mode = get_irn_mode(left);
+ ir_mode *r_mode = get_irn_mode(right);
+ if (mode_is_int(l_mode)) {
+ /* Usually, Sub(I*,P) is an error, hence the verifier rejects it.
+ * However, it is correct in this case, so add Conv to make verifier happy. */
+ ir_node *block = get_nodes_block(right);
+ ir_node *lconv = new_r_Conv(block, left, r_mode);
+ assert(mode_is_reference(r_mode));
+ set_Sub_left(irn, lconv);
+ }
+ }
+ }
+} /* fix_adds_and_subs */
+
+/* Performs Operator Strength Reduction for the passed graph. */
+void opt_osr(ir_graph *irg, unsigned flags)
+{
+ iv_env env;
+ int edges;