This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
create less temporary rtl
- From: Segher Boessenkool <segher at chello dot nl>
- To: gcc at gcc dot gnu dot org
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Tue, 13 Aug 2002 07:50:01 +0200
- Subject: create less temporary rtl
Investigating GCC's memory allocation behaviour, I noticed there are a few
"hot" routines where RTL is generated just to call a function that expects
an rtx while, for example, we only have a register number. The attached
patch fixes one of those places, namely, where call-clobbered registers get
marked as such.
I'm sure I got all the details wrong (and the indenting, too); but it
bootstraps fine (on gnu-linux-powerpc), and is a full minute faster on
bootstrap, too. On some files (expr.c), it saves more than 10% compilation
time.
Of course, with a refcounting garbage collector, the impact would be much
less ;)
Comments?
Segher
*** flow.c.ORIG Thu Apr 18 22:21:09 2002
--- flow.c Tue Aug 13 05:05:14 2002
***************
*** 304,309 ****
--- 304,313 ----
static void mark_set_1 PARAMS ((struct propagate_block_info *,
enum rtx_code, rtx, rtx,
rtx, int));
+ static void mark_invalidated_by_call PARAMS ((struct propagate_block_info *,
+ rtx, rtx));
+ static void mark_set_reg_invalidated_by_call PARAMS ((struct propagate_block_info *,
+ int, rtx, rtx));
static int find_regno_partial PARAMS ((rtx *, void *));
#ifdef HAVE_conditional_execution
***************
*** 339,344 ****
--- 343,350 ----
rtx));
static void invalidate_mems_from_set PARAMS ((struct propagate_block_info *,
rtx));
+ static void invalidate_mems_from_set_1 PARAMS ((struct propagate_block_info *,
+ int));
static void delete_dead_jumptables PARAMS ((void));
static void clear_log_links PARAMS ((sbitmap));
***************
*** 1694,1700 ****
if (GET_CODE (insn) == CALL_INSN)
{
- int i;
rtx note, cond;
cond = NULL_RTX;
--- 1700,1705 ----
***************
*** 1717,1730 ****
cond, insn, pbi->flags);
/* Calls change all call-used and global registers. */
! for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
! if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
! {
! /* We do not want REG_UNUSED notes for these registers. */
! mark_set_1 (pbi, CLOBBER, gen_rtx_REG (reg_raw_mode[i], i),
! cond, insn,
! pbi->flags & ~(PROP_DEATH_NOTES | PROP_REG_INFO));
! }
}
/* If an insn doesn't use CC0, it becomes dead since we assume
--- 1722,1728 ----
cond, insn, pbi->flags);
/* Calls change all call-used and global registers. */
! mark_invalidated_by_call(pbi, cond, insn);
}
/* If an insn doesn't use CC0, it becomes dead since we assume
***************
*** 2416,2421 ****
--- 2414,2447 ----
}
}
+ static void
+ invalidate_mems_from_set_1 (pbi, regno)
+ struct propagate_block_info *pbi;
+ int regno;
+ {
+ rtx temp = pbi->mem_set_list;
+ rtx prev = NULL_RTX;
+ rtx next;
+
+ while (temp)
+ {
+ next = XEXP (temp, 1);
+ if (refers_to_regno_p (regno, regno, XEXP (temp, 0), (rtx *)0))
+ {
+ /* Splice this entry out of the list. */
+ if (prev)
+ XEXP (prev, 1) = next;
+ else
+ pbi->mem_set_list = next;
+ free_EXPR_LIST_node (temp);
+ pbi->mem_set_list_len--;
+ }
+ else
+ prev = temp;
+ temp = next;
+ }
+ }
+
/* Process the registers that are set within X. Their bits are set to
1 in the regset DEAD, because they are dead prior to this insn.
***************
*** 2802,2807 ****
--- 2828,2964 ----
REG_NOTES (insn)
= alloc_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (insn));
}
+ }
+
+ static void
+ mark_set_reg_invalidated_by_call (pbi, regno, cond, insn)
+ struct propagate_block_info *pbi;
+ int regno;
+ rtx cond, insn;
+ {
+ unsigned long not_dead = 0;
+ int flags;
+
+ flags = pbi->flags;
+
+ if ( ! (regno == FRAME_POINTER_REGNUM
+ && (! reload_completed || frame_pointer_needed))
+ #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+ && ! (regno == HARD_FRAME_POINTER_REGNUM
+ && (! reload_completed || frame_pointer_needed))
+ #endif
+ #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ && ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
+ #endif
+ )
+ {
+ int some_was_live = 0, some_was_dead = 0;
+
+ {
+ int needed_regno = REGNO_REG_SET_P (pbi->reg_live, regno);
+ if (pbi->local_set)
+ {
+ /* Order of the set operation matters here since both
+ sets may be the same. */
+ CLEAR_REGNO_REG_SET (pbi->cond_local_set, regno);
+ if (cond != NULL_RTX
+ && ! REGNO_REG_SET_P (pbi->local_set, regno))
+ SET_REGNO_REG_SET (pbi->cond_local_set, regno);
+ else
+ SET_REGNO_REG_SET (pbi->local_set, regno);
+ }
+
+ some_was_live |= needed_regno;
+ some_was_dead |= ! needed_regno;
+ }
+
+ #ifdef HAVE_conditional_execution
+ /* Consider conditional death in deciding that the register needs
+ a death note. */
+ if (some_was_live && ! not_dead
+ /* The stack pointer is never dead. Well, not strictly true,
+ but it's very difficult to tell from here. Hopefully
+ combine_stack_adjustments will fix up the most egregious
+ errors. */
+ && regno != STACK_POINTER_REGNUM)
+ {
+ if (! mark_regno_cond_dead (pbi, regno, cond))
+ not_dead |= 1;
+ }
+ #endif
+
+ /* Additional data to record if this is the final pass. */
+ if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
+ {
+ rtx y;
+ int blocknum = pbi->bb->index;
+
+ y = NULL_RTX;
+ if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
+ {
+ y = pbi->reg_next_use[regno];
+
+ /* The next use is no longer next, since a store intervenes. */
+ pbi->reg_next_use[regno] = 0;
+ }
+
+ if (! some_was_dead)
+ {
+ if (flags & PROP_LOG_LINKS)
+ {
+ /* Make a logical link from the next following insn
+ that uses this register, back to this insn.
+ The following insns have already been processed.
+
+ We don't build a LOG_LINK for hard registers containing
+ in ASM_OPERANDs. If these registers get replaced,
+ we might wind up changing the semantics of the insn,
+ even if reload can make what appear to be valid
+ assignments later. */
+ if (y && (BLOCK_NUM (y) == blocknum)
+ && (asm_noperands (PATTERN (y)) < 0))
+ LOG_LINKS (y) = alloc_INSN_LIST (insn, LOG_LINKS (y));
+ }
+ }
+ }
+
+ /* Mark the register as being dead. */
+ if (some_was_live
+ /* The stack pointer is never dead. Well, not strictly true,
+ but it's very difficult to tell from here. Hopefully
+ combine_stack_adjustments will fix up the most egregious
+ errors. */
+ && regno != STACK_POINTER_REGNUM)
+ {
+ if (!(not_dead & 1))
+ CLEAR_REGNO_REG_SET (pbi->reg_live, regno);
+ }
+ }
+ else
+ {
+ if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
+ pbi->reg_next_use[regno] = 0;
+ }
+ }
+
+ /* Calls change all call-used and global registers. */
+ static void
+ mark_invalidated_by_call (pbi, cond, insn)
+ struct propagate_block_info *pbi;
+ rtx cond;
+ rtx insn;
+ {
+ int i;
+ if (optimize && (pbi->flags & PROP_SCAN_DEAD_CODE))
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
+ {
+ /* This set is a REG, so it kills any MEMs which use the reg. */
+ invalidate_mems_from_set_1 (pbi, i);
+ }
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
+ mark_set_reg_invalidated_by_call (pbi, i, cond, insn);
}
#ifdef HAVE_conditional_execution