X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcfg.c;h=1f681124105befeaac7818382f5daed07d617871;hb=28519aa935dfaeec125104b8206a203f227211a3;hp=c46ac0b88eeb1b06d9098f63e7befca5dc65dbba;hpb=738571e87c2c95ca446849e5aec56aa89f9c9b1e;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cfg.c b/gcc/cfg.c index c46ac0b88ee..1f681124105 100644 --- a/gcc/cfg.c +++ b/gcc/cfg.c @@ -1,13 +1,13 @@ /* Control flow graph manipulation code for GNU compiler. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* This file contains low level functions to manipulate the CFG and analyze it. All other modules should not transform the data structure @@ -62,9 +61,13 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "tm_p.h" #include "obstack.h" #include "timevar.h" +#include "tree-pass.h" #include "ggc.h" #include "hashtab.h" #include "alloc-pool.h" +#include "df.h" +#include "cfgloop.h" +#include "tree-flow.h" /* The obstack on which the flow graph components are allocated. */ @@ -78,17 +81,21 @@ static void free_edge (edge); /* Called once at initialization time. */ void -init_flow (void) +init_flow (struct function *the_fun) { - if (!cfun->cfg) - cfun->cfg = ggc_alloc_cleared (sizeof (struct control_flow_graph)); - n_edges = 0; - ENTRY_BLOCK_PTR = ggc_alloc_cleared (sizeof (struct basic_block_def)); - ENTRY_BLOCK_PTR->index = ENTRY_BLOCK; - EXIT_BLOCK_PTR = ggc_alloc_cleared (sizeof (struct basic_block_def)); - EXIT_BLOCK_PTR->index = EXIT_BLOCK; - ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR; - EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR; + if (!the_fun->cfg) + the_fun->cfg = GGC_CNEW (struct control_flow_graph); + n_edges_for_function (the_fun) = 0; + ENTRY_BLOCK_PTR_FOR_FUNCTION (the_fun) + = GGC_CNEW (struct basic_block_def); + ENTRY_BLOCK_PTR_FOR_FUNCTION (the_fun)->index = ENTRY_BLOCK; + EXIT_BLOCK_PTR_FOR_FUNCTION (the_fun) + = GGC_CNEW (struct basic_block_def); + EXIT_BLOCK_PTR_FOR_FUNCTION (the_fun)->index = EXIT_BLOCK; + ENTRY_BLOCK_PTR_FOR_FUNCTION (the_fun)->next_bb + = EXIT_BLOCK_PTR_FOR_FUNCTION (the_fun); + EXIT_BLOCK_PTR_FOR_FUNCTION (the_fun)->prev_bb + = ENTRY_BLOCK_PTR_FOR_FUNCTION (the_fun); } /* Helper function for remove_edge and clear_edges. Frees edge structure @@ -132,7 +139,7 @@ basic_block alloc_block (void) { basic_block bb; - bb = ggc_alloc_cleared (sizeof (*bb)); + bb = GGC_CNEW (struct basic_block_def); return bb; } @@ -161,21 +168,28 @@ void compact_blocks (void) { int i; - basic_block bb; - i = 0; - FOR_EACH_BB (bb) + SET_BASIC_BLOCK (ENTRY_BLOCK, ENTRY_BLOCK_PTR); + SET_BASIC_BLOCK (EXIT_BLOCK, EXIT_BLOCK_PTR); + + if (df) + df_compact_blocks (); + else { - BASIC_BLOCK (i) = bb; - bb->index = i; - i++; - } - - gcc_assert (i == n_basic_blocks); - - for (; i < last_basic_block; i++) - BASIC_BLOCK (i) = NULL; + basic_block bb; + + i = NUM_FIXED_BLOCKS; + FOR_EACH_BB (bb) + { + SET_BASIC_BLOCK (i, bb); + bb->index = i; + i++; + } + gcc_assert (i == n_basic_blocks); + for (; i < last_basic_block; i++) + SET_BASIC_BLOCK (i, NULL); + } last_basic_block = n_basic_blocks; } @@ -185,7 +199,7 @@ void expunge_block (basic_block b) { unlink_block (b); - BASIC_BLOCK (b->index) = NULL; + SET_BASIC_BLOCK (b->index, NULL); n_basic_blocks--; /* We should be able to ggc_free here, but we are not. The dead SSA_NAMES are left pointing to dead statements that are pointing @@ -200,6 +214,7 @@ static inline void connect_src (edge e) { VEC_safe_push (edge, gc, e->src->succs, e); + df_mark_solutions_dirty (); } /* Connect E to E->dest. */ @@ -210,6 +225,7 @@ connect_dest (edge e) basic_block dest = e->dest; VEC_safe_push (edge, gc, dest->preds, e); e->dest_idx = EDGE_COUNT (dest->preds) - 1; + df_mark_solutions_dirty (); } /* Disconnect edge E from E->src. */ @@ -232,6 +248,7 @@ disconnect_src (edge e) ei_next (&ei); } + df_mark_solutions_dirty (); gcc_unreachable (); } @@ -249,6 +266,7 @@ disconnect_dest (edge e) to update dest_idx of the edge that moved into the "hole". */ if (dest_idx < EDGE_COUNT (dest->preds)) EDGE_PRED (dest, dest_idx)->dest_idx = dest_idx; + df_mark_solutions_dirty (); } /* Create an edge connecting SRC and DEST with flags FLAGS. Return newly @@ -259,7 +277,7 @@ edge unchecked_make_edge (basic_block src, basic_block dst, int flags) { edge e; - e = ggc_alloc_cleared (sizeof (*e)); + e = GGC_CNEW (struct edge_def); n_edges++; e->src = src; @@ -270,7 +288,6 @@ unchecked_make_edge (basic_block src, basic_block dst, int flags) connect_dest (e); execute_on_growing_pred (e); - return e; } @@ -339,7 +356,7 @@ make_single_succ_edge (basic_block src, basic_block dest, int flags) /* This function will remove an edge from the flow graph. */ void -remove_edge (edge e) +remove_edge_raw (edge e) { remove_predictions_associated_with_edge (e); execute_on_shrinking_pred (e); @@ -347,6 +364,9 @@ remove_edge (edge e) disconnect_src (e); disconnect_dest (e); + /* This is probably not needed, but it doesn't hurt. */ + redirect_edge_var_map_clear (e); + free_edge (e); } @@ -383,6 +403,7 @@ redirect_edge_succ_nodup (edge e, basic_block new_succ) s->probability = REG_BR_PROB_BASE; s->count += e->count; remove_edge (e); + redirect_edge_var_map_dup (s, e); e = s; } else @@ -404,15 +425,16 @@ redirect_edge_pred (edge e, basic_block new_pred) connect_src (e); } -/* Clear all basic block flags, with the exception of partitioning. */ +/* Clear all basic block flags, with the exception of partitioning and + setjmp_target. */ void clear_bb_flags (void) { basic_block bb; FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) - bb->flags = (BB_PARTITION (bb) | (bb->flags & BB_DISABLE_SCHEDULE) - | (bb->flags & BB_RTL)); + bb->flags = (BB_PARTITION (bb) + | (bb->flags & (BB_DISABLE_SCHEDULE + BB_RTL + BB_NON_LOCAL_GOTO_TARGET))); } /* Check the consistency of profile information. We can't do that @@ -464,102 +486,182 @@ check_bb_profile (basic_block bb, FILE * file) } } +/* Write information about registers and basic blocks into FILE. + This is part of making a debugging dump. */ + void -dump_flow_info (FILE *file) +dump_regset (regset r, FILE *outf) { - basic_block bb; + unsigned i; + reg_set_iterator rsi; - /* There are no pseudo registers after reload. Don't dump them. */ - if (reg_n_info && !reload_completed) + if (r == NULL) { - unsigned int i, max = max_reg_num (); - fprintf (file, "%d registers.\n", max); - for (i = FIRST_PSEUDO_REGISTER; i < max; i++) - if (REG_N_REFS (i)) - { - enum reg_class class, altclass; - - fprintf (file, "\nRegister %d used %d times across %d insns", - i, REG_N_REFS (i), REG_LIVE_LENGTH (i)); - if (REG_BASIC_BLOCK (i) >= 0) - fprintf (file, " in block %d", REG_BASIC_BLOCK (i)); - if (REG_N_SETS (i)) - fprintf (file, "; set %d time%s", REG_N_SETS (i), - (REG_N_SETS (i) == 1) ? "" : "s"); - if (regno_reg_rtx[i] != NULL && REG_USERVAR_P (regno_reg_rtx[i])) - fprintf (file, "; user var"); - if (REG_N_DEATHS (i) != 1) - fprintf (file, "; dies in %d places", REG_N_DEATHS (i)); - if (REG_N_CALLS_CROSSED (i) == 1) - fprintf (file, "; crosses 1 call"); - else if (REG_N_CALLS_CROSSED (i)) - fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i)); - if (regno_reg_rtx[i] != NULL - && PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD) - fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i)); - - class = reg_preferred_class (i); - altclass = reg_alternate_class (i); - if (class != GENERAL_REGS || altclass != ALL_REGS) - { - if (altclass == ALL_REGS || class == ALL_REGS) - fprintf (file, "; pref %s", reg_class_names[(int) class]); - else if (altclass == NO_REGS) - fprintf (file, "; %s or none", reg_class_names[(int) class]); - else - fprintf (file, "; pref %s, else %s", - reg_class_names[(int) class], - reg_class_names[(int) altclass]); - } - - if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i])) - fprintf (file, "; pointer"); - fprintf (file, ".\n"); - } + fputs (" (nil)", outf); + return; } - fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges); - FOR_EACH_BB (bb) + EXECUTE_IF_SET_IN_REG_SET (r, 0, i, rsi) { - edge e; - edge_iterator ei; + fprintf (outf, " %d", i); + if (i < FIRST_PSEUDO_REGISTER) + fprintf (outf, " [%s]", + reg_names[i]); + } +} + +/* Print a human-readable representation of R on the standard error + stream. This function is designed to be used from within the + debugger. */ + +void +debug_regset (regset r) +{ + dump_regset (r, stderr); + putc ('\n', stderr); +} + +/* Emit basic block information for BB. HEADER is true if the user wants + the generic information and the predecessors, FOOTER is true if they want + the successors. FLAGS is the dump flags of interest; TDF_DETAILS emit + global register liveness information. PREFIX is put in front of every + line. The output is emitted to FILE. */ +void +dump_bb_info (basic_block bb, bool header, bool footer, int flags, + const char *prefix, FILE *file) +{ + edge e; + edge_iterator ei; - fprintf (file, "\nBasic block %d ", bb->index); - fprintf (file, "prev %d, next %d, ", - bb->prev_bb->index, bb->next_bb->index); - fprintf (file, "loop_depth %d, count ", bb->loop_depth); + if (header) + { + fprintf (file, "\n%sBasic block %d ", prefix, bb->index); + if (bb->prev_bb) + fprintf (file, ", prev %d", bb->prev_bb->index); + if (bb->next_bb) + fprintf (file, ", next %d", bb->next_bb->index); + fprintf (file, ", loop_depth %d, count ", bb->loop_depth); fprintf (file, HOST_WIDEST_INT_PRINT_DEC, bb->count); fprintf (file, ", freq %i", bb->frequency); - if (maybe_hot_bb_p (bb)) + /* Both maybe_hot_bb_p & probably_never_executed_bb_p functions + crash without cfun. */ + if (cfun && maybe_hot_bb_p (bb)) fprintf (file, ", maybe hot"); - if (probably_never_executed_bb_p (bb)) + if (cfun && probably_never_executed_bb_p (bb)) fprintf (file, ", probably never executed"); fprintf (file, ".\n"); - fprintf (file, "Predecessors: "); + fprintf (file, "%sPredecessors: ", prefix); FOR_EACH_EDGE (e, ei, bb->preds) dump_edge_info (file, e, 0); - fprintf (file, "\nSuccessors: "); + if ((flags & TDF_DETAILS) + && (bb->flags & BB_RTL) + && df) + { + fprintf (file, "\n"); + df_dump_top (bb, file); + } + } + + if (footer) + { + fprintf (file, "\n%sSuccessors: ", prefix); FOR_EACH_EDGE (e, ei, bb->succs) dump_edge_info (file, e, 1); - if (bb->flags & BB_RTL) + if ((flags & TDF_DETAILS) + && (bb->flags & BB_RTL) + && df) { - if (bb->il.rtl->global_live_at_start) - { - fprintf (file, "\nRegisters live at start:"); - dump_regset (bb->il.rtl->global_live_at_start, file); - } + fprintf (file, "\n"); + df_dump_bottom (bb, file); + } + } - if (bb->il.rtl->global_live_at_end) - { - fprintf (file, "\nRegisters live at end:"); - dump_regset (bb->il.rtl->global_live_at_end, file); - } + putc ('\n', file); +} + +/* Dump the register info to FILE. */ + +void +dump_reg_info (FILE *file) +{ + unsigned int i, max = max_reg_num (); + if (reload_completed) + return; + + if (reg_info_p_size < max) + max = reg_info_p_size; + + fprintf (file, "%d registers.\n", max); + for (i = FIRST_PSEUDO_REGISTER; i < max; i++) + { + enum reg_class rclass, altclass; + + if (regstat_n_sets_and_refs) + fprintf (file, "\nRegister %d used %d times across %d insns", + i, REG_N_REFS (i), REG_LIVE_LENGTH (i)); + else if (df) + fprintf (file, "\nRegister %d used %d times across %d insns", + i, DF_REG_USE_COUNT (i) + DF_REG_DEF_COUNT (i), REG_LIVE_LENGTH (i)); + + if (REG_BASIC_BLOCK (i) >= NUM_FIXED_BLOCKS) + fprintf (file, " in block %d", REG_BASIC_BLOCK (i)); + if (regstat_n_sets_and_refs) + fprintf (file, "; set %d time%s", REG_N_SETS (i), + (REG_N_SETS (i) == 1) ? "" : "s"); + else if (df) + fprintf (file, "; set %d time%s", DF_REG_DEF_COUNT (i), + (DF_REG_DEF_COUNT (i) == 1) ? "" : "s"); + if (regno_reg_rtx[i] != NULL && REG_USERVAR_P (regno_reg_rtx[i])) + fprintf (file, "; user var"); + if (REG_N_DEATHS (i) != 1) + fprintf (file, "; dies in %d places", REG_N_DEATHS (i)); + if (REG_N_CALLS_CROSSED (i) == 1) + fprintf (file, "; crosses 1 call"); + else if (REG_N_CALLS_CROSSED (i)) + fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i)); + if (REG_FREQ_CALLS_CROSSED (i)) + fprintf (file, "; crosses call with %d frequency", REG_FREQ_CALLS_CROSSED (i)); + if (regno_reg_rtx[i] != NULL + && PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD) + fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i)); + + rclass = reg_preferred_class (i); + altclass = reg_alternate_class (i); + if (rclass != GENERAL_REGS || altclass != ALL_REGS) + { + if (altclass == ALL_REGS || rclass == ALL_REGS) + fprintf (file, "; pref %s", reg_class_names[(int) rclass]); + else if (altclass == NO_REGS) + fprintf (file, "; %s or none", reg_class_names[(int) rclass]); + else + fprintf (file, "; pref %s, else %s", + reg_class_names[(int) rclass], + reg_class_names[(int) altclass]); } + + if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i])) + fprintf (file, "; pointer"); + fprintf (file, ".\n"); + } +} + + +void +dump_flow_info (FILE *file, int flags) +{ + basic_block bb; + + /* There are no pseudo registers after reload. Don't dump them. */ + if (reg_info_p_size && (flags & TDF_DETAILS) != 0) + dump_reg_info (file); - putc ('\n', file); + fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges); + FOR_ALL_BB (bb) + { + dump_bb_info (bb, true, true, flags, "", file); check_bb_profile (bb, file); } @@ -569,17 +671,17 @@ dump_flow_info (FILE *file) void debug_flow_info (void) { - dump_flow_info (stderr); + dump_flow_info (stderr, TDF_DETAILS); } void dump_edge_info (FILE *file, edge e, int do_succ) { basic_block side = (do_succ ? e->dest : e->src); - - if (side == ENTRY_BLOCK_PTR) + /* both ENTRY_BLOCK_PTR & EXIT_BLOCK_PTR depend upon cfun. */ + if (cfun && side == ENTRY_BLOCK_PTR) fputs (" ENTRY", file); - else if (side == EXIT_BLOCK_PTR) + else if (cfun && side == EXIT_BLOCK_PTR) fputs (" EXIT", file); else fprintf (file, " %d", side->index); @@ -657,7 +759,7 @@ alloc_aux_for_blocks (int size) else /* Check whether AUX data are still allocated. */ gcc_assert (!first_block_aux_obj); - + first_block_aux_obj = obstack_alloc (&block_aux_obstack, 0); if (size) { @@ -790,7 +892,9 @@ dump_cfg_bb_info (FILE *file, basic_block bb) bool first = true; static const char * const bb_bitnames[] = { - "dirty", "new", "reachable", "visited", "irreducible_loop", "superblock" + "new", "reachable", "irreducible_loop", "superblock", + "nosched", "hot", "cold", "dup", "xlabel", "rtl", + "fwdr", "nothrd" }; const unsigned n_bitnames = sizeof (bb_bitnames) / sizeof (char *); edge e; @@ -835,7 +939,7 @@ brief_dump_cfg (FILE *file) /* An edge originally destinating BB of FREQUENCY and COUNT has been proved to leave the block by TAKEN_EDGE. Update profile of BB such that edge E can be - redirected to destination of TAKEN_EDGE. + redirected to destination of TAKEN_EDGE. This function may leave the profile inconsistent in the case TAKEN_EDGE frequency or count is believed to be lower than FREQUENCY or COUNT @@ -897,9 +1001,15 @@ update_bb_profile_for_threading (basic_block bb, int edge_frequency, FOR_EACH_EDGE (c, ei, bb->succs) { - c->probability = RDIV (c->probability * scale, 65536); - if (c->probability > REG_BR_PROB_BASE) + /* Protect from overflow due to additional scaling. */ + if (c->probability > prob) c->probability = REG_BR_PROB_BASE; + else + { + c->probability = RDIV (c->probability * scale, 65536); + if (c->probability > REG_BR_PROB_BASE) + c->probability = REG_BR_PROB_BASE; + } } } @@ -923,15 +1033,28 @@ scale_bbs_frequencies_int (basic_block *bbs, int nbbs, int num, int den) edge e; if (num < 0) num = 0; - if (num > den) + + /* Scale NUM and DEN to avoid overflows. Frequencies are in order of + 10^4, if we make DEN <= 10^3, we can afford to upscale by 100 + and still safely fit in int during calculations. */ + if (den > 1000) + { + if (num > 1000000) + return; + + num = RDIV (1000 * num, den); + den = 1000; + } + if (num > 100 * den) return; - /* Assume that the users are producing the fraction from frequencies - that never grow far enough to risk arithmetic overflow. */ - gcc_assert (num < 65536); + for (i = 0; i < nbbs; i++) { edge_iterator ei; bbs[i]->frequency = RDIV (bbs[i]->frequency * num, den); + /* Make sure the frequencies do not grow over BB_FREQ_MAX. */ + if (bbs[i]->frequency > BB_FREQ_MAX) + bbs[i]->frequency = BB_FREQ_MAX; bbs[i]->count = RDIV (bbs[i]->count * num, den); FOR_EACH_EDGE (e, ei, bbs[i]->succs) e->count = RDIV (e->count * num, den); @@ -946,8 +1069,8 @@ scale_bbs_frequencies_int (basic_block *bbs, int nbbs, int num, int den) by NUM/DEN, in gcov_type arithmetic. More accurate than previous function but considerably slower. */ void -scale_bbs_frequencies_gcov_type (basic_block *bbs, int nbbs, gcov_type num, - gcov_type den) +scale_bbs_frequencies_gcov_type (basic_block *bbs, int nbbs, gcov_type num, + gcov_type den) { int i; edge e; @@ -988,6 +1111,9 @@ scale_bbs_frequencies_gcov_type (basic_block *bbs, int nbbs, gcov_type num, copies. */ static htab_t bb_original; static htab_t bb_copy; + +/* And between loops and copies. */ +static htab_t loop_copy; static alloc_pool original_copy_bb_pool; struct htab_bb_copy_original_entry @@ -1001,18 +1127,18 @@ struct htab_bb_copy_original_entry static hashval_t bb_copy_original_hash (const void *p) { - struct htab_bb_copy_original_entry *data - = ((struct htab_bb_copy_original_entry *)p); + const struct htab_bb_copy_original_entry *data + = ((const struct htab_bb_copy_original_entry *)p); return data->index1; } static int bb_copy_original_eq (const void *p, const void *q) { - struct htab_bb_copy_original_entry *data - = ((struct htab_bb_copy_original_entry *)p); - struct htab_bb_copy_original_entry *data2 - = ((struct htab_bb_copy_original_entry *)q); + const struct htab_bb_copy_original_entry *data + = ((const struct htab_bb_copy_original_entry *)p); + const struct htab_bb_copy_original_entry *data2 + = ((const struct htab_bb_copy_original_entry *)q); return data->index1 == data2->index1; } @@ -1029,6 +1155,7 @@ initialize_original_copy_tables (void) bb_original = htab_create (10, bb_copy_original_hash, bb_copy_original_eq, NULL); bb_copy = htab_create (10, bb_copy_original_hash, bb_copy_original_eq, NULL); + loop_copy = htab_create (10, bb_copy_original_hash, bb_copy_original_eq, NULL); } /* Free the data structures to maintain mapping between blocks and @@ -1039,35 +1166,65 @@ free_original_copy_tables (void) gcc_assert (original_copy_bb_pool); htab_delete (bb_copy); htab_delete (bb_original); + htab_delete (loop_copy); free_alloc_pool (original_copy_bb_pool); bb_copy = NULL; bb_original = NULL; + loop_copy = NULL; original_copy_bb_pool = NULL; } +/* Removes the value associated with OBJ from table TAB. */ + +static void +copy_original_table_clear (htab_t tab, unsigned obj) +{ + void **slot; + struct htab_bb_copy_original_entry key, *elt; + + if (!original_copy_bb_pool) + return; + + key.index1 = obj; + slot = htab_find_slot (tab, &key, NO_INSERT); + if (!slot) + return; + + elt = (struct htab_bb_copy_original_entry *) *slot; + htab_clear_slot (tab, slot); + pool_free (original_copy_bb_pool, elt); +} + +/* Sets the value associated with OBJ in table TAB to VAL. + Do nothing when data structures are not initialized. */ + +static void +copy_original_table_set (htab_t tab, unsigned obj, unsigned val) +{ + struct htab_bb_copy_original_entry **slot; + struct htab_bb_copy_original_entry key; + + if (!original_copy_bb_pool) + return; + + key.index1 = obj; + slot = (struct htab_bb_copy_original_entry **) + htab_find_slot (tab, &key, INSERT); + if (!*slot) + { + *slot = (struct htab_bb_copy_original_entry *) + pool_alloc (original_copy_bb_pool); + (*slot)->index1 = obj; + } + (*slot)->index2 = val; +} + /* Set original for basic block. Do nothing when data structures are not initialized so passes not needing this don't need to care. */ void set_bb_original (basic_block bb, basic_block original) { - if (original_copy_bb_pool) - { - struct htab_bb_copy_original_entry **slot; - struct htab_bb_copy_original_entry key; - - key.index1 = bb->index; - slot = - (struct htab_bb_copy_original_entry **) htab_find_slot (bb_original, - &key, INSERT); - if (*slot) - (*slot)->index2 = original->index; - else - { - *slot = pool_alloc (original_copy_bb_pool); - (*slot)->index1 = bb->index; - (*slot)->index2 = original->index; - } - } + copy_original_table_set (bb_original, bb->index, original->index); } /* Get the original basic block. */ @@ -1092,24 +1249,7 @@ get_bb_original (basic_block bb) void set_bb_copy (basic_block bb, basic_block copy) { - if (original_copy_bb_pool) - { - struct htab_bb_copy_original_entry **slot; - struct htab_bb_copy_original_entry key; - - key.index1 = bb->index; - slot = - (struct htab_bb_copy_original_entry **) htab_find_slot (bb_copy, - &key, INSERT); - if (*slot) - (*slot)->index2 = copy->index; - else - { - *slot = pool_alloc (original_copy_bb_pool); - (*slot)->index1 = bb->index; - (*slot)->index2 = copy->index; - } - } + copy_original_table_set (bb_copy, bb->index, copy->index); } /* Get the copy of basic block. */ @@ -1128,3 +1268,33 @@ get_bb_copy (basic_block bb) else return NULL; } + +/* Set copy for LOOP to COPY. Do nothing when data structures are not + initialized so passes not needing this don't need to care. */ + +void +set_loop_copy (struct loop *loop, struct loop *copy) +{ + if (!copy) + copy_original_table_clear (loop_copy, loop->num); + else + copy_original_table_set (loop_copy, loop->num, copy->num); +} + +/* Get the copy of LOOP. */ + +struct loop * +get_loop_copy (struct loop *loop) +{ + struct htab_bb_copy_original_entry *entry; + struct htab_bb_copy_original_entry key; + + gcc_assert (original_copy_bb_pool); + + key.index1 = loop->num; + entry = (struct htab_bb_copy_original_entry *) htab_find (loop_copy, &key); + if (entry) + return get_loop (entry->index2); + else + return NULL; +}