This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
On Sun, 8 Apr 2001 13:06:45 -0700 Richard Henderson wrote: > ... is a hack. Use flow.c for proper dead code removal. Perhaps this is easier to swallow. :-) Currently delete_prior_computation only checks that a parallel doesn't set other registers (it ignores other things that might be present in the parallel) and doesn't handle a parallel which contains unused sets. The patch passes make bootstrap and check on i386-pc-solaris2.7. It also passes make and check on arm-elf and powerpc-eabisim. ChangeLog: Sun Apr 22 23:12:52 EDT 2001 John Wehle (john@feith.com) * jump.c: Include basic-block.h. (mark_live_reg): New function. (delete_prior_computation): Reimplement using flow. (delete_computation): Reimplement. (redirect_tablejump): Update delete_prior_computation call. * flow.c (propagate_one_insn): Respect reg notes when scanning dead code after flow2 has completed. Enjoy! -- John Wehle ------------------8<------------------------8<------------------------ *** gcc/jump.c.ORIGINAL Fri Apr 13 00:07:08 2001 --- gcc/jump.c Sun Apr 22 13:53:23 2001 *************** Boston, MA 02111-1307, USA. */ *** 57,62 **** --- 57,63 ---- #include "tm_p.h" #include "flags.h" #include "hard-reg-set.h" + #include "basic-block.h" #include "regs.h" #include "insn-config.h" #include "insn-attr.h" *************** static void mark_modified_reg PARAMS (( *** 123,129 **** static void redirect_tablejump PARAMS ((rtx, rtx)); static void jump_optimize_1 PARAMS ((rtx, int, int, int, int, int)); static int returnjump_p_1 PARAMS ((rtx *, void *)); ! static void delete_prior_computation PARAMS ((rtx, rtx)); /* Main external entry point into the jump optimizer. See comments before jump_optimize_1 for descriptions of the arguments. */ --- 124,131 ---- static void redirect_tablejump PARAMS ((rtx, rtx)); static void jump_optimize_1 PARAMS ((rtx, int, int, int, int, int)); static int returnjump_p_1 PARAMS ((rtx *, void *)); ! static void mark_live_reg PARAMS ((rtx, rtx, void *)); ! static void delete_prior_computation PARAMS ((rtx)); /* Main external entry point into the jump optimizer. See comments before jump_optimize_1 for descriptions of the arguments. */ *************** delete_barrier (insn) *** 2606,2783 **** delete_insn (insn); } ! /* Recursively delete prior insns that compute the value (used only by INSN ! which the caller is deleting) stored in the register mentioned by NOTE ! which is a REG_DEAD note associated with INSN. */ static void ! delete_prior_computation (note, insn) ! rtx note; ! rtx insn; { ! rtx our_prev; ! rtx reg = XEXP (note, 0); ! ! for (our_prev = prev_nonnote_insn (insn); ! our_prev && (GET_CODE (our_prev) == INSN ! || GET_CODE (our_prev) == CALL_INSN); ! our_prev = prev_nonnote_insn (our_prev)) ! { ! rtx pat = PATTERN (our_prev); ! /* If we reach a CALL which is not calling a const function ! or the callee pops the arguments, then give up. */ ! if (GET_CODE (our_prev) == CALL_INSN ! && (! CONST_CALL_P (our_prev) ! || GET_CODE (pat) != SET || GET_CODE (SET_SRC (pat)) != CALL)) ! break; ! ! /* If we reach a SEQUENCE, it is too complex to try to ! do anything with it, so give up. */ ! if (GET_CODE (pat) == SEQUENCE) ! break; ! ! if (GET_CODE (pat) == USE ! && GET_CODE (XEXP (pat, 0)) == INSN) ! /* reorg creates USEs that look like this. We leave them ! alone because reorg needs them for its own purposes. */ ! break; ! ! if (reg_set_p (reg, pat)) ! { ! if (side_effects_p (pat) && GET_CODE (our_prev) != CALL_INSN) ! break; ! if (GET_CODE (pat) == PARALLEL) ! { ! /* If we find a SET of something else, we can't ! delete the insn. */ ! int i; ! for (i = 0; i < XVECLEN (pat, 0); i++) ! { ! rtx part = XVECEXP (pat, 0, i); ! if (GET_CODE (part) == SET ! && SET_DEST (part) != reg) ! break; ! } ! if (i == XVECLEN (pat, 0)) ! delete_computation (our_prev); ! } ! else if (GET_CODE (pat) == SET ! && GET_CODE (SET_DEST (pat)) == REG) { ! int dest_regno = REGNO (SET_DEST (pat)); ! int dest_endregno ! = (dest_regno ! + (dest_regno < FIRST_PSEUDO_REGISTER ! ? HARD_REGNO_NREGS (dest_regno, ! GET_MODE (SET_DEST (pat))) : 1)); ! int regno = REGNO (reg); ! int endregno ! = (regno ! + (regno < FIRST_PSEUDO_REGISTER ! ? HARD_REGNO_NREGS (regno, GET_MODE (reg)) : 1)); ! ! if (dest_regno >= regno ! && dest_endregno <= endregno) ! delete_computation (our_prev); ! ! /* We may have a multi-word hard register and some, but not ! all, of the words of the register are needed in subsequent ! insns. Write REG_UNUSED notes for those parts that were not ! needed. */ ! else if (dest_regno <= regno ! && dest_endregno >= endregno) { ! int i; ! ! REG_NOTES (our_prev) ! = gen_rtx_EXPR_LIST (REG_UNUSED, reg, ! REG_NOTES (our_prev)); ! ! for (i = dest_regno; i < dest_endregno; i++) ! if (! find_regno_note (our_prev, REG_UNUSED, i)) ! break; ! ! if (i == dest_endregno) ! delete_computation (our_prev); } } - - break; - } - - /* If PAT references the register that dies here, it is an - additional use. Hence any prior SET isn't dead. However, this - insn becomes the new place for the REG_DEAD note. */ - if (reg_overlap_mentioned_p (reg, pat)) - { - XEXP (note, 1) = REG_NOTES (our_prev); - REG_NOTES (our_prev) = note; - break; } } - } ! /* Delete INSN and recursively delete insns that compute values used only ! by INSN. This uses the REG_DEAD notes computed during flow analysis. ! If we are running before flow.c, we need do nothing since flow.c will ! delete dead code. We also can't know if the registers being used are ! dead or not at this point. ! ! Otherwise, look at all our REG_DEAD notes. If a previous insn does ! nothing other than set a register that dies in this insn, we can delete ! that insn as well. ! On machines with CC0, if CC0 is used in this insn, we may be able to ! delete the insn that set it. */ ! static void ! delete_computation (insn) ! rtx insn; ! { ! rtx note, next; ! #ifdef HAVE_cc0 ! if (reg_referenced_p (cc0_rtx, PATTERN (insn))) ! { ! rtx prev = prev_nonnote_insn (insn); ! /* We assume that at this stage ! CC's are always set explicitly ! and always immediately before the jump that ! will use them. So if the previous insn ! exists to set the CC's, delete it ! (unless it performs auto-increments, etc.). */ ! if (prev && GET_CODE (prev) == INSN ! && sets_cc0_p (PATTERN (prev))) ! { ! if (sets_cc0_p (PATTERN (prev)) > 0 ! && ! side_effects_p (PATTERN (prev))) ! delete_computation (prev); ! else ! /* Otherwise, show that cc0 won't be used. */ ! REG_NOTES (prev) = gen_rtx_EXPR_LIST (REG_UNUSED, ! cc0_rtx, REG_NOTES (prev)); ! } ! } ! #endif ! for (note = REG_NOTES (insn); note; note = next) { - next = XEXP (note, 1); - if (REG_NOTE_KIND (note) != REG_DEAD /* Verify that the REG_NOTE is legitimate. */ || GET_CODE (XEXP (note, 0)) != REG) continue; ! delete_prior_computation (note, insn); } delete_insn (insn); } --- 2608,2770 ---- delete_insn (insn); } ! /* Mark register REG set by SETTER as alive in regset LIVE. ! This is called via note_stores. */ static void ! mark_live_reg (reg, setter, live) ! rtx reg, setter; ! void *live; { ! int regno; ! int n; ! if (GET_CODE (reg) == SUBREG) ! reg = SUBREG_REG (reg); ! if (GET_CODE (reg) != REG ! || GET_CODE (setter) != SET) ! return; ! ! regno = REGNO (reg); ! n = regno < FIRST_PSEUDO_REGISTER ! ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (reg, 0))) : 1; ! while (n-- > 0) ! SET_REGNO_REG_SET ((regset)live, regno + n); ! } ! /* Delete prior insns that compute values used only by INSN which the ! caller is deleting. This uses the REG_DEAD notes computed during ! flow analysis. If we are running before flow2, we need do nothing ! since flow2 will delete dead code. We also can't know if the ! registers being used are dead or not at this point. ! On machines with CC0, if CC0 is used in this insn, we may be able to ! delete the insn that set it. */ ! static void ! delete_prior_computation (insn) ! rtx insn; ! { ! int i; ! int max_reg = max_reg_num (); ! int n; ! int regno; ! regset_head live_head; ! regset live; ! struct propagate_block_info *pbi; ! rtx prev; ! rtx note; ! if (! flow2_completed) ! { ! #ifdef HAVE_cc0 ! if (reg_referenced_p (cc0_rtx, PATTERN (insn))) ! { ! prev = prev_nonnote_insn (insn); ! /* We assume that at this stage ! CC's are always set explicitly ! and always immediately before the jump that ! will use them. So if the previous insn ! exists to set the CC's, delete it ! (unless it performs auto-increments, etc.). */ ! if (prev && GET_CODE (prev) == INSN ! && sets_cc0_p (PATTERN (prev))) { ! if (sets_cc0_p (PATTERN (prev)) > 0 ! && ! side_effects_p (PATTERN (prev))) { ! delete_prior_computation (prev); ! delete_insn (prev); } + else + /* Otherwise, show that cc0 won't be used. */ + REG_NOTES (prev) + = gen_rtx_EXPR_LIST (REG_UNUSED, cc0_rtx, REG_NOTES (prev)); } } + #endif + return; } ! /* Unfortunately BLOCK_FOR_INSN isn't necessarily valid. */ ! for (prev = PREV_INSN (insn); ! prev && ! NOTE_INSN_BASIC_BLOCK_P (prev); ! prev = PREV_INSN (prev)) ! ; ! if (! prev) ! return; ! live = INITIALIZE_REG_SET (live_head); ! /* Start by assuming that all the registers ! are alive after this insn. */ ! for (i = 0; i < max_reg; i++) ! SET_REGNO_REG_SET (live, i); ! /* Remove the ones known to be dead. */ ! for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) { if (REG_NOTE_KIND (note) != REG_DEAD /* Verify that the REG_NOTE is legitimate. */ || GET_CODE (XEXP (note, 0)) != REG) continue; ! regno = REGNO (XEXP (note, 0)); ! n = regno < FIRST_PSEUDO_REGISTER ! ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) : 1; ! while (n-- > 0) ! CLEAR_REGNO_REG_SET (live, regno + n); ! } ! ! /* Assume that registers which are set are alive ! even if there is a REG_DEAD note present since ! the insn may be a no-op move. */ ! note_stores (PATTERN (insn), mark_live_reg, live); ! ! /* Remove the ones known to be unused. */ ! for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) ! { ! if (REG_NOTE_KIND (note) != REG_UNUSED ! /* Verify that the REG_NOTE is legitimate. */ ! || GET_CODE (XEXP (note, 0)) != REG) ! continue; ! ! regno = REGNO (XEXP (note, 0)); ! n = regno < FIRST_PSEUDO_REGISTER ! ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) : 1; ! while (n-- > 0) ! CLEAR_REGNO_REG_SET (live, regno + n); ! } ! ! pbi = init_propagate_block_info (NOTE_BASIC_BLOCK (prev), live, NULL, NULL, ! PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE ! | PROP_KILL_DEAD_CODE); ! ! for (prev = PREV_INSN (insn); ! prev && ! NOTE_INSN_BASIC_BLOCK_P (prev); ! prev = propagate_one_insn (pbi, prev)) ! { ! /* If we reach a SEQUENCE, give up since flow doesn't handle them. */ ! if (INSN_P (prev) && GET_CODE (PATTERN (prev)) == SEQUENCE) ! break; } + + free_propagate_block_info (pbi); + + FREE_REG_SET (live); + } + + /* Delete INSN and insns that compute values used only by INSN. */ + + static void + delete_computation (insn) + rtx insn; + { + + delete_prior_computation (insn); delete_insn (insn); } *************** redirect_tablejump (jump, nlabel) *** 3390,3396 **** rtx jump, nlabel; { register rtx olabel = JUMP_LABEL (jump); - rtx *notep, note, next; /* Add this jump to the jump_chain of NLABEL. */ if (jump_chain && INSN_UID (nlabel) < max_jump_chain --- 3377,3382 ---- *************** redirect_tablejump (jump, nlabel) *** 3400,3420 **** jump_chain[INSN_UID (nlabel)] = jump; } ! for (notep = ®_NOTES (jump), note = *notep; note; note = next) ! { ! next = XEXP (note, 1); ! ! if (REG_NOTE_KIND (note) != REG_DEAD ! /* Verify that the REG_NOTE is legitimate. */ ! || GET_CODE (XEXP (note, 0)) != REG ! || ! reg_mentioned_p (XEXP (note, 0), PATTERN (jump))) ! notep = &XEXP (note, 1); ! else ! { ! delete_prior_computation (note, jump); ! *notep = next; ! } ! } PATTERN (jump) = gen_jump (nlabel); JUMP_LABEL (jump) = nlabel; --- 3386,3392 ---- jump_chain[INSN_UID (nlabel)] = jump; } ! delete_prior_computation (jump); PATTERN (jump) = gen_jump (nlabel); JUMP_LABEL (jump) = nlabel; *** gcc/flow.c.ORIGINAL Fri Apr 13 00:01:33 2001 --- gcc/flow.c Sun Apr 22 03:39:43 2001 *************** propagate_one_insn (pbi, insn) *** 3691,3707 **** int insn_is_dead = 0; int libcall_is_dead = 0; rtx note; int i; if (! INSN_P (insn)) return prev; ! note = find_reg_note (insn, REG_RETVAL, NULL_RTX); if (flags & PROP_SCAN_DEAD_CODE) { insn_is_dead = insn_dead_p (pbi, PATTERN (insn), 0, REG_NOTES (insn)); ! libcall_is_dead = (insn_is_dead && note != 0 ! && libcall_dead_p (pbi, note, insn)); } /* If an instruction consists of just dead store(s) on final pass, --- 3691,3728 ---- int insn_is_dead = 0; int libcall_is_dead = 0; rtx note; + rtx retval_note; int i; if (! INSN_P (insn)) return prev; ! retval_note = find_reg_note (insn, REG_RETVAL, NULL_RTX); if (flags & PROP_SCAN_DEAD_CODE) { + /* Note which registers are unused after this insn since they are + not alive after this insn. */ + if (flow2_completed) + for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) + { + int regno; + int n; + + if (REG_NOTE_KIND (note) != REG_UNUSED + /* Verify that the REG_NOTE is legitimate. */ + || GET_CODE (XEXP (note, 0)) != REG) + continue; + + regno = REGNO (XEXP (note, 0)); + n = regno < FIRST_PSEUDO_REGISTER + ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) : 1; + while (n-- > 0) + CLEAR_REGNO_REG_SET (pbi->reg_live, regno + n); + } + insn_is_dead = insn_dead_p (pbi, PATTERN (insn), 0, REG_NOTES (insn)); ! libcall_is_dead = (insn_is_dead && retval_note != 0 ! && libcall_dead_p (pbi, retval_note, insn)); } /* If an instruction consists of just dead store(s) on final pass, *************** propagate_one_insn (pbi, insn) *** 3733,3741 **** so the next insn can't use it. */ pbi->cc0_live = 0; if (libcall_is_dead) { ! prev = propagate_block_delete_libcall (pbi->bb, insn, note); insn = NEXT_INSN (prev); } else --- 3754,3782 ---- so the next insn can't use it. */ pbi->cc0_live = 0; + /* Note which registers died in this insn since they no longer + need to be alive prior to this insn. */ + if (flow2_completed) + for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) + { + int regno; + int n; + + if (REG_NOTE_KIND (note) != REG_DEAD + /* Verify that the REG_NOTE is legitimate. */ + || GET_CODE (XEXP (note, 0)) != REG) + continue; + + regno = REGNO (XEXP (note, 0)); + n = regno < FIRST_PSEUDO_REGISTER + ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) : 1; + while (n-- > 0) + CLEAR_REGNO_REG_SET (pbi->reg_live, regno + n); + } + if (libcall_is_dead) { ! prev = propagate_block_delete_libcall (pbi->bb, insn, retval_note); insn = NEXT_INSN (prev); } else *************** propagate_one_insn (pbi, insn) *** 3777,3783 **** /* Record the death of the dest reg. */ mark_set_regs (pbi, PATTERN (insn), insn); ! insn = XEXP (note, 0); return PREV_INSN (insn); } else if (GET_CODE (PATTERN (insn)) == SET --- 3818,3824 ---- /* Record the death of the dest reg. */ mark_set_regs (pbi, PATTERN (insn), insn); ! insn = XEXP (retval_note, 0); return PREV_INSN (insn); } else if (GET_CODE (PATTERN (insn)) == SET *************** propagate_one_insn (pbi, insn) *** 3807,3813 **** if (GET_CODE (insn) == CALL_INSN) { register int i; ! rtx note, cond; cond = NULL_RTX; if (GET_CODE (PATTERN (insn)) == COND_EXEC) --- 3848,3854 ---- if (GET_CODE (insn) == CALL_INSN) { register int i; ! rtx cond; cond = NULL_RTX; if (GET_CODE (PATTERN (insn)) == COND_EXEC) *************** propagate_one_insn (pbi, insn) *** 3858,3864 **** if (! insn_is_dead && GET_CODE (insn) == CALL_INSN) { register int i; ! rtx note, cond; cond = NULL_RTX; if (GET_CODE (PATTERN (insn)) == COND_EXEC) --- 3899,3905 ---- if (! insn_is_dead && GET_CODE (insn) == CALL_INSN) { register int i; ! rtx cond; cond = NULL_RTX; if (GET_CODE (PATTERN (insn)) == COND_EXEC) ------------------------------------------------------------------------- | Feith Systems | Voice: 1-215-646-8000 | Email: john@feith.com | | John Wehle | Fax: 1-215-540-5495 | | -------------------------------------------------------------------------
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |