Hi, This is mostly a small memory and pointer-chasing cleanup. We always know exactly what form an assignment takes so there is no need to record assignments as SET-rtxen.
Bootstrapped and tested on x86_64-unknown-linux-gnu. OK? Ciao! Steven
* cprop.c (struct expr): Split 'expr' field in 'dest' and 'src'. (expr_equiv_p): Remove. (insert_set_in_table): Look at <dest, src> pair instead of expr. (hash_scan_set): Update call to insert_set_in_table. (dump_hash_table): Dump <dest, src> pair. (lookup_set): Simplify. Lookup <dest, src> pair. (compute_transp): Remove, fold heavily simplified code into... (compute_local_properties): ...here. Expect COMP and TRANSP unconditionally. (find_avail_set): Take set directly from struct expr. (find_bypass-set): Likewise. (bypass_block): Likewise. (cprop_insn): Likewise. Remove redundant INSN_P test. *** cprop.c.v5 2011-04-02 00:56:57.000000000 +0200 --- cprop.c.v6 2011-04-02 15:54:38.000000000 +0200 *************** static struct obstack cprop_obstack; *** 55,77 **** struct reg_use {rtx reg_rtx; }; - /* Hash table of expressions. */ - - struct expr - { - /* The expression (SET_SRC for expressions, PATTERN for assignments). */ - rtx expr; - /* Index in the available expression bitmaps. */ - int bitmap_index; - /* Next entry with the same hash. */ - struct expr *next_same_hash; - /* List of available occurrence in basic blocks in the function. - An "available occurrence" is one that is the last occurrence in the - basic block and the operands are not modified by following statements in - the basic block [including this insn]. */ - struct occr *avail_occr; - }; - /* Occurrence of an expression. There is one per basic block. If a pattern appears more than once the last appearance is used. */ --- 55,60 ---- *************** typedef struct occr *occr_t; *** 88,94 **** DEF_VEC_P (occr_t); DEF_VEC_ALLOC_P (occr_t, heap); ! /* Expression and copy propagation hash tables. Each hash table is an array of buckets. ??? It is known that if it were an array of entries, structure elements `next_same_hash' and `bitmap_index' wouldn't be necessary. However, it is --- 71,96 ---- DEF_VEC_P (occr_t); DEF_VEC_ALLOC_P (occr_t, heap); ! /* Hash table entry for an assignment expressions. */ ! ! struct expr ! { ! /* The expression (DEST := SRC). */ ! rtx dest; ! rtx src; ! ! /* Index in the available expression bitmaps. */ ! int bitmap_index; ! /* Next entry with the same hash. */ ! struct expr *next_same_hash; ! /* List of available occurrence in basic blocks in the function. ! An "available occurrence" is one that is the last occurrence in the ! basic block and the operands are not modified by following statements in ! the basic block [including this insn]. */ ! struct occr *avail_occr; ! }; ! ! /* Hash table for copy propagation expressions. Each hash table is an array of buckets. ??? It is known that if it were an array of entries, structure elements `next_same_hash' and `bitmap_index' wouldn't be necessary. However, it is *************** hash_set (int regno, int hash_table_size *** 175,214 **** return hash % hash_table_size; } ! /* Return nonzero if exp1 is equivalent to exp2. */ ! ! static int ! expr_equiv_p (const_rtx x, const_rtx y) ! { ! return exp_equiv_p (x, y, 0, true); ! } ! ! /* Insert pattern X in INSN in the hash table. ! X is a SET of a reg to either another reg or a constant. ! If it is already present, record it as the last occurrence in INSN's ! basic block. */ static void ! insert_set_in_table (rtx x, rtx insn, struct hash_table_d *table) { ! int found; unsigned int hash; struct expr *cur_expr, *last_expr = NULL; struct occr *cur_occr; ! gcc_assert (GET_CODE (x) == SET && REG_P (SET_DEST (x))); ! ! hash = hash_set (REGNO (SET_DEST (x)), table->size); ! cur_expr = table->table[hash]; ! found = 0; ! ! while (cur_expr && 0 == (found = expr_equiv_p (cur_expr->expr, x))) { ! /* If the expression isn't found, save a pointer to the end of ! the list. */ last_expr = cur_expr; - cur_expr = cur_expr->next_same_hash; } if (! found) --- 177,207 ---- return hash % hash_table_size; } ! /* Insert assignment DEST:=SET from INSN in the hash table. ! DEST is a register and SET is a register or a suitable constant. ! If the assignment is already present in the table, record it as ! the last occurrence in INSN's basic block. */ static void ! insert_set_in_table (rtx dest, rtx src, rtx insn, struct hash_table_d *table) { ! bool found = false; unsigned int hash; struct expr *cur_expr, *last_expr = NULL; struct occr *cur_occr; ! hash = hash_set (REGNO (dest), table->size); ! for (cur_expr = table->table[hash]; cur_expr; ! cur_expr = cur_expr->next_same_hash) { ! if (dest == cur_expr->dest ! && src == cur_expr->src) ! { ! found = true; ! break; ! } last_expr = cur_expr; } if (! found) *************** insert_set_in_table (rtx x, rtx insn, st *** 225,231 **** /* Set the fields of the expr element. We must copy X because it can be modified when copy propagation is performed on its operands. */ ! cur_expr->expr = copy_rtx (x); cur_expr->bitmap_index = table->n_elems++; cur_expr->next_same_hash = NULL; cur_expr->avail_occr = NULL; --- 218,225 ---- /* Set the fields of the expr element. We must copy X because it can be modified when copy propagation is performed on its operands. */ ! cur_expr->dest = copy_rtx (dest); ! cur_expr->src = copy_rtx (src); cur_expr->bitmap_index = table->n_elems++; cur_expr->next_same_hash = NULL; cur_expr->avail_occr = NULL; *************** hash_scan_set (rtx pat, rtx insn, struct *** 290,296 **** 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. */ rtx note = find_reg_equal_equiv_note (insn); if (note != 0 && REG_NOTE_KIND (note) == REG_EQUAL --- 284,290 ---- for INSN, we miss copy propagation opportunities. Note that this does not impede profitable constant propagations. We ! "look through" reg-reg sets in lookup_set. */ rtx note = find_reg_equal_equiv_note (insn); if (note != 0 && REG_NOTE_KIND (note) == REG_EQUAL *************** hash_scan_set (rtx pat, rtx insn, struct *** 304,310 **** && ! HARD_REGISTER_P (src) && reg_available_p (src, insn)) || cprop_constant_p (src)) ! insert_set_in_table (pat, insn, table); } } --- 298,304 ---- && ! HARD_REGISTER_P (src) && reg_available_p (src, insn)) || cprop_constant_p (src)) ! insert_set_in_table (dest, src, insn, table); } } *************** dump_hash_table (FILE *file, const char *** 368,374 **** expr = flat_table[i]; fprintf (file, "Index %d (hash value %d)\n ", expr->bitmap_index, hash_val[i]); ! print_rtl (file, expr->expr); fprintf (file, "\n"); } --- 362,370 ---- expr = flat_table[i]; fprintf (file, "Index %d (hash value %d)\n ", expr->bitmap_index, hash_val[i]); ! print_rtl (file, expr->dest); ! fprintf (file, " := "); ! print_rtl (file, expr->src); fprintf (file, "\n"); } *************** lookup_set (unsigned int regno, struct h *** 497,503 **** expr = table->table[hash]; ! while (expr && REGNO (SET_DEST (expr->expr)) != regno) expr = expr->next_same_hash; return expr; --- 493,499 ---- expr = table->table[hash]; ! while (expr && REGNO (expr->dest) != regno) expr = expr->next_same_hash; return expr; *************** next_set (unsigned int regno, struct exp *** 510,516 **** { do expr = expr->next_same_hash; ! while (expr && REGNO (SET_DEST (expr->expr)) != regno); return expr; } --- 506,512 ---- { do expr = expr->next_same_hash; ! while (expr && REGNO (expr->dest) != regno); return expr; } *************** free_cprop_mem (void) *** 583,658 **** sbitmap_vector_free (cprop_avout); } - /* For each block, compute whether X is transparent. X is either an - expression or an assignment [though we don't care which, for this context - an assignment is treated as an expression]. For each block where an - element of X is modified, set the INDX bit in BMAP. */ - - static void - compute_transp (const_rtx x, int indx, sbitmap *bmap) - { - int i, j; - enum rtx_code code; - const char *fmt; - - /* repeat is used to turn tail-recursion into iteration since GCC - can't do it when there's no return value. */ - repeat: - - if (x == 0) - return; - - code = GET_CODE (x); - switch (code) - { - case REG: - { - df_ref def; - for (def = DF_REG_DEF_CHAIN (REGNO (x)); - def; - def = DF_REF_NEXT_REG (def)) - SET_BIT (bmap[DF_REF_BB (def)->index], indx); - } - return; - - 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; - - default: - break; - } - - for (i = GET_RTX_LENGTH (code) - 1, fmt = GET_RTX_FORMAT (code); i >= 0; i--) - { - if (fmt[i] == 'e') - { - /* If we are about to do the last recursive call - needed at this level, change it into iteration. - This function is called enough to be worth it. */ - if (i == 0) - { - x = XEXP (x, i); - goto repeat; - } - - compute_transp (XEXP (x, i), indx, bmap); - } - else if (fmt[i] == 'E') - for (j = 0; j < XVECLEN (x, i); j++) - compute_transp (XVECEXP (x, i, j), indx, bmap); - } - } - /* Compute the local properties of each recorded expression. Local properties are those that are defined by the block, irrespective of --- 579,584 ---- *************** compute_transp (const_rtx x, int indx, s *** 665,675 **** at least once and expression would contain the same value if the computation was moved to the end of the block. ! TRANSP and COMP are destination sbitmaps for recording local properties. ! If NULL, then it is not necessary to compute or record that particular ! property. ! ! TRANSP is computed as ~TRANSP, since this is really cprop's ABSALTERED. */ static void compute_local_properties (sbitmap *transp, sbitmap *comp, --- 591,597 ---- at least once and expression would contain the same value if the computation was moved to the end of the block. ! TRANSP and COMP are destination sbitmaps for recording local properties. */ static void compute_local_properties (sbitmap *transp, sbitmap *comp, *************** compute_local_properties (sbitmap *trans *** 677,690 **** { unsigned int i; ! /* Initialize any bitmaps that were passed in. */ ! if (transp) ! { ! sbitmap_vector_zero (transp, last_basic_block); ! } ! ! if (comp) ! sbitmap_vector_zero (comp, last_basic_block); for (i = 0; i < table->size; i++) { --- 599,607 ---- { unsigned int i; ! /* Initialize the bitmaps that were passed in. */ ! sbitmap_vector_zero (transp, last_basic_block); ! sbitmap_vector_zero (comp, last_basic_block); for (i = 0; i < table->size; i++) { *************** compute_local_properties (sbitmap *trans *** 693,713 **** for (expr = table->table[i]; expr != NULL; expr = expr->next_same_hash) { int indx = expr->bitmap_index; struct occr *occr; ! /* The expression is transparent in this block if it is not killed. ! We start by assuming all are transparent [none are killed], and ! then reset the bits for those that are. */ ! if (transp) ! compute_transp (expr->expr, indx, transp); /* The occurrences recorded in avail_occr are exactly those that we want to set to nonzero in COMP. */ ! if (comp) ! for (occr = expr->avail_occr; occr != NULL; occr = occr->next) ! { ! SET_BIT (comp[BLOCK_FOR_INSN (occr->insn)->index], indx); ! } } } } --- 610,636 ---- for (expr = table->table[i]; expr != NULL; expr = expr->next_same_hash) { int indx = expr->bitmap_index; + df_ref def; struct occr *occr; ! /* The expression is transparent in a block if it is not killed, ! i.e. DEST and SRC are not set or clobbered in the block. ! We start by assuming all are transparent [none are killed], ! and then set the bits for those that are. */ ! for (def = DF_REG_DEF_CHAIN (REGNO (expr->dest)); ! def; def = DF_REF_NEXT_REG (def)) ! SET_BIT (transp[DF_REF_BB (def)->index], indx); ! if (REG_P (expr->src)) ! for (def = DF_REG_DEF_CHAIN (REGNO (expr->src)); ! def; def = DF_REF_NEXT_REG (def)) ! SET_BIT (transp[DF_REF_BB (def)->index], indx); /* The occurrences recorded in avail_occr are exactly those that we want to set to nonzero in COMP. */ ! for (occr = expr->avail_occr; occr != NULL; occr = occr->next) ! { ! SET_BIT (comp[BLOCK_FOR_INSN (occr->insn)->index], indx); ! } } } } *************** find_avail_set (int regno, rtx insn) *** 892,900 **** if (set == 0) break; ! gcc_assert (GET_CODE (set->expr) == SET); ! ! src = SET_SRC (set->expr); /* We know the set is available. Now check that SRC is locally anticipatable (i.e. none of the --- 815,821 ---- if (set == 0) break; ! src = set->src; /* We know the set is available. Now check that SRC is locally anticipatable (i.e. none of the *************** cprop_insn (rtx insn) *** 1080,1094 **** int changed = 0; rtx note; - if (!INSN_P (insn)) - return 0; - reg_use_count = 0; note_uses (&PATTERN (insn), find_used_regs, NULL); - note = find_reg_equal_equiv_note (insn); - /* We may win even when propagating constants into notes. */ if (note) find_used_regs (&XEXP (note, 0), NULL); --- 1001,1011 ---- int changed = 0; rtx note; reg_use_count = 0; note_uses (&PATTERN (insn), find_used_regs, NULL); /* We may win even when propagating constants into notes. */ + note = find_reg_equal_equiv_note (insn); if (note) find_used_regs (&XEXP (note, 0), NULL); *************** cprop_insn (rtx insn) *** 1096,1102 **** reg_used++, reg_use_count--) { unsigned int regno = REGNO (reg_used->reg_rtx); ! rtx pat, src; struct expr *set; /* If the register has already been set in this block, there's --- 1013,1019 ---- reg_used++, reg_use_count--) { unsigned int regno = REGNO (reg_used->reg_rtx); ! rtx src; struct expr *set; /* If the register has already been set in this block, there's *************** cprop_insn (rtx insn) *** 1110,1120 **** if (! set) continue; ! pat = set->expr; ! /* ??? We might be able to handle PARALLELs. Later. */ ! gcc_assert (GET_CODE (pat) == SET); ! ! src = SET_SRC (pat); /* Constant propagation. */ if (cprop_constant_p (src)) --- 1027,1033 ---- if (! set) continue; ! src = set->src; /* Constant propagation. */ if (cprop_constant_p (src)) *************** cprop_insn (rtx insn) *** 1150,1156 **** } /* The original insn setting reg_used may or may not now be ! deletable. We leave the deletion to flow. */ /* FIXME: If it turns out that the insn isn't deletable, then we may have unnecessarily extended register lifetimes and made things worse. */ --- 1063,1069 ---- } /* The original insn setting reg_used may or may not now be ! deletable. We leave the deletion to DCE. */ /* FIXME: If it turns out that the insn isn't deletable, then we may have unnecessarily extended register lifetimes and made things worse. */ *************** find_bypass_set (int regno, int bb) *** 1502,1510 **** if (set == 0) break; ! gcc_assert (GET_CODE (set->expr) == SET); ! ! src = SET_SRC (set->expr); if (cprop_constant_p (src)) result = set; --- 1415,1421 ---- if (set == 0) break; ! src = set->src; if (cprop_constant_p (src)) result = set; *************** bypass_block (basic_block bb, rtx setcc, *** 1625,1631 **** SET_SRC (PATTERN (setcc))); new_rtx = simplify_replace_rtx (src, reg_used->reg_rtx, ! SET_SRC (set->expr)); /* Jump bypassing may have already placed instructions on edges of the CFG. We can't bypass an outgoing edge that --- 1536,1542 ---- SET_SRC (PATTERN (setcc))); new_rtx = simplify_replace_rtx (src, reg_used->reg_rtx, ! set->src); /* Jump bypassing may have already placed instructions on edges of the CFG. We can't bypass an outgoing edge that *************** bypass_block (basic_block bb, rtx setcc, *** 1677,1683 **** fprintf (dump_file, "JUMP-BYPASS: Proved reg %d " "in jump_insn %d equals constant ", regno, INSN_UID (jump)); ! print_rtl (dump_file, SET_SRC (set->expr)); fprintf (dump_file, "\nBypass edge from %d->%d to %d\n", e->src->index, old_dest->index, dest->index); } --- 1588,1594 ---- fprintf (dump_file, "JUMP-BYPASS: Proved reg %d " "in jump_insn %d equals constant ", regno, INSN_UID (jump)); ! print_rtl (dump_file, set->src); fprintf (dump_file, "\nBypass edge from %d->%d to %d\n", e->src->index, old_dest->index, dest->index); }