diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3b384483790..dbb46a56218 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2000-11-30 Michael Matz + + * flow.c (make_edge): Early out, if no flags to set. + (calculate_global_regs_live): Clear out garbage only when necessary. + + * simplify-rtx.c (varray_type used_regs): New. + (clear_table): Use it to only clear necessary items. + (cselib_lookup, cselib_record_set): Remember newly set items. + (cselib_update_varray_sizes, cselib_init): Initialize and grow + used_regs. + + * local-alloc.c (update_equiv_regs): New local `cleared_regs'. + Move clearing of dead regs out of insn-loop. + 2000-11-30 Richard Henderson * calls.c (expand_call): Emit queued insns before creating diff --git a/gcc/flow.c b/gcc/flow.c index 1e370827486..4aacbf8413e 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -1262,13 +1262,27 @@ make_edge (edge_cache, src, dst, flags) && dst != EXIT_BLOCK_PTR); /* Make sure we don't add duplicate edges. */ - if (! use_edge_cache || TEST_BIT (edge_cache[src->index], dst->index)) - for (e = src->succ; e; e = e->succ_next) - if (e->dest == dst) - { - e->flags |= flags; - return; - } + switch (use_edge_cache) + { + default: + /* Quick test for non-existance of the edge. */ + if (! TEST_BIT (edge_cache[src->index], dst->index)) + break; + + /* The edge exists; early exit if no work to do. */ + if (flags == 0) + return; + + /* FALLTHRU */ + case 0: + for (e = src->succ; e; e = e->succ_next) + if (e->dest == dst) + { + e->flags |= flags; + return; + } + break; + } e = (edge) xcalloc (1, sizeof (*e)); n_edges++; @@ -3306,15 +3320,15 @@ calculate_global_regs_live (blocks_in, blocks_out, flags) qtail = queue; qhead = qend = queue + n_basic_blocks + 2; - /* Clear out the garbage that might be hanging out in bb->aux. */ - for (i = n_basic_blocks - 1; i >= 0; --i) - BASIC_BLOCK (i)->aux = NULL; - /* Queue the blocks set in the initial mask. Do this in reverse block number order so that we are more likely for the first round to do useful work. We use AUX non-null to flag that the block is queued. */ if (blocks_in) { + /* Clear out the garbage that might be hanging out in bb->aux. */ + for (i = n_basic_blocks - 1; i >= 0; --i) + BASIC_BLOCK (i)->aux = NULL; + EXECUTE_IF_SET_IN_SBITMAP (blocks_in, 0, i, { basic_block bb = BASIC_BLOCK (i); diff --git a/gcc/local-alloc.c b/gcc/local-alloc.c index ac2183e02f4..62142f04c38 100644 --- a/gcc/local-alloc.c +++ b/gcc/local-alloc.c @@ -804,8 +804,11 @@ update_equiv_regs () rtx insn; int block; int loop_depth; + regset_head cleared_regs; + int clear_regnos = 0; reg_equiv = (struct equivalence *) xcalloc (max_regno, sizeof *reg_equiv); + INIT_REG_SET (&cleared_regs); init_alias_analysis (); @@ -1135,7 +1138,6 @@ update_equiv_regs () INSN. Update the flow information. */ else if (PREV_INSN (insn) != equiv_insn) { - int l; rtx new_insn; new_insn = emit_insn_before (copy_rtx (PATTERN (equiv_insn)), @@ -1156,22 +1158,43 @@ update_equiv_regs () if (block >= 0 && insn == BLOCK_HEAD (block)) BLOCK_HEAD (block) = PREV_INSN (insn); - for (l = 0; l < n_basic_blocks; l++) - { - CLEAR_REGNO_REG_SET ( - BASIC_BLOCK (l)->global_live_at_start, - regno); - CLEAR_REGNO_REG_SET ( - BASIC_BLOCK (l)->global_live_at_end, - regno); - } + /* Remember to clear REGNO from all basic block's live + info. */ + SET_REGNO_REG_SET (&cleared_regs, regno); + clear_regnos++; } } } } + /* Clear all dead REGNOs from all basic block's live info. */ + if (clear_regnos) + { + int j, l; + if (clear_regnos > 8) + { + for (l = 0; l < n_basic_blocks; l++) + { + AND_COMPL_REG_SET (BASIC_BLOCK (l)->global_live_at_start, + &cleared_regs); + AND_COMPL_REG_SET (BASIC_BLOCK (l)->global_live_at_end, + &cleared_regs); + } + } + else + EXECUTE_IF_SET_IN_REG_SET (&cleared_regs, 0, j, + { + for (l = 0; l < n_basic_blocks; l++) + { + CLEAR_REGNO_REG_SET (BASIC_BLOCK (l)->global_live_at_start, j); + CLEAR_REGNO_REG_SET (BASIC_BLOCK (l)->global_live_at_end, j); + } + }); + } + /* Clean up. */ end_alias_analysis (); + CLEAR_REG_SET (&cleared_regs); free (reg_equiv); } diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 08ceaf7fc10..ae15b087d4d 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -111,7 +111,7 @@ static struct elt_loc_list *new_elt_loc_list PARAMS ((struct elt_loc_list *, static void unchain_one_value PARAMS ((cselib_val *)); static void unchain_one_elt_list PARAMS ((struct elt_list **)); static void unchain_one_elt_loc_list PARAMS ((struct elt_loc_list **)); -static void clear_table PARAMS ((void)); +static void clear_table PARAMS ((int)); static int discard_useless_locs PARAMS ((void **, void *)); static int discard_useless_values PARAMS ((void **, void *)); static void remove_useless_values PARAMS ((void)); @@ -168,6 +168,10 @@ static int n_useless_values; static varray_type reg_values; #define REG_VALUES(I) VARRAY_ELT_LIST (reg_values, (I)) +/* Here the set of indices I with REG_VALUES(I) != 0 is saved. This is used + in clear_table() for fast emptying. */ +static varray_type used_regs; + /* We pass this to cselib_invalidate_mem to invalidate all of memory for a non-const call instruction. */ static rtx callmem; @@ -2200,15 +2204,23 @@ unchain_one_value (v) } /* Remove all entries from the hash table. Also used during - initialization. */ + initialization. If CLEAR_ALL isn't set, then only clear the entries + which are known to have been used. */ static void -clear_table () +clear_table (clear_all) + int clear_all; { unsigned int i; - for (i = 0; i < cselib_nregs; i++) - REG_VALUES (i) = 0; + if (clear_all) + for (i = 0; i < cselib_nregs; i++) + REG_VALUES (i) = 0; + else + for (i = 0; i < VARRAY_ACTIVE_SIZE (used_regs); i++) + REG_VALUES (VARRAY_UINT (used_regs, i)) = 0; + + VARRAY_POP_ALL (used_regs); htab_empty (hash_table); obstack_free (&cselib_obstack, cselib_startobj); @@ -2867,6 +2879,8 @@ cselib_lookup (x, mode, create) e = new_cselib_val (++next_unknown_value, GET_MODE (x)); e->locs = new_elt_loc_list (e->locs, x); + if (REG_VALUES (i) == 0) + VARRAY_PUSH_UINT (used_regs, i); REG_VALUES (i) = new_elt_list (REG_VALUES (i), e); slot = htab_find_slot_with_hash (hash_table, x, e->value, INSERT); *slot = e; @@ -3133,6 +3147,9 @@ cselib_record_set (dest, src_elt, dest_addr_elt) if (dreg >= 0) { + if (REG_VALUES (dreg) == 0) + VARRAY_PUSH_UINT (used_regs, dreg); + REG_VALUES (dreg) = new_elt_list (REG_VALUES (dreg), src_elt); if (src_elt->locs == 0) n_useless_values--; @@ -3249,7 +3266,7 @@ cselib_process_insn (insn) && GET_CODE (PATTERN (insn)) == ASM_OPERANDS && MEM_VOLATILE_P (PATTERN (insn)))) { - clear_table (); + clear_table (0); return; } @@ -3309,6 +3326,7 @@ cselib_update_varray_sizes () cselib_nregs = nregs; VARRAY_GROW (reg_values, nregs); + VARRAY_GROW (used_regs, nregs); } /* Initialize cselib for one pass. The caller must also call @@ -3329,8 +3347,9 @@ cselib_init () cselib_nregs = max_reg_num (); VARRAY_ELT_LIST_INIT (reg_values, cselib_nregs, "reg_values"); + VARRAY_UINT_INIT (used_regs, cselib_nregs, "used_regs"); hash_table = htab_create (31, get_value_hash, entry_and_rtx_equal_p, NULL); - clear_table (); + clear_table (1); } /* Called when the current user is done with cselib. */ @@ -3338,6 +3357,6 @@ cselib_init () void cselib_finish () { - clear_table (); + clear_table (0); htab_delete (hash_table); }