summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2001-07-30 20:30:23 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2001-07-30 20:30:23 +0000
commitecb7b89177c4cec230e1775fb7feb2f3dd77a5c9 (patch)
treedf492d486710873b66c3b9b278a0eac02a7df6c8
parent87f01205933bc3787a0ef34d9401e4c297e97d7c (diff)
downloadgcc-ecb7b89177c4cec230e1775fb7feb2f3dd77a5c9.tar.gz
* i386.c (ix86_output_main_function_alignment_hack): New function.
(TARGET_ASM_FUNCTION_PROLOGUE): Default to it. * flow.c (mark_dfs_back_edges): Move from loop_p ; mark back edges by EDGE_DFS_BACK flag. (dump_edge_info): Add dfs_back flag. * basic-block.h (EDGE_DFS_BACK): New constant. (mark_dfs_back_edges): Declare. * alias.c (loop_p): Remove. (mark_constant_function): Use mark_dfs_back_edges. * reg-stack.c (block_info_def): Add predecesors counter and stack_out. (reg_to_stack): Call mark_dfs_back_edges; count the predecesors. (compensate_edge): Break out from ... (convert_regs_1): ... here; do smart choosing of stack_out to copy. (convert_regs_2): Set block_done once block is really done; Do updating of the predecesors counts. * toplev.c (rest_of_compilation): Recompute block_for_insn before post-reload cfg_cleanup. * function.c (thread_prologue_epilogue_insns): Call set_block_for_new_insns when emitting prologue directly. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@44486 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog25
-rw-r--r--gcc/alias.c94
-rw-r--r--gcc/basic-block.h2
-rw-r--r--gcc/config/i386/i386.c47
-rw-r--r--gcc/flow.c95
-rw-r--r--gcc/function.c3
-rw-r--r--gcc/reg-stack.c340
-rw-r--r--gcc/toplev.c6
8 files changed, 382 insertions, 230 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e6b7d91de92..c2e831aa8f8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,28 @@
+Mon Jul 30 22:16:08 CEST 2001 Jan Hubicka <jh@suse.cz>
+
+ * i386.c (ix86_output_main_function_alignment_hack): New function.
+ (TARGET_ASM_FUNCTION_PROLOGUE): Default to it.
+
+ * flow.c (mark_dfs_back_edges): Move from loop_p ; mark back
+ edges by EDGE_DFS_BACK flag.
+ (dump_edge_info): Add dfs_back flag.
+ * basic-block.h (EDGE_DFS_BACK): New constant.
+ (mark_dfs_back_edges): Declare.
+ * alias.c (loop_p): Remove.
+ (mark_constant_function): Use mark_dfs_back_edges.
+
+ * reg-stack.c (block_info_def): Add predecesors counter and stack_out.
+ (reg_to_stack): Call mark_dfs_back_edges; count the predecesors.
+ (compensate_edge): Break out from ...
+ (convert_regs_1): ... here; do smart choosing of stack_out to copy.
+ (convert_regs_2): Set block_done once block is really done;
+ Do updating of the predecesors counts.
+
+ * toplev.c (rest_of_compilation): Recompute block_for_insn
+ before post-reload cfg_cleanup.
+ * function.c (thread_prologue_epilogue_insns):
+ Call set_block_for_new_insns when emitting prologue directly.
+
2001-07-30 Andreas Jaeger <aj@suse.de>
* jump.c: Add prototype for mark_modified_reg.
diff --git a/gcc/alias.c b/gcc/alias.c
index 84a7663ce7b..bbde59b6440 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -107,8 +107,6 @@ static int aliases_everything_p PARAMS ((rtx));
static int write_dependence_p PARAMS ((rtx, rtx, int));
static int nonlocal_mentioned_p PARAMS ((rtx));
-static int loop_p PARAMS ((void));
-
/* Set up all info needed to perform alias analysis on memory references. */
/* Returns the size in bytes of the mode of X. */
@@ -2051,96 +2049,6 @@ nonlocal_mentioned_p (x)
return 0;
}
-/* Return non-zero if a loop (natural or otherwise) is present.
- Inspired by Depth_First_Search_PP described in:
-
- Advanced Compiler Design and Implementation
- Steven Muchnick
- Morgan Kaufmann, 1997
-
- and heavily borrowed from flow_depth_first_order_compute. */
-
-static int
-loop_p ()
-{
- edge *stack;
- int *pre;
- int *post;
- int sp;
- int prenum = 1;
- int postnum = 1;
- sbitmap visited;
-
- /* Allocate the preorder and postorder number arrays. */
- pre = (int *) xcalloc (n_basic_blocks, sizeof (int));
- post = (int *) xcalloc (n_basic_blocks, sizeof (int));
-
- /* Allocate stack for back-tracking up CFG. */
- stack = (edge *) xmalloc ((n_basic_blocks + 1) * sizeof (edge));
- sp = 0;
-
- /* Allocate bitmap to track nodes that have been visited. */
- visited = sbitmap_alloc (n_basic_blocks);
-
- /* None of the nodes in the CFG have been visited yet. */
- sbitmap_zero (visited);
-
- /* Push the first edge on to the stack. */
- stack[sp++] = ENTRY_BLOCK_PTR->succ;
-
- while (sp)
- {
- edge e;
- basic_block src;
- basic_block dest;
-
- /* Look at the edge on the top of the stack. */
- e = stack[sp - 1];
- src = e->src;
- dest = e->dest;
-
- /* Check if the edge destination has been visited yet. */
- if (dest != EXIT_BLOCK_PTR && ! TEST_BIT (visited, dest->index))
- {
- /* Mark that we have visited the destination. */
- SET_BIT (visited, dest->index);
-
- pre[dest->index] = prenum++;
-
- if (dest->succ)
- {
- /* Since the DEST node has been visited for the first
- time, check its successors. */
- stack[sp++] = dest->succ;
- }
- else
- post[dest->index] = postnum++;
- }
- else
- {
- if (dest != EXIT_BLOCK_PTR && src != ENTRY_BLOCK_PTR
- && pre[src->index] >= pre[dest->index]
- && post[dest->index] == 0)
- break;
-
- if (! e->succ_next && src != ENTRY_BLOCK_PTR)
- post[src->index] = postnum++;
-
- if (e->succ_next)
- stack[sp - 1] = e->succ_next;
- else
- sp--;
- }
- }
-
- free (pre);
- free (post);
- free (stack);
- sbitmap_free (visited);
-
- return sp;
-}
-
/* Mark the function if it is constant. */
void
@@ -2157,7 +2065,7 @@ mark_constant_function ()
return;
/* A loop might not return which counts as a side effect. */
- if (loop_p ())
+ if (mark_dfs_back_edges ())
return;
nonlocal_mentioned = 0;
diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index 7b467c2b431..d7893a58b06 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -145,6 +145,7 @@ typedef struct edge_def {
#define EDGE_ABNORMAL_CALL 8
#define EDGE_EH 16
#define EDGE_FAKE 32
+#define EDGE_DFS_BACK 64
#define EDGE_COMPLEX (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH)
@@ -650,6 +651,7 @@ extern void conflict_graph_print PARAMS ((conflict_graph, FILE*));
extern conflict_graph conflict_graph_compute
PARAMS ((regset,
partition));
+extern bool mark_dfs_back_edges PARAMS ((void));
/* In dominance.c */
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 725a984e90e..9017207e292 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -574,6 +574,7 @@ static HOST_WIDE_INT ix86_GOT_alias_set PARAMS ((void));
static void ix86_adjust_counter PARAMS ((rtx, HOST_WIDE_INT));
static rtx ix86_expand_aligntest PARAMS ((rtx, int));
static void ix86_expand_strlensi_unroll_1 PARAMS ((rtx, rtx));
+static void ix86_output_main_function_alignment_hack PARAMS ((FILE *f, int));
struct ix86_address
{
@@ -634,6 +635,10 @@ static int ix86_comp_type_attributes PARAMS ((tree, tree));
HOST_WIDE_INT));
# undef TARGET_ASM_FUNCTION_PROLOGUE
# define TARGET_ASM_FUNCTION_PROLOGUE ix86_osf_output_function_prologue
+#else
+# undef TARGET_ASM_FUNCTION_PROLOGUE
+# define TARGET_ASM_FUNCTION_PROLOGUE \
+ ix86_output_main_function_alignment_hack
#endif
#undef TARGET_ASM_OPEN_PAREN
@@ -10775,3 +10780,45 @@ ix86_memory_move_cost (mode, class, in)
* (int) GET_MODE_SIZE (mode) / 4);
}
}
+
+/* Most of current runtimes (Jul 2001) do not align stack properly when
+ entering main, so emit an wrapper to align stack before the real main
+ code is called.
+
+ This can eventually go if we manage to fix the runtimes or teach gcc
+ to dynamically align stack in main automatically.
+
+ Adding check to configure is probably not good idea, as binarry can move
+ from one shared library to older. */
+
+static void
+ix86_output_main_function_alignment_hack (file, size)
+ FILE *file;
+ int size ATTRIBUTE_UNUSED;
+{
+ rtx label;
+ char buf[256];
+ /* Check that we see main function with maximally 8 bytes of arguments.
+ if so, emit the hack to align stack for runtimes, where this constraint
+ is broken. */
+ if (strcmp (cfun->name, "main"))
+ return;
+ if (cfun->pops_args || cfun->args_size > 12)
+ return;
+ if (PREFERRED_STACK_BOUNDARY <= 2)
+ return;
+ label = gen_label_rtx ();
+ fprintf (file, "\tpushl\t%%ebp\n");
+ fprintf (file, "\tmovl\t%%esp, %%ebp\n");
+ fprintf (file, "\tandl\t$0xfffffff0, %%esp\n");
+ fprintf (file, "\tpushl\t%%ebp\n");
+ fprintf (file, "\tpushl\t16(%%ebp)\n");
+ fprintf (file, "\tpushl\t12(%%ebp)\n");
+ fprintf (file, "\tpushl\t8(%%ebp)\n");
+ fprintf (file, "\tcall\t");
+ ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (label));
+ assemble_name (file, buf);
+ fprintf (file, "\n\tleave\n");
+ fprintf (file, "\tret\n");
+ ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (label));
+}
diff --git a/gcc/flow.c b/gcc/flow.c
index 69e7747502d..b13591f044c 100644
--- a/gcc/flow.c
+++ b/gcc/flow.c
@@ -1528,6 +1528,99 @@ mark_critical_edges ()
}
}
+/* Mark the back edges in DFS traversal.
+ Return non-zero if a loop (natural or otherwise) is present.
+ Inspired by Depth_First_Search_PP described in:
+
+ Advanced Compiler Design and Implementation
+ Steven Muchnick
+ Morgan Kaufmann, 1997
+
+ and heavily borrowed from flow_depth_first_order_compute. */
+
+bool
+mark_dfs_back_edges ()
+{
+ edge *stack;
+ int *pre;
+ int *post;
+ int sp;
+ int prenum = 1;
+ int postnum = 1;
+ sbitmap visited;
+ bool found = false;
+
+ /* Allocate the preorder and postorder number arrays. */
+ pre = (int *) xcalloc (n_basic_blocks, sizeof (int));
+ post = (int *) xcalloc (n_basic_blocks, sizeof (int));
+
+ /* Allocate stack for back-tracking up CFG. */
+ stack = (edge *) xmalloc ((n_basic_blocks + 1) * sizeof (edge));
+ sp = 0;
+
+ /* Allocate bitmap to track nodes that have been visited. */
+ visited = sbitmap_alloc (n_basic_blocks);
+
+ /* None of the nodes in the CFG have been visited yet. */
+ sbitmap_zero (visited);
+
+ /* Push the first edge on to the stack. */
+ stack[sp++] = ENTRY_BLOCK_PTR->succ;
+
+ while (sp)
+ {
+ edge e;
+ basic_block src;
+ basic_block dest;
+
+ /* Look at the edge on the top of the stack. */
+ e = stack[sp - 1];
+ src = e->src;
+ dest = e->dest;
+ e->flags &= ~EDGE_DFS_BACK;
+
+ /* Check if the edge destination has been visited yet. */
+ if (dest != EXIT_BLOCK_PTR && ! TEST_BIT (visited, dest->index))
+ {
+ /* Mark that we have visited the destination. */
+ SET_BIT (visited, dest->index);
+
+ pre[dest->index] = prenum++;
+
+ if (dest->succ)
+ {
+ /* Since the DEST node has been visited for the first
+ time, check its successors. */
+ stack[sp++] = dest->succ;
+ }
+ else
+ post[dest->index] = postnum++;
+ }
+ else
+ {
+ if (dest != EXIT_BLOCK_PTR && src != ENTRY_BLOCK_PTR
+ && pre[src->index] >= pre[dest->index]
+ && post[dest->index] == 0)
+ e->flags |= EDGE_DFS_BACK, found = true;
+
+ if (! e->succ_next && src != ENTRY_BLOCK_PTR)
+ post[src->index] = postnum++;
+
+ if (e->succ_next)
+ stack[sp - 1] = e->succ_next;
+ else
+ sp--;
+ }
+ }
+
+ free (pre);
+ free (post);
+ free (stack);
+ sbitmap_free (visited);
+
+ return found;
+}
+
/* Split a block BB after insn INSN creating a new fallthru edge.
Return the new edge. Note that to keep other parts of the compiler happy,
this function renumbers all the basic blocks so that the new
@@ -7779,7 +7872,7 @@ dump_edge_info (file, e, do_succ)
if (e->flags)
{
static const char * const bitnames[] = {
- "fallthru", "crit", "ab", "abcall", "eh", "fake"
+ "fallthru", "crit", "ab", "abcall", "eh", "fake", "dfs_back"
};
int comma = 0;
int i, flags = e->flags;
diff --git a/gcc/function.c b/gcc/function.c
index 4dec34e8a78..a2284a0d12a 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -7226,7 +7226,8 @@ thread_prologue_and_epilogue_insns (f)
inserted = 1;
}
else
- emit_insn_after (seq, f);
+ set_block_for_new_insns (emit_insn_after (seq, f),
+ ENTRY_BLOCK_PTR->succ);
}
#endif
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c
index 38803b21e80..342477cb329 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -194,8 +194,11 @@ typedef struct stack_def
typedef struct block_info_def
{
struct stack_def stack_in; /* Input stack configuration. */
+ struct stack_def stack_out; /* Output stack configuration. */
HARD_REG_SET out_reg_set; /* Stack regs live on output. */
int done; /* True if block already converted. */
+ int predecesors; /* Number of predecesors that needs
+ to be visited. */
} *block_info;
#define BLOCK_INFO(B) ((block_info) (B)->aux)
@@ -263,6 +266,7 @@ static int convert_regs PARAMS ((FILE *));
static void print_stack PARAMS ((FILE *, stack));
static rtx next_flags_user PARAMS ((rtx));
static void record_label_references PARAMS ((rtx, rtx));
+static bool compensate_edge PARAMS ((edge, FILE *));
/* Return non-zero if any stack register is mentioned somewhere within PAT. */
@@ -443,11 +447,20 @@ reg_to_stack (first, file)
find_basic_blocks (first, max_reg_num (), file);
count_or_remove_death_notes (NULL, 1);
life_analysis (first, file, PROP_DEATH_NOTES);
+ mark_dfs_back_edges ();
/* Set up block info for each basic block. */
bi = (block_info) xcalloc ((n_basic_blocks + 1), sizeof (*bi));
for (i = n_basic_blocks - 1; i >= 0; --i)
- BASIC_BLOCK (i)->aux = bi + i;
+ {
+ edge e;
+ basic_block bb = BASIC_BLOCK (i);
+ bb->aux = bi + i;
+ for (e = bb->pred; e; e=e->pred_next)
+ if (!(e->flags & EDGE_DFS_BACK)
+ && e->src != ENTRY_BLOCK_PTR)
+ BLOCK_INFO (bb)->predecesors++;
+ }
EXIT_BLOCK_PTR->aux = bi + n_basic_blocks;
/* Create the replacement registers up front. */
@@ -2452,6 +2465,143 @@ convert_regs_exit ()
}
}
+/* Adjust the stack of this block on exit to match the stack of the
+ target block, or copy stack info into the stack of the successor
+ of the successor hasn't been processed yet. */
+static bool
+compensate_edge (e, file)
+ edge e;
+ FILE *file;
+{
+ basic_block block = e->src, target = e->dest;
+ block_info bi = BLOCK_INFO (block);
+ struct stack_def regstack, tmpstack;
+ stack target_stack = &BLOCK_INFO (target)->stack_in;
+ int reg;
+
+ current_block = block;
+ regstack = bi->stack_out;
+ if (file)
+ fprintf (file, "Edge %d->%d: ", block->index, target->index);
+
+ if (target_stack->top == -2)
+ {
+ /* The target block hasn't had a stack order selected.
+ We need merely ensure that no pops are needed. */
+ for (reg = regstack.top; reg >= 0; --reg)
+ if (!TEST_HARD_REG_BIT (target_stack->reg_set, regstack.reg[reg]))
+ break;
+
+ if (reg == -1)
+ {
+ if (file)
+ fprintf (file, "new block; copying stack position\n");
+
+ /* change_stack kills values in regstack. */
+ tmpstack = regstack;
+
+ change_stack (block->end, &tmpstack, target_stack, EMIT_AFTER);
+ return false;
+ }
+
+ if (file)
+ fprintf (file, "new block; pops needed\n");
+ }
+ else
+ {
+ if (target_stack->top == regstack.top)
+ {
+ for (reg = target_stack->top; reg >= 0; --reg)
+ if (target_stack->reg[reg] != regstack.reg[reg])
+ break;
+
+ if (reg == -1)
+ {
+ if (file)
+ fprintf (file, "no changes needed\n");
+ return false;
+ }
+ }
+
+ if (file)
+ {
+ fprintf (file, "correcting stack to ");
+ print_stack (file, target_stack);
+ }
+ }
+
+ /* Care for non-call EH edges specially. The normal return path have
+ values in registers. These will be popped en masse by the unwind
+ library. */
+ if ((e->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) == EDGE_EH)
+ target_stack->top = -1;
+
+ /* Other calls may appear to have values live in st(0), but the
+ abnormal return path will not have actually loaded the values. */
+ else if (e->flags & EDGE_ABNORMAL_CALL)
+ {
+ /* Assert that the lifetimes are as we expect -- one value
+ live at st(0) on the end of the source block, and no
+ values live at the beginning of the destination block. */
+ HARD_REG_SET tmp;
+
+ CLEAR_HARD_REG_SET (tmp);
+ GO_IF_HARD_REG_EQUAL (target_stack->reg_set, tmp, eh1);
+ abort ();
+ eh1:
+
+ SET_HARD_REG_BIT (tmp, FIRST_STACK_REG);
+ GO_IF_HARD_REG_EQUAL (regstack.reg_set, tmp, eh2);
+ abort ();
+ eh2:
+
+ target_stack->top = -1;
+ }
+
+ /* It is better to output directly to the end of the block
+ instead of to the edge, because emit_swap can do minimal
+ insn scheduling. We can do this when there is only one
+ edge out, and it is not abnormal. */
+ else if (block->succ->succ_next == NULL && !(e->flags & EDGE_ABNORMAL))
+ {
+ /* change_stack kills values in regstack. */
+ tmpstack = regstack;
+
+ change_stack (block->end, &tmpstack, target_stack,
+ (GET_CODE (block->end) == JUMP_INSN
+ ? EMIT_BEFORE : EMIT_AFTER));
+ }
+ else
+ {
+ rtx seq, after;
+
+ /* We don't support abnormal edges. Global takes care to
+ avoid any live register across them, so we should never
+ have to insert instructions on such edges. */
+ if (e->flags & EDGE_ABNORMAL)
+ abort ();
+
+ current_block = NULL;
+ start_sequence ();
+
+ /* ??? change_stack needs some point to emit insns after.
+ Also needed to keep gen_sequence from returning a
+ pattern as opposed to a sequence, which would lose
+ REG_DEAD notes. */
+ after = emit_note (NULL, NOTE_INSN_DELETED);
+
+ tmpstack = regstack;
+ change_stack (after, &tmpstack, target_stack, EMIT_BEFORE);
+
+ seq = gen_sequence ();
+ end_sequence ();
+
+ insert_insn_on_edge (seq, e);
+ return true;
+ }
+ return false;
+}
+
/* Convert stack register references in one block. */
static int
@@ -2459,14 +2609,48 @@ convert_regs_1 (file, block)
FILE *file;
basic_block block;
{
- struct stack_def regstack, tmpstack;
+ struct stack_def regstack;
block_info bi = BLOCK_INFO (block);
int inserted, reg;
rtx insn, next;
- edge e;
+ edge e, beste = NULL;
- current_block = block;
+ inserted = 0;
+
+ /* Find the edge we will copy stack from. It should be the most frequent
+ one as it will get cheapest after compensation code is generated,
+ if multiple such exists, take one with largest count, preffer critical
+ one (as splitting critical edges is more expensive), or one with lowest
+ index, to avoid random changes with different orders of the edges. */
+ for (e = block->pred; e ; e = e->pred_next)
+ {
+ if (e->flags & EDGE_DFS_BACK)
+ ;
+ else if (! beste)
+ beste = e;
+ else if (EDGE_FREQUENCY (beste) < EDGE_FREQUENCY (e))
+ beste = e;
+ else if (beste->count < e->count)
+ beste = e;
+ else if (beste->count > e->count)
+ ;
+ else if ((e->flags & EDGE_CRITICAL) != (beste->flags & EDGE_CRITICAL))
+ {
+ if (e->flags & EDGE_CRITICAL)
+ beste = e;
+ }
+ else if (e->src->index < beste->src->index)
+ beste = e;
+ }
+
+ /* Entry block does have stack already initialized. */
+ if (bi->stack_in.top == -2)
+ inserted |= compensate_edge (beste, file);
+ else
+ beste = NULL;
+ current_block = block;
+
if (file)
{
fprintf (file, "\nBasic block %d\nInput stack: ", block->index);
@@ -2546,137 +2730,28 @@ convert_regs_1 (file, block)
GO_IF_HARD_REG_EQUAL (regstack.reg_set, bi->out_reg_set, win);
abort ();
win:
+ bi->stack_out = regstack;
- /* Adjust the stack of this block on exit to match the stack of the
- target block, or copy stack info into the stack of the successor
- of the successor hasn't been processed yet. */
- inserted = 0;
+ /* Compensate the back edges, as those wasn't visited yet. */
for (e = block->succ; e ; e = e->succ_next)
{
- basic_block target = e->dest;
- stack target_stack = &BLOCK_INFO (target)->stack_in;
-
- if (file)
- fprintf (file, "Edge to block %d: ", target->index);
-
- if (target_stack->top == -2)
- {
- /* The target block hasn't had a stack order selected.
- We need merely ensure that no pops are needed. */
- for (reg = regstack.top; reg >= 0; --reg)
- if (! TEST_HARD_REG_BIT (target_stack->reg_set,
- regstack.reg[reg]))
- break;
-
- if (reg == -1)
- {
- if (file)
- fprintf (file, "new block; copying stack position\n");
-
- /* change_stack kills values in regstack. */
- tmpstack = regstack;
-
- change_stack (block->end, &tmpstack,
- target_stack, EMIT_AFTER);
- continue;
- }
-
- if (file)
- fprintf (file, "new block; pops needed\n");
- }
- else
+ if (e->flags & EDGE_DFS_BACK
+ || (e->dest == EXIT_BLOCK_PTR))
{
- if (target_stack->top == regstack.top)
- {
- for (reg = target_stack->top; reg >= 0; --reg)
- if (target_stack->reg[reg] != regstack.reg[reg])
- break;
-
- if (reg == -1)
- {
- if (file)
- fprintf (file, "no changes needed\n");
- continue;
- }
- }
-
- if (file)
- {
- fprintf (file, "correcting stack to ");
- print_stack (file, target_stack);
- }
- }
-
- /* Care for non-call EH edges specially. The normal return path have
- values in registers. These will be popped en masse by the unwind
- library. */
- if ((e->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) == EDGE_EH)
- target_stack->top = -1;
-
- /* Other calls may appear to have values live in st(0), but the
- abnormal return path will not have actually loaded the values. */
- else if (e->flags & EDGE_ABNORMAL_CALL)
- {
- /* Assert that the lifetimes are as we expect -- one value
- live at st(0) on the end of the source block, and no
- values live at the beginning of the destination block. */
- HARD_REG_SET tmp;
-
- CLEAR_HARD_REG_SET (tmp);
- GO_IF_HARD_REG_EQUAL (target_stack->reg_set, tmp, eh1);
- abort();
- eh1:
-
- SET_HARD_REG_BIT (tmp, FIRST_STACK_REG);
- GO_IF_HARD_REG_EQUAL (regstack.reg_set, tmp, eh2);
- abort();
- eh2:
-
- target_stack->top = -1;
- }
-
- /* It is better to output directly to the end of the block
- instead of to the edge, because emit_swap can do minimal
- insn scheduling. We can do this when there is only one
- edge out, and it is not abnormal. */
- else if (block->succ->succ_next == NULL
- && ! (e->flags & EDGE_ABNORMAL))
- {
- /* change_stack kills values in regstack. */
- tmpstack = regstack;
-
- change_stack (block->end, &tmpstack, target_stack,
- (GET_CODE (block->end) == JUMP_INSN
- ? EMIT_BEFORE : EMIT_AFTER));
+ if (!BLOCK_INFO (e->dest)->done
+ && e->dest != block)
+ abort ();
+ inserted |= compensate_edge (e, file);
}
- else
+ }
+ for (e = block->pred; e ; e = e->pred_next)
+ {
+ if (e != beste && !(e->flags & EDGE_DFS_BACK)
+ && e->src != ENTRY_BLOCK_PTR)
{
- rtx seq, after;
-
- /* We don't support abnormal edges. Global takes care to
- avoid any live register across them, so we should never
- have to insert instructions on such edges. */
- if (e->flags & EDGE_ABNORMAL)
+ if (!BLOCK_INFO (e->src)->done)
abort ();
-
- current_block = NULL;
- start_sequence ();
-
- /* ??? change_stack needs some point to emit insns after.
- Also needed to keep gen_sequence from returning a
- pattern as opposed to a sequence, which would lose
- REG_DEAD notes. */
- after = emit_note (NULL, NOTE_INSN_DELETED);
-
- tmpstack = regstack;
- change_stack (after, &tmpstack, target_stack, EMIT_BEFORE);
-
- seq = gen_sequence ();
- end_sequence ();
-
- insert_insn_on_edge (seq, e);
- inserted = 1;
- current_block = block;
+ inserted |= compensate_edge (e, file);
}
}
@@ -2697,7 +2772,6 @@ convert_regs_2 (file, block)
sp = stack;
*sp++ = block;
- BLOCK_INFO (block)->done = 1;
inserted = 0;
do
@@ -2706,12 +2780,14 @@ convert_regs_2 (file, block)
block = *--sp;
inserted |= convert_regs_1 (file, block);
+ BLOCK_INFO (block)->done = 1;
for (e = block->succ; e ; e = e->succ_next)
- if (! BLOCK_INFO (e->dest)->done)
+ if (! (e->flags & EDGE_DFS_BACK))
{
- *sp++ = e->dest;
- BLOCK_INFO (e->dest)->done = 1;
+ BLOCK_INFO (e->dest)->predecesors--;
+ if (!BLOCK_INFO (e->dest)->predecesors)
+ *sp++ = e->dest;
}
}
while (sp != stack);
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 07de29ba4b1..f3b50d14025 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -3473,11 +3473,13 @@ rest_of_compilation (decl)
verify_flow_info ();
#endif
+ compute_bb_for_insn (get_max_uid ());
+
/* If optimizing, then go ahead and split insns now. */
if (optimize > 0)
split_all_insns (0);
- cleanup_cfg (0);
+ cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
/* On some machines, the prologue and epilogue code, or parts thereof,
can be represented as RTL. Doing so lets us schedule insns between
@@ -3485,8 +3487,6 @@ rest_of_compilation (decl)
scheduling to operate in the epilogue. */
thread_prologue_and_epilogue_insns (insns);
- compute_bb_for_insn (get_max_uid ());
-
if (optimize)
{
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_CROSSJUMP);