edge ssa_redirect_edge (edge e, basic_block dest) { tree phi; tree list = NULL, *last = &list; tree src, dst, node; /* Remove the appropriate PHI arguments in E's destination block. */ for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi)) { if (PHI_ARG_DEF (phi, e->dest_idx) == NULL_TREE) continue; src = PHI_ARG_DEF (phi, e->dest_idx); dst = PHI_RESULT (phi); node = build_tree_list (dst, src); *last = node; last = &TREE_CHAIN (node); } e = redirect_edge_succ_nodup (e, dest); PENDING_STMT (e) = list; return e; }
void flush_pending_stmts (edge e) { tree phi, arg; if (!PENDING_STMT (e)) return; for (phi = phi_nodes (e->dest), arg = PENDING_STMT (e); phi; phi = PHI_CHAIN (phi), arg = TREE_CHAIN (arg)) { tree def = TREE_VALUE (arg); add_phi_arg (phi, def, e); } PENDING_STMT (e) = NULL; }
void gsi_commit_one_edge_insert (edge e, basic_block *new_bb) { if (new_bb) *new_bb = NULL; if (PENDING_STMT (e)) { gimple_stmt_iterator gsi; gimple_seq seq = PENDING_STMT (e); bool ins_after; PENDING_STMT (e) = NULL; ins_after = gimple_find_edge_insert_loc (e, &gsi, new_bb); update_call_edge_frequencies (gimple_seq_first (seq), gsi.bb); if (ins_after) gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT); else gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT); } }
basic_block gsi_insert_seq_on_edge_immediate (edge e, gimple_seq stmts) { gimple_stmt_iterator gsi; basic_block new_bb = NULL; bool ins_after; gcc_assert (!PENDING_STMT (e)); ins_after = gimple_find_edge_insert_loc (e, &gsi, &new_bb); update_call_edge_frequencies (gimple_seq_first (stmts), gsi.bb); if (ins_after) gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT); else gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT); return new_bb; }
basic_block gsi_insert_on_edge_immediate (edge e, gimple stmt) { gimple_stmt_iterator gsi; struct gimple_seq_node_d node; basic_block new_bb = NULL; bool ins_after; gcc_assert (!PENDING_STMT (e)); ins_after = gimple_find_edge_insert_loc (e, &gsi, &new_bb); node.stmt = stmt; node.prev = node.next = NULL; update_call_edge_frequencies (&node, gsi.bb); if (ins_after) gsi_insert_after (&gsi, stmt, GSI_NEW_STMT); else gsi_insert_before (&gsi, stmt, GSI_NEW_STMT); return new_bb; }
static void eliminate_tail_call (struct tailcall *t) { tree param, rslt; gimple stmt, call; tree arg; size_t idx; basic_block bb, first; edge e; gimple phi; gimple_stmt_iterator gsi; gimple orig_stmt; stmt = orig_stmt = gsi_stmt (t->call_gsi); bb = gsi_bb (t->call_gsi); if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Eliminated tail recursion in bb %d : ", bb->index); print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); fprintf (dump_file, "\n"); } gcc_assert (is_gimple_call (stmt)); first = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); /* Remove the code after call_gsi that will become unreachable. The possibly unreachable code in other blocks is removed later in cfg cleanup. */ gsi = t->call_gsi; gsi_next (&gsi); while (!gsi_end_p (gsi)) { gimple t = gsi_stmt (gsi); /* Do not remove the return statement, so that redirect_edge_and_branch sees how the block ends. */ if (gimple_code (t) == GIMPLE_RETURN) break; gsi_remove (&gsi, true); release_defs (t); } /* Number of executions of function has reduced by the tailcall. */ e = single_succ_edge (gsi_bb (t->call_gsi)); decrease_profile (EXIT_BLOCK_PTR_FOR_FN (cfun), e->count, EDGE_FREQUENCY (e)); decrease_profile (ENTRY_BLOCK_PTR_FOR_FN (cfun), e->count, EDGE_FREQUENCY (e)); if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)) decrease_profile (e->dest, e->count, EDGE_FREQUENCY (e)); /* Replace the call by a jump to the start of function. */ e = redirect_edge_and_branch (single_succ_edge (gsi_bb (t->call_gsi)), first); gcc_assert (e); PENDING_STMT (e) = NULL; /* Add phi node entries for arguments. The ordering of the phi nodes should be the same as the ordering of the arguments. */ for (param = DECL_ARGUMENTS (current_function_decl), idx = 0, gsi = gsi_start_phis (first); param; param = DECL_CHAIN (param), idx++) { if (!arg_needs_copy_p (param)) continue; arg = gimple_call_arg (stmt, idx); phi = gsi_stmt (gsi); gcc_assert (param == SSA_NAME_VAR (PHI_RESULT (phi))); add_phi_arg (phi, arg, e, gimple_location (stmt)); gsi_next (&gsi); } /* Update the values of accumulators. */ adjust_accumulator_values (t->call_gsi, t->mult, t->add, e); call = gsi_stmt (t->call_gsi); rslt = gimple_call_lhs (call); if (rslt != NULL_TREE) { /* Result of the call will no longer be defined. So adjust the SSA_NAME_DEF_STMT accordingly. */ SSA_NAME_DEF_STMT (rslt) = gimple_build_nop (); } gsi_remove (&t->call_gsi, true); release_defs (call); }
gimple_stmt_iterator gsi_start_edge (edge e) { return gsi_start (PENDING_STMT (e)); }
void gsi_insert_seq_on_edge (edge e, gimple_seq seq) { gimple_seq_add_seq (&PENDING_STMT (e), seq); }
void gsi_insert_on_edge (edge e, gimple *stmt) { gimple_seq_add_stmt (&PENDING_STMT (e), stmt); }