diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2001-07-30 20:30:23 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2001-07-30 20:30:23 +0000 |
commit | ecb7b89177c4cec230e1775fb7feb2f3dd77a5c9 (patch) | |
tree | df492d486710873b66c3b9b278a0eac02a7df6c8 | |
parent | 87f01205933bc3787a0ef34d9401e4c297e97d7c (diff) | |
download | gcc-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/ChangeLog | 25 | ||||
-rw-r--r-- | gcc/alias.c | 94 | ||||
-rw-r--r-- | gcc/basic-block.h | 2 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 47 | ||||
-rw-r--r-- | gcc/flow.c | 95 | ||||
-rw-r--r-- | gcc/function.c | 3 | ||||
-rw-r--r-- | gcc/reg-stack.c | 340 | ||||
-rw-r--r-- | gcc/toplev.c | 6 |
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); |