aboutsummaryrefslogtreecommitdiff
path: root/gcc/flow.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/flow.c')
-rw-r--r--gcc/flow.c232
1 files changed, 127 insertions, 105 deletions
diff --git a/gcc/flow.c b/gcc/flow.c
index 2694a0b07e0..c146310cb0a 100644
--- a/gcc/flow.c
+++ b/gcc/flow.c
@@ -136,20 +136,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "toplev.h"
#include "recog.h"
#include "expr.h"
-#include "ssa.h"
#include "timevar.h"
#include "obstack.h"
#include "splay-tree.h"
-/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
- the stack pointer does not matter. The value is tested only in
- functions that have frame pointers.
- No definition is equivalent to always zero. */
-#ifndef EXIT_IGNORE_STACK
-#define EXIT_IGNORE_STACK 0
-#endif
-
#ifndef HAVE_epilogue
#define HAVE_epilogue 0
#endif
@@ -160,9 +151,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#define HAVE_sibcall_epilogue 0
#endif
-#ifndef LOCAL_REGNO
-#define LOCAL_REGNO(REGNO) 0
-#endif
#ifndef EPILOGUE_USES
#define EPILOGUE_USES(REGNO) 0
#endif
@@ -293,7 +281,6 @@ static void notice_stack_pointer_modification_1 (rtx, rtx, void *);
static void notice_stack_pointer_modification (rtx);
static void mark_reg (rtx, void *);
static void mark_regs_live_at_end (regset);
-static int set_phi_alternative_reg (rtx, int, int, void *);
static void calculate_global_regs_live (sbitmap, sbitmap, int);
static void propagate_block_delete_insn (rtx);
static rtx propagate_block_delete_libcall (rtx, rtx);
@@ -328,6 +315,7 @@ static void add_to_mem_set_list (struct propagate_block_info *, rtx);
static int invalidate_mems_from_autoinc (rtx *, void *);
static void invalidate_mems_from_set (struct propagate_block_info *, rtx);
static void clear_log_links (sbitmap);
+static int count_or_remove_death_notes_bb (basic_block, int);
void
@@ -380,7 +368,7 @@ first_insn_after_basic_block_note (basic_block block)
rtx insn;
/* Get the first instruction in the block. */
- insn = block->head;
+ insn = BB_HEAD (block);
if (insn == NULL_RTX)
return NULL_RTX;
@@ -465,7 +453,10 @@ life_analysis (rtx f, FILE *file, int flags)
is not immediately handy. */
if (flags & PROP_REG_INFO)
- memset (regs_ever_live, 0, sizeof (regs_ever_live));
+ {
+ memset (regs_ever_live, 0, sizeof (regs_ever_live));
+ memset (regs_asm_clobbered, 0, sizeof (regs_asm_clobbered));
+ }
update_life_info (NULL, UPDATE_LIFE_GLOBAL, flags);
/* Clean up. */
@@ -506,7 +497,7 @@ verify_wide_reg_1 (rtx *px, void *pregno)
static void
verify_wide_reg (int regno, basic_block bb)
{
- rtx head = bb->head, end = bb->end;
+ rtx head = BB_HEAD (bb), end = BB_END (bb);
while (1)
{
@@ -596,6 +587,9 @@ verify_local_live_at_start (regset new_live_at_start, basic_block bb)
generates subregs of a multi-word pseudo, current life analysis will
lose the kill. So we _can_ have a pseudo go live. How irritating.
+ It is also not true when a peephole decides that it doesn't need one
+ or more of the inputs.
+
Including PROP_REG_INFO does not properly refresh regs_ever_live
unless the caller resets it to zero. */
@@ -820,7 +814,7 @@ delete_noop_moves (rtx f ATTRIBUTE_UNUSED)
FOR_EACH_BB (bb)
{
- for (insn = bb->head; insn != NEXT_INSN (bb->end); insn = next)
+ for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); insn = next)
{
next = NEXT_INSN (insn);
if (INSN_P (insn) && noop_move_p (insn))
@@ -1033,20 +1027,6 @@ mark_regs_live_at_end (regset set)
diddle_return_value (mark_reg, set);
}
-/* Callback function for for_each_successor_phi. DATA is a regset.
- Sets the SRC_REGNO, the regno of the phi alternative for phi node
- INSN, in the regset. */
-
-static int
-set_phi_alternative_reg (rtx insn ATTRIBUTE_UNUSED,
- int dest_regno ATTRIBUTE_UNUSED, int src_regno,
- void *data)
-{
- regset live = (regset) data;
- SET_REGNO_REG_SET (live, src_regno);
- return 0;
-}
-
/* Propagate global life info around the graph of basic blocks. Begin
considering blocks with their corresponding bit set in BLOCKS_IN.
If BLOCKS_IN is null, consider it the universal set.
@@ -1208,14 +1188,6 @@ calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags)
SET_REGNO_REG_SET (new_live_at_end, PIC_OFFSET_TABLE_REGNUM);
}
- /* Regs used in phi nodes are not included in
- global_live_at_start, since they are live only along a
- particular edge. Set those regs that are live because of a
- phi node alternative corresponding to this particular block. */
- if (in_ssa_form)
- for_each_successor_phi (bb, &set_phi_alternative_reg,
- new_live_at_end);
-
if (bb == ENTRY_BLOCK_PTR)
{
COPY_REG_SET (bb->global_live_at_end, new_live_at_end);
@@ -1864,8 +1836,8 @@ init_propagate_block_info (basic_block bb, regset live, regset local_set,
/* If this block ends in a conditional branch, for each register
live from one side of the branch and not the other, record the
register as conditionally dead. */
- if (GET_CODE (bb->end) == JUMP_INSN
- && any_condjump_p (bb->end))
+ if (GET_CODE (BB_END (bb)) == JUMP_INSN
+ && any_condjump_p (BB_END (bb)))
{
regset_head diff_head;
regset diff = INITIALIZE_REG_SET (diff_head);
@@ -1890,7 +1862,7 @@ init_propagate_block_info (basic_block bb, regset live, regset local_set,
else
{
/* This can happen with a conditional jump to the next insn. */
- if (JUMP_LABEL (bb->end) != bb_true->head)
+ if (JUMP_LABEL (BB_END (bb)) != BB_HEAD (bb_true))
abort ();
/* Simplest way to do nothing. */
@@ -1902,7 +1874,7 @@ init_propagate_block_info (basic_block bb, regset live, regset local_set,
bb_false->global_live_at_start, BITMAP_XOR))
{
/* Extract the condition from the branch. */
- rtx set_src = SET_SRC (pc_set (bb->end));
+ rtx set_src = SET_SRC (pc_set (BB_END (bb)));
rtx cond_true = XEXP (set_src, 0);
rtx reg = XEXP (cond_true, 0);
@@ -1971,7 +1943,7 @@ init_propagate_block_info (basic_block bb, regset live, regset local_set,
&& ! current_function_calls_eh_return)))
{
rtx insn, set;
- for (insn = bb->end; insn != bb->head; insn = PREV_INSN (insn))
+ for (insn = BB_END (bb); insn != BB_HEAD (bb); insn = PREV_INSN (insn))
if (GET_CODE (insn) == INSN
&& (set = single_set (insn))
&& GET_CODE (SET_DEST (set)) == MEM)
@@ -2051,7 +2023,7 @@ propagate_block (basic_block bb, regset live, regset local_set,
/* Scan the block an insn at a time from end to beginning. */
changed = 0;
- for (insn = bb->end;; insn = prev)
+ for (insn = BB_END (bb); ; insn = prev)
{
/* If this is a call to `setjmp' et al, warn if any
non-volatile datum is live. */
@@ -2066,7 +2038,7 @@ propagate_block (basic_block bb, regset live, regset local_set,
else
changed |= NEXT_INSN (prev) != insn;
- if (insn == bb->head)
+ if (insn == BB_HEAD (bb))
break;
}
@@ -2465,6 +2437,7 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn)
rtx cond = NULL_RTX;
rtx link;
enum rtx_code code;
+ int flags = pbi->flags;
if (insn)
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
@@ -2473,14 +2446,17 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn)
mark_set_1 (pbi, SET, XEXP (link, 0),
(GET_CODE (x) == COND_EXEC
? COND_EXEC_TEST (x) : NULL_RTX),
- insn, pbi->flags);
+ insn, flags);
}
retry:
switch (code = GET_CODE (x))
{
case SET:
+ if (GET_CODE (XEXP (x, 1)) == ASM_OPERANDS)
+ flags |= PROP_ASM_SCAN;
+ /* Fall through */
case CLOBBER:
- mark_set_1 (pbi, code, SET_DEST (x), cond, insn, pbi->flags);
+ mark_set_1 (pbi, code, SET_DEST (x), cond, insn, flags);
return;
case COND_EXEC:
@@ -2492,7 +2468,9 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn)
{
int i;
- for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ /* We must scan forwards. If we have an asm, we need to set
+ the PROP_ASM_SCAN flag before scanning the clobbers. */
+ for (i = 0; i < XVECLEN (x, 0); i++)
{
rtx sub = XVECEXP (x, 0, i);
switch (code = GET_CODE (sub))
@@ -2503,13 +2481,24 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn)
cond = COND_EXEC_TEST (sub);
sub = COND_EXEC_CODE (sub);
- if (GET_CODE (sub) != SET && GET_CODE (sub) != CLOBBER)
- break;
- /* Fall through. */
+ if (GET_CODE (sub) == SET)
+ goto mark_set;
+ if (GET_CODE (sub) == CLOBBER)
+ goto mark_clob;
+ break;
case SET:
+ mark_set:
+ if (GET_CODE (XEXP (sub, 1)) == ASM_OPERANDS)
+ flags |= PROP_ASM_SCAN;
+ /* Fall through */
case CLOBBER:
- mark_set_1 (pbi, code, SET_DEST (sub), cond, insn, pbi->flags);
+ mark_clob:
+ mark_set_1 (pbi, code, SET_DEST (sub), cond, insn, flags);
+ break;
+
+ case ASM_OPERANDS:
+ flags |= PROP_ASM_SCAN;
break;
default:
@@ -2733,6 +2722,9 @@ mark_set_1 (struct propagate_block_info *pbi, enum rtx_code code, rtx reg, rtx c
{
for (i = regno_first; i <= regno_last; i++)
regs_ever_live[i] = 1;
+ if (flags & PROP_ASM_SCAN)
+ for (i = regno_first; i <= regno_last; i++)
+ regs_asm_clobbered[i] = 1;
}
else
{
@@ -2818,6 +2810,14 @@ mark_set_1 (struct propagate_block_info *pbi, enum rtx_code code, rtx reg, rtx c
{
if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
pbi->reg_next_use[regno_first] = 0;
+
+ if ((flags & PROP_REG_INFO) != 0
+ && (flags & PROP_ASM_SCAN) != 0
+ && regno_first < FIRST_PSEUDO_REGISTER)
+ {
+ for (i = regno_first; i <= regno_last; i++)
+ regs_asm_clobbered[i] = 1;
+ }
}
/* If this is the last pass and this is a SCRATCH, show it will be dying
@@ -3311,8 +3311,8 @@ attempt_auto_inc (struct propagate_block_info *pbi, rtx inc, rtx insn,
new insn(s) and do the updates. */
emit_insn_before (insns, insn);
- if (pbi->bb->head == insn)
- pbi->bb->head = insns;
+ if (BB_HEAD (pbi->bb) == insn)
+ BB_HEAD (pbi->bb) = insns;
/* INCR will become a NOTE and INSN won't contain a
use of INCR_REG. If a use of INCR_REG was just placed in
@@ -3908,14 +3908,6 @@ mark_used_regs (struct propagate_block_info *pbi, rtx x, rtx cond, rtx insn)
x = COND_EXEC_CODE (x);
goto retry;
- case PHI:
- /* We _do_not_ want to scan operands of phi nodes. Operands of
- a phi function are evaluated only when control reaches this
- block along a particular edge. Therefore, regs that appear
- as arguments to phi should not be added to the global live at
- start. */
- return;
-
default:
break;
}
@@ -4197,65 +4189,95 @@ int
count_or_remove_death_notes (sbitmap blocks, int kill)
{
int count = 0;
+ int i;
basic_block bb;
- FOR_EACH_BB_REVERSE (bb)
+
+ /* This used to be a loop over all the blocks with a membership test
+ inside the loop. That can be amazingly expensive on a large CFG
+ when only a small number of bits are set in BLOCKs (for example,
+ the calls from the scheduler typically have very few bits set).
+
+ For extra credit, someone should convert BLOCKS to a bitmap rather
+ than an sbitmap. */
+ if (blocks)
{
- rtx insn;
+ EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i,
+ {
+ count += count_or_remove_death_notes_bb (BASIC_BLOCK (i), kill);
+ });
+ }
+ else
+ {
+ FOR_EACH_BB (bb)
+ {
+ count += count_or_remove_death_notes_bb (bb, kill);
+ }
+ }
- if (blocks && ! TEST_BIT (blocks, bb->index))
- continue;
+ return count;
+}
+
+/* Optionally removes all the REG_DEAD and REG_UNUSED notes from basic
+ block BB. Returns a count of the number of registers that died. */
- for (insn = bb->head;; insn = NEXT_INSN (insn))
+static int
+count_or_remove_death_notes_bb (basic_block bb, int kill)
+{
+ int count = 0;
+ rtx insn;
+
+ for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn))
+ {
+ if (INSN_P (insn))
{
- if (INSN_P (insn))
- {
- rtx *pprev = &REG_NOTES (insn);
- rtx link = *pprev;
+ rtx *pprev = &REG_NOTES (insn);
+ rtx link = *pprev;
- while (link)
+ while (link)
+ {
+ switch (REG_NOTE_KIND (link))
{
- switch (REG_NOTE_KIND (link))
+ case REG_DEAD:
+ if (GET_CODE (XEXP (link, 0)) == REG)
+ {
+ rtx reg = XEXP (link, 0);
+ int n;
+
+ if (REGNO (reg) >= FIRST_PSEUDO_REGISTER)
+ n = 1;
+ else
+ n = HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg));
+ count += n;
+ }
+
+ /* Fall through. */
+
+ case REG_UNUSED:
+ if (kill)
{
- case REG_DEAD:
- if (GET_CODE (XEXP (link, 0)) == REG)
- {
- rtx reg = XEXP (link, 0);
- int n;
-
- if (REGNO (reg) >= FIRST_PSEUDO_REGISTER)
- n = 1;
- else
- n = HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg));
- count += n;
- }
- /* Fall through. */
-
- case REG_UNUSED:
- if (kill)
- {
- rtx next = XEXP (link, 1);
- free_EXPR_LIST_node (link);
- *pprev = link = next;
- break;
- }
- /* Fall through. */
-
- default:
- pprev = &XEXP (link, 1);
- link = *pprev;
+ rtx next = XEXP (link, 1);
+ free_EXPR_LIST_node (link);
+ *pprev = link = next;
break;
}
+ /* Fall through. */
+
+ default:
+ pprev = &XEXP (link, 1);
+ link = *pprev;
+ break;
}
}
-
- if (insn == bb->end)
- break;
}
+
+ if (insn == BB_END (bb))
+ break;
}
return count;
}
+
/* Clear LOG_LINKS fields of insns in a selected blocks or whole chain
if blocks is NULL. */
@@ -4276,7 +4298,7 @@ clear_log_links (sbitmap blocks)
{
basic_block bb = BASIC_BLOCK (i);
- for (insn = bb->head; insn != NEXT_INSN (bb->end);
+ for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
insn = NEXT_INSN (insn))
if (INSN_P (insn))
free_INSN_LIST_list (&LOG_LINKS (insn));