From 7d11cebe9a4c0ca58d956644027ab7d9b93b8157 Mon Sep 17 00:00:00 2001 From: Steven Bosscher Date: Thu, 31 Mar 2011 19:48:11 +0000 Subject: [PATCH] cprop.c: Clean up hash table building. * cprop.c: Clean up hash table building. (reg_avail_info): Remove. (oprs_available_p): Remove. (record_last_reg_set_info): Remove. (record_last_set_info): Remove. (reg_available_p): New function. (gcse_constant_p): Do not treat unfolded conditions as constants. (make_set_regs_unavailable): New function. (hash_scan_set): Simplify with new reg_available_p. (compute_hash_table_work): Traverse insns stream only once. Do not compute reg_avail_info. Traverse insns in reverse order. Record implicit sets after recording explicit sets from the block. From-SVN: r171794 --- gcc/ChangeLog | 15 ++++ gcc/cprop.c | 221 +++++++++++--------------------------------------- 2 files changed, 61 insertions(+), 175 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index aee2430889b..a0ba31aa4b2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2011-03-31 Steven Bosscher + + * cprop.c: Clean up hash table building. + (reg_avail_info): Remove. + (oprs_available_p): Remove. + (record_last_reg_set_info): Remove. + (record_last_set_info): Remove. + (reg_available_p): New function. + (gcse_constant_p): Do not treat unfolded conditions as constants. + (make_set_regs_unavailable): New function. + (hash_scan_set): Simplify with new reg_available_p. + (compute_hash_table_work): Traverse insns stream only once. + Do not compute reg_avail_info. Traverse insns in reverse order. + Record implicit sets after recording explicit sets from the block. + 2011-03-31 Michael Matz * builtins.c (build_va_arg_indirect_ref): Use diff --git a/gcc/cprop.c b/gcc/cprop.c index 7e035af86e2..7d06e7be26d 100644 --- a/gcc/cprop.c +++ b/gcc/cprop.c @@ -118,7 +118,7 @@ static rtx *implicit_sets; /* Bitmap containing one bit for each register in the program. Used when performing GCSE to track which registers have been set since - the start of the basic block. */ + the start or end of the basic block while traversing that block. */ static regset reg_set_bitmap; /* Various variables for statistics gathering. */ @@ -183,79 +183,13 @@ free_gcse_mem (void) FREE_REG_SET (reg_set_bitmap); } -struct reg_avail_info -{ - basic_block last_bb; - int last_set; -}; - -static struct reg_avail_info *reg_avail_info; -static basic_block current_bb; - -/* Return nonzero if the operands of expression X are unchanged from - INSN to the end of INSN's basic block. */ +/* Return nonzero if register X is unchanged from INSN to the end + of INSN's basic block. */ static int -oprs_available_p (const_rtx x, const_rtx insn) +reg_available_p (const_rtx x, const_rtx insn ATTRIBUTE_UNUSED) { - int i, j; - enum rtx_code code; - const char *fmt; - - if (x == 0) - return 1; - - code = GET_CODE (x); - switch (code) - { - case REG: - { - struct reg_avail_info *info = ®_avail_info[REGNO (x)]; - - if (info->last_bb != current_bb) - return 1; - return info->last_set < DF_INSN_LUID (insn); - } - - case PRE_DEC: - case PRE_INC: - case POST_DEC: - case POST_INC: - case PRE_MODIFY: - case POST_MODIFY: - return 0; - - case PC: - case CC0: /*FIXME*/ - case CONST: - case CONST_INT: - case CONST_DOUBLE: - case CONST_FIXED: - case CONST_VECTOR: - case SYMBOL_REF: - case LABEL_REF: - case ADDR_VEC: - case ADDR_DIFF_VEC: - return 1; - - default: - break; - } - - for (i = GET_RTX_LENGTH (code) - 1, fmt = GET_RTX_FORMAT (code); i >= 0; i--) - { - if (fmt[i] == 'e') - { - if (! oprs_available_p (XEXP (x, i), insn)) - return 0; - } - else if (fmt[i] == 'E') - for (j = 0; j < XVECLEN (x, i); j++) - if (! oprs_available_p (XVECEXP (x, i, j), insn)) - return 0; - } - - return 1; + return ! REGNO_REG_SET_P (reg_set_bitmap, REGNO (x)); } /* Hash a set of register REGNO. @@ -353,29 +287,13 @@ insert_set_in_table (rtx x, rtx insn, struct hash_table_d *table) } } -/* Determine whether the rtx X should be treated as a constant for - the purposes of GCSE's constant propagation. */ +/* Determine whether the rtx X should be treated as a constant for CPROP. + Since X might be inserted more than once we have to take care that it + is sharable. */ static bool gcse_constant_p (const_rtx x) { - /* Consider a COMPARE of two integers constant. */ - if (GET_CODE (x) == COMPARE - && CONST_INT_P (XEXP (x, 0)) - && CONST_INT_P (XEXP (x, 1))) - return true; - - /* Consider a COMPARE of the same registers is a constant - if they are not floating point registers. */ - if (GET_CODE(x) == COMPARE - && REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1)) - && REGNO (XEXP (x, 0)) == REGNO (XEXP (x, 1)) - && ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0))) - && ! FLOAT_MODE_P (GET_MODE (XEXP (x, 1)))) - return true; - - /* Since X might be inserted more than once we have to take care that it - is sharable. */ return CONSTANT_P (x) && (GET_CODE (x) != CONST || shared_const_p (x)); } @@ -387,29 +305,26 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table) { rtx src = SET_SRC (pat); rtx dest = SET_DEST (pat); - rtx note; - if (REG_P (dest)) + if (REG_P (dest) + && ! HARD_REGISTER_P (dest) + && reg_available_p (dest, insn) + && can_copy_p (GET_MODE (dest))) { - unsigned int regno = REGNO (dest); - rtx tmp; - /* See if a REG_EQUAL note shows this equivalent to a simpler expression. - This allows us to do a single GCSE pass and still eliminate + This allows us to do a single CPROP pass and still eliminate redundant constants, addresses or other expressions that are constructed with multiple instructions. However, keep the original SRC if INSN is a simple reg-reg move. In In this case, there will almost always be a REG_EQUAL note on the insn that sets SRC. By recording the REG_EQUAL value here as SRC - for INSN, we miss copy propagation opportunities and we perform the - same PRE GCSE operation repeatedly on the same REG_EQUAL value if we - do more than one PRE GCSE pass. + for INSN, we miss copy propagation opportunities. Note that this does not impede profitable constant propagations. We "look through" reg-reg sets in lookup_avail_set. */ - note = find_reg_equal_equiv_note (insn); + rtx note = find_reg_equal_equiv_note (insn); if (note != 0 && REG_NOTE_KIND (note) == REG_EQUAL && !REG_P (src) @@ -417,19 +332,11 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table) src = XEXP (note, 0), pat = gen_rtx_SET (VOIDmode, dest, src); /* Record sets for constant/copy propagation. */ - if (regno >= FIRST_PSEUDO_REGISTER - && ((REG_P (src) - && REGNO (src) >= FIRST_PSEUDO_REGISTER - && can_copy_p (GET_MODE (dest)) - && REGNO (src) != regno) - || gcse_constant_p (src)) - /* A copy is not available if its src or dest is subsequently - modified. Here we want to search from INSN+1 on, but - oprs_available_p searches from INSN on. */ - && (insn == BB_END (BLOCK_FOR_INSN (insn)) - || (tmp = next_nonnote_nondebug_insn (insn)) == NULL_RTX - || BLOCK_FOR_INSN (tmp) != BLOCK_FOR_INSN (insn) - || oprs_available_p (pat, tmp))) + if ((REG_P (src) + && src != dest + && ! HARD_REGISTER_P (src) + && reg_available_p (src, insn)) + || gcse_constant_p (src)) insert_set_in_table (pat, insn, table); } } @@ -504,39 +411,15 @@ dump_hash_table (FILE *file, const char *name, struct hash_table_d *table) free (hash_val); } -/* Record register first/last/block set information for REGNO in INSN. - - last_set records the last place in the block where the register - is set and is used to compute "availability". - - last_bb records the block for which last_set is valid, as a quick - test to invalidate it. */ - +/* Record as unavailable all registers that are DEF operands of INSN. */ static void -record_last_reg_set_info (rtx insn, int regno) +make_set_regs_unavailable (rtx insn) { - struct reg_avail_info *info = ®_avail_info[regno]; - int luid = DF_INSN_LUID (insn); + struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn); + df_ref *def_rec; - info->last_set = luid; - if (info->last_bb != current_bb) - info->last_bb = current_bb; -} - -/* Called from compute_hash_table via note_stores to handle one - SET or CLOBBER in an insn. DATA is really the instruction in which - the SET is taking place. */ - -static void -record_last_set_info (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, void *data) -{ - rtx last_set_insn = (rtx) data; - - if (GET_CODE (dest) == SUBREG) - dest = SUBREG_REG (dest); - - if (REG_P (dest)) - record_last_reg_set_info (last_set_insn, REGNO (dest)); + for (def_rec = DF_INSN_INFO_DEFS (insn_info); *def_rec; def_rec++) + SET_REGNO_REG_SET (reg_set_bitmap, DF_REF_REGNO (*def_rec)); } /* Top level function to create an assignments hash table. @@ -553,49 +436,37 @@ record_last_set_info (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, void *data) static void compute_hash_table_work (struct hash_table_d *table) { - int i; + basic_block bb; - /* Some working arrays used to track first and last set in each block. */ - reg_avail_info = GNEWVEC (struct reg_avail_info, max_reg_num ()); - - for (i = 0; i < max_reg_num (); ++i) - reg_avail_info[i].last_bb = NULL; - - FOR_EACH_BB (current_bb) + FOR_EACH_BB (bb) { rtx insn; - unsigned int regno; - /* First pass over the instructions records information used to - determine when registers and memory are first and last set. */ - FOR_BB_INSNS (current_bb, insn) - { + /* Reset tables used to keep track of what's not yet invalid [since + the end of the block]. */ + CLEAR_REG_SET (reg_set_bitmap); + + /* Go over all insns from the last to the first. This is convenient + for tracking available registers, i.e. not set between INSN and + the end of the basic block BB. */ + FOR_BB_INSNS_REVERSE (bb, insn) + { + /* Only real insns are interesting. */ if (!NONDEBUG_INSN_P (insn)) continue; - if (CALL_P (insn)) - { - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno)) - record_last_reg_set_info (insn, regno); - } + /* Record interesting sets from INSN in the hash table. */ + hash_scan_insn (insn, table); - note_stores (PATTERN (insn), record_last_set_info, insn); + /* Any registers set in INSN will make SETs above it not AVAIL. */ + make_set_regs_unavailable (insn); } - /* Insert implicit sets in the hash table. */ - if (implicit_sets[current_bb->index] != NULL_RTX) - hash_scan_set (implicit_sets[current_bb->index], - BB_HEAD (current_bb), table); - - /* The next pass builds the hash table. */ - FOR_BB_INSNS (current_bb, insn) - if (NONDEBUG_INSN_P (insn)) - hash_scan_insn (insn, table); + /* Insert implicit sets in the hash table, pretending they appear as + insns at the head of the basic block. */ + if (implicit_sets[bb->index] != NULL_RTX) + hash_scan_set (implicit_sets[bb->index], BB_HEAD (bb), table); } - - free (reg_avail_info); - reg_avail_info = NULL; } /* Allocate space for the set/expr hash TABLE.