Commit 0ecf09f9 by Jan Hubicka Committed by Jan Hubicka

i386.c (ix86_output_main_function_alignment_hack): New function.

	* 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.

From-SVN: r44486
parent 1490f392
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> 2001-07-30 Andreas Jaeger <aj@suse.de>
* jump.c: Add prototype for mark_modified_reg. * jump.c: Add prototype for mark_modified_reg.
......
...@@ -107,8 +107,6 @@ static int aliases_everything_p PARAMS ((rtx)); ...@@ -107,8 +107,6 @@ static int aliases_everything_p PARAMS ((rtx));
static int write_dependence_p PARAMS ((rtx, rtx, int)); static int write_dependence_p PARAMS ((rtx, rtx, int));
static int nonlocal_mentioned_p PARAMS ((rtx)); 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. */ /* Set up all info needed to perform alias analysis on memory references. */
/* Returns the size in bytes of the mode of X. */ /* Returns the size in bytes of the mode of X. */
...@@ -2051,96 +2049,6 @@ nonlocal_mentioned_p (x) ...@@ -2051,96 +2049,6 @@ nonlocal_mentioned_p (x)
return 0; 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. */ /* Mark the function if it is constant. */
void void
...@@ -2157,7 +2065,7 @@ mark_constant_function () ...@@ -2157,7 +2065,7 @@ mark_constant_function ()
return; return;
/* A loop might not return which counts as a side effect. */ /* A loop might not return which counts as a side effect. */
if (loop_p ()) if (mark_dfs_back_edges ())
return; return;
nonlocal_mentioned = 0; nonlocal_mentioned = 0;
......
...@@ -145,6 +145,7 @@ typedef struct edge_def { ...@@ -145,6 +145,7 @@ typedef struct edge_def {
#define EDGE_ABNORMAL_CALL 8 #define EDGE_ABNORMAL_CALL 8
#define EDGE_EH 16 #define EDGE_EH 16
#define EDGE_FAKE 32 #define EDGE_FAKE 32
#define EDGE_DFS_BACK 64
#define EDGE_COMPLEX (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH) #define EDGE_COMPLEX (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH)
...@@ -650,6 +651,7 @@ extern void conflict_graph_print PARAMS ((conflict_graph, FILE*)); ...@@ -650,6 +651,7 @@ extern void conflict_graph_print PARAMS ((conflict_graph, FILE*));
extern conflict_graph conflict_graph_compute extern conflict_graph conflict_graph_compute
PARAMS ((regset, PARAMS ((regset,
partition)); partition));
extern bool mark_dfs_back_edges PARAMS ((void));
/* In dominance.c */ /* In dominance.c */
......
...@@ -574,6 +574,7 @@ static HOST_WIDE_INT ix86_GOT_alias_set PARAMS ((void)); ...@@ -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 void ix86_adjust_counter PARAMS ((rtx, HOST_WIDE_INT));
static rtx ix86_expand_aligntest PARAMS ((rtx, int)); static rtx ix86_expand_aligntest PARAMS ((rtx, int));
static void ix86_expand_strlensi_unroll_1 PARAMS ((rtx, rtx)); 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 struct ix86_address
{ {
...@@ -634,6 +635,10 @@ static int ix86_comp_type_attributes PARAMS ((tree, tree)); ...@@ -634,6 +635,10 @@ static int ix86_comp_type_attributes PARAMS ((tree, tree));
HOST_WIDE_INT)); HOST_WIDE_INT));
# undef TARGET_ASM_FUNCTION_PROLOGUE # undef TARGET_ASM_FUNCTION_PROLOGUE
# define TARGET_ASM_FUNCTION_PROLOGUE ix86_osf_output_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 #endif
#undef TARGET_ASM_OPEN_PAREN #undef TARGET_ASM_OPEN_PAREN
...@@ -10775,3 +10780,45 @@ ix86_memory_move_cost (mode, class, in) ...@@ -10775,3 +10780,45 @@ ix86_memory_move_cost (mode, class, in)
* (int) GET_MODE_SIZE (mode) / 4); * (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));
}
...@@ -1528,6 +1528,99 @@ mark_critical_edges () ...@@ -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. /* 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, 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 this function renumbers all the basic blocks so that the new
...@@ -7779,7 +7872,7 @@ dump_edge_info (file, e, do_succ) ...@@ -7779,7 +7872,7 @@ dump_edge_info (file, e, do_succ)
if (e->flags) if (e->flags)
{ {
static const char * const bitnames[] = { static const char * const bitnames[] = {
"fallthru", "crit", "ab", "abcall", "eh", "fake" "fallthru", "crit", "ab", "abcall", "eh", "fake", "dfs_back"
}; };
int comma = 0; int comma = 0;
int i, flags = e->flags; int i, flags = e->flags;
......
...@@ -7226,7 +7226,8 @@ thread_prologue_and_epilogue_insns (f) ...@@ -7226,7 +7226,8 @@ thread_prologue_and_epilogue_insns (f)
inserted = 1; inserted = 1;
} }
else else
emit_insn_after (seq, f); set_block_for_new_insns (emit_insn_after (seq, f),
ENTRY_BLOCK_PTR->succ);
} }
#endif #endif
......
...@@ -194,8 +194,11 @@ typedef struct stack_def ...@@ -194,8 +194,11 @@ typedef struct stack_def
typedef struct block_info_def typedef struct block_info_def
{ {
struct stack_def stack_in; /* Input stack configuration. */ 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. */ HARD_REG_SET out_reg_set; /* Stack regs live on output. */
int done; /* True if block already converted. */ int done; /* True if block already converted. */
int predecesors; /* Number of predecesors that needs
to be visited. */
} *block_info; } *block_info;
#define BLOCK_INFO(B) ((block_info) (B)->aux) #define BLOCK_INFO(B) ((block_info) (B)->aux)
...@@ -263,6 +266,7 @@ static int convert_regs PARAMS ((FILE *)); ...@@ -263,6 +266,7 @@ static int convert_regs PARAMS ((FILE *));
static void print_stack PARAMS ((FILE *, stack)); static void print_stack PARAMS ((FILE *, stack));
static rtx next_flags_user PARAMS ((rtx)); static rtx next_flags_user PARAMS ((rtx));
static void record_label_references PARAMS ((rtx, 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. */ /* Return non-zero if any stack register is mentioned somewhere within PAT. */
...@@ -443,11 +447,20 @@ reg_to_stack (first, file) ...@@ -443,11 +447,20 @@ reg_to_stack (first, file)
find_basic_blocks (first, max_reg_num (), file); find_basic_blocks (first, max_reg_num (), file);
count_or_remove_death_notes (NULL, 1); count_or_remove_death_notes (NULL, 1);
life_analysis (first, file, PROP_DEATH_NOTES); life_analysis (first, file, PROP_DEATH_NOTES);
mark_dfs_back_edges ();
/* Set up block info for each basic block. */ /* Set up block info for each basic block. */
bi = (block_info) xcalloc ((n_basic_blocks + 1), sizeof (*bi)); bi = (block_info) xcalloc ((n_basic_blocks + 1), sizeof (*bi));
for (i = n_basic_blocks - 1; i >= 0; --i) 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; EXIT_BLOCK_PTR->aux = bi + n_basic_blocks;
/* Create the replacement registers up front. */ /* Create the replacement registers up front. */
...@@ -2452,120 +2465,31 @@ convert_regs_exit () ...@@ -2452,120 +2465,31 @@ convert_regs_exit ()
} }
} }
/* Convert stack register references in one block. */ /* 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
static int of the successor hasn't been processed yet. */
convert_regs_1 (file, block) static bool
compensate_edge (e, file)
edge e;
FILE *file; FILE *file;
basic_block block;
{ {
struct stack_def regstack, tmpstack; basic_block block = e->src, target = e->dest;
block_info bi = BLOCK_INFO (block); block_info bi = BLOCK_INFO (block);
int inserted, reg; struct stack_def regstack, tmpstack;
rtx insn, next;
edge e;
current_block = block;
if (file)
{
fprintf (file, "\nBasic block %d\nInput stack: ", block->index);
print_stack (file, &bi->stack_in);
}
/* Process all insns in this block. Keep track of NEXT so that we
don't process insns emitted while substituting in INSN. */
next = block->head;
regstack = bi->stack_in;
do
{
insn = next;
next = NEXT_INSN (insn);
/* Ensure we have not missed a block boundary. */
if (next == NULL)
abort ();
if (insn == block->end)
next = NULL;
/* Don't bother processing unless there is a stack reg
mentioned or if it's a CALL_INSN. */
if (stack_regs_mentioned (insn)
|| GET_CODE (insn) == CALL_INSN)
{
if (file)
{
fprintf (file, " insn %d input stack: ",
INSN_UID (insn));
print_stack (file, &regstack);
}
subst_stack_regs (insn, &regstack);
}
}
while (next);
if (file)
{
fprintf (file, "Expected live registers [");
for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
if (TEST_HARD_REG_BIT (bi->out_reg_set, reg))
fprintf (file, " %d", reg);
fprintf (file, " ]\nOutput stack: ");
print_stack (file, &regstack);
}
insn = block->end;
if (GET_CODE (insn) == JUMP_INSN)
insn = PREV_INSN (insn);
/* If the function is declared to return a value, but it returns one
in only some cases, some registers might come live here. Emit
necessary moves for them. */
for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
{
if (TEST_HARD_REG_BIT (bi->out_reg_set, reg)
&& ! TEST_HARD_REG_BIT (regstack.reg_set, reg))
{
rtx set;
if (file)
{
fprintf (file, "Emitting insn initializing reg %d\n",
reg);
}
set = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, SFmode),
nan);
insn = emit_block_insn_after (set, insn, block);
subst_stack_regs (insn, &regstack);
}
}
/* Something failed if the stack lives don't match. */
GO_IF_HARD_REG_EQUAL (regstack.reg_set, bi->out_reg_set, win);
abort ();
win:
/* 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;
for (e = block->succ; e ; e = e->succ_next)
{
basic_block target = e->dest;
stack target_stack = &BLOCK_INFO (target)->stack_in; stack target_stack = &BLOCK_INFO (target)->stack_in;
int reg;
current_block = block;
regstack = bi->stack_out;
if (file) if (file)
fprintf (file, "Edge to block %d: ", target->index); fprintf (file, "Edge %d->%d: ", block->index, target->index);
if (target_stack->top == -2) if (target_stack->top == -2)
{ {
/* The target block hasn't had a stack order selected. /* The target block hasn't had a stack order selected.
We need merely ensure that no pops are needed. */ We need merely ensure that no pops are needed. */
for (reg = regstack.top; reg >= 0; --reg) for (reg = regstack.top; reg >= 0; --reg)
if (! TEST_HARD_REG_BIT (target_stack->reg_set, if (!TEST_HARD_REG_BIT (target_stack->reg_set, regstack.reg[reg]))
regstack.reg[reg]))
break; break;
if (reg == -1) if (reg == -1)
...@@ -2576,9 +2500,8 @@ convert_regs_1 (file, block) ...@@ -2576,9 +2500,8 @@ convert_regs_1 (file, block)
/* change_stack kills values in regstack. */ /* change_stack kills values in regstack. */
tmpstack = regstack; tmpstack = regstack;
change_stack (block->end, &tmpstack, change_stack (block->end, &tmpstack, target_stack, EMIT_AFTER);
target_stack, EMIT_AFTER); return false;
continue;
} }
if (file) if (file)
...@@ -2596,7 +2519,7 @@ convert_regs_1 (file, block) ...@@ -2596,7 +2519,7 @@ convert_regs_1 (file, block)
{ {
if (file) if (file)
fprintf (file, "no changes needed\n"); fprintf (file, "no changes needed\n");
continue; return false;
} }
} }
...@@ -2624,12 +2547,12 @@ convert_regs_1 (file, block) ...@@ -2624,12 +2547,12 @@ convert_regs_1 (file, block)
CLEAR_HARD_REG_SET (tmp); CLEAR_HARD_REG_SET (tmp);
GO_IF_HARD_REG_EQUAL (target_stack->reg_set, tmp, eh1); GO_IF_HARD_REG_EQUAL (target_stack->reg_set, tmp, eh1);
abort(); abort ();
eh1: eh1:
SET_HARD_REG_BIT (tmp, FIRST_STACK_REG); SET_HARD_REG_BIT (tmp, FIRST_STACK_REG);
GO_IF_HARD_REG_EQUAL (regstack.reg_set, tmp, eh2); GO_IF_HARD_REG_EQUAL (regstack.reg_set, tmp, eh2);
abort(); abort ();
eh2: eh2:
target_stack->top = -1; target_stack->top = -1;
...@@ -2639,8 +2562,7 @@ convert_regs_1 (file, block) ...@@ -2639,8 +2562,7 @@ convert_regs_1 (file, block)
instead of to the edge, because emit_swap can do minimal instead of to the edge, because emit_swap can do minimal
insn scheduling. We can do this when there is only one insn scheduling. We can do this when there is only one
edge out, and it is not abnormal. */ edge out, and it is not abnormal. */
else if (block->succ->succ_next == NULL else if (block->succ->succ_next == NULL && !(e->flags & EDGE_ABNORMAL))
&& ! (e->flags & EDGE_ABNORMAL))
{ {
/* change_stack kills values in regstack. */ /* change_stack kills values in regstack. */
tmpstack = regstack; tmpstack = regstack;
...@@ -2675,8 +2597,161 @@ convert_regs_1 (file, block) ...@@ -2675,8 +2597,161 @@ convert_regs_1 (file, block)
end_sequence (); end_sequence ();
insert_insn_on_edge (seq, e); insert_insn_on_edge (seq, e);
inserted = 1; return true;
}
return false;
}
/* Convert stack register references in one block. */
static int
convert_regs_1 (file, block)
FILE *file;
basic_block block;
{
struct stack_def regstack;
block_info bi = BLOCK_INFO (block);
int inserted, reg;
rtx insn, next;
edge e, beste = NULL;
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; current_block = block;
if (file)
{
fprintf (file, "\nBasic block %d\nInput stack: ", block->index);
print_stack (file, &bi->stack_in);
}
/* Process all insns in this block. Keep track of NEXT so that we
don't process insns emitted while substituting in INSN. */
next = block->head;
regstack = bi->stack_in;
do
{
insn = next;
next = NEXT_INSN (insn);
/* Ensure we have not missed a block boundary. */
if (next == NULL)
abort ();
if (insn == block->end)
next = NULL;
/* Don't bother processing unless there is a stack reg
mentioned or if it's a CALL_INSN. */
if (stack_regs_mentioned (insn)
|| GET_CODE (insn) == CALL_INSN)
{
if (file)
{
fprintf (file, " insn %d input stack: ",
INSN_UID (insn));
print_stack (file, &regstack);
}
subst_stack_regs (insn, &regstack);
}
}
while (next);
if (file)
{
fprintf (file, "Expected live registers [");
for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
if (TEST_HARD_REG_BIT (bi->out_reg_set, reg))
fprintf (file, " %d", reg);
fprintf (file, " ]\nOutput stack: ");
print_stack (file, &regstack);
}
insn = block->end;
if (GET_CODE (insn) == JUMP_INSN)
insn = PREV_INSN (insn);
/* If the function is declared to return a value, but it returns one
in only some cases, some registers might come live here. Emit
necessary moves for them. */
for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
{
if (TEST_HARD_REG_BIT (bi->out_reg_set, reg)
&& ! TEST_HARD_REG_BIT (regstack.reg_set, reg))
{
rtx set;
if (file)
{
fprintf (file, "Emitting insn initializing reg %d\n",
reg);
}
set = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, SFmode),
nan);
insn = emit_block_insn_after (set, insn, block);
subst_stack_regs (insn, &regstack);
}
}
/* Something failed if the stack lives don't match. */
GO_IF_HARD_REG_EQUAL (regstack.reg_set, bi->out_reg_set, win);
abort ();
win:
bi->stack_out = regstack;
/* Compensate the back edges, as those wasn't visited yet. */
for (e = block->succ; e ; e = e->succ_next)
{
if (e->flags & EDGE_DFS_BACK
|| (e->dest == EXIT_BLOCK_PTR))
{
if (!BLOCK_INFO (e->dest)->done
&& e->dest != block)
abort ();
inserted |= compensate_edge (e, file);
}
}
for (e = block->pred; e ; e = e->pred_next)
{
if (e != beste && !(e->flags & EDGE_DFS_BACK)
&& e->src != ENTRY_BLOCK_PTR)
{
if (!BLOCK_INFO (e->src)->done)
abort ();
inserted |= compensate_edge (e, file);
} }
} }
...@@ -2697,7 +2772,6 @@ convert_regs_2 (file, block) ...@@ -2697,7 +2772,6 @@ convert_regs_2 (file, block)
sp = stack; sp = stack;
*sp++ = block; *sp++ = block;
BLOCK_INFO (block)->done = 1;
inserted = 0; inserted = 0;
do do
...@@ -2706,12 +2780,14 @@ convert_regs_2 (file, block) ...@@ -2706,12 +2780,14 @@ convert_regs_2 (file, block)
block = *--sp; block = *--sp;
inserted |= convert_regs_1 (file, block); inserted |= convert_regs_1 (file, block);
BLOCK_INFO (block)->done = 1;
for (e = block->succ; e ; e = e->succ_next) for (e = block->succ; e ; e = e->succ_next)
if (! BLOCK_INFO (e->dest)->done) if (! (e->flags & EDGE_DFS_BACK))
{ {
BLOCK_INFO (e->dest)->predecesors--;
if (!BLOCK_INFO (e->dest)->predecesors)
*sp++ = e->dest; *sp++ = e->dest;
BLOCK_INFO (e->dest)->done = 1;
} }
} }
while (sp != stack); while (sp != stack);
......
...@@ -3473,11 +3473,13 @@ rest_of_compilation (decl) ...@@ -3473,11 +3473,13 @@ rest_of_compilation (decl)
verify_flow_info (); verify_flow_info ();
#endif #endif
compute_bb_for_insn (get_max_uid ());
/* If optimizing, then go ahead and split insns now. */ /* If optimizing, then go ahead and split insns now. */
if (optimize > 0) if (optimize > 0)
split_all_insns (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, /* On some machines, the prologue and epilogue code, or parts thereof,
can be represented as RTL. Doing so lets us schedule insns between can be represented as RTL. Doing so lets us schedule insns between
...@@ -3485,8 +3487,6 @@ rest_of_compilation (decl) ...@@ -3485,8 +3487,6 @@ rest_of_compilation (decl)
scheduling to operate in the epilogue. */ scheduling to operate in the epilogue. */
thread_prologue_and_epilogue_insns (insns); thread_prologue_and_epilogue_insns (insns);
compute_bb_for_insn (get_max_uid ());
if (optimize) if (optimize)
{ {
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_CROSSJUMP); cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_CROSSJUMP);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment