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 predecessors; /* Number of predecessors that needs
+ int predecessors; /* Number of predecessors that need
to be visited. */
} *block_info;
static bool
compensate_edge (edge e, FILE *file)
{
- basic_block block = e->src, target = e->dest;
- block_info bi = BLOCK_INFO (block);
- struct stack_def regstack, tmpstack;
+ basic_block source = e->src, target = e->dest;
stack target_stack = &BLOCK_INFO (target)->stack_in;
+ stack source_stack = &BLOCK_INFO (source)->stack_out;
+ struct stack_def regstack;
int reg;
- current_block = block;
- regstack = bi->stack_out;
if (file)
- fprintf (file, "Edge %d->%d: ", block->index, target->index);
+ fprintf (file, "Edge %d->%d: ", source->index, target->index);
gcc_assert (target_stack->top != -2);
/* Check whether stacks are identical. */
- if (target_stack->top == regstack.top)
+ if (target_stack->top == source_stack->top)
{
for (reg = target_stack->top; reg >= 0; --reg)
- if (target_stack->reg[reg] != regstack.reg[reg])
+ if (target_stack->reg[reg] != source_stack->reg[reg])
break;
if (reg == -1)
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 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)
+ 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);
- gcc_unreachable ();
- eh1:
-
- /* We are sure that there is st(0) live, otherwise we won't compensate.
- For complex return values, we may have st(1) live as well. */
- SET_HARD_REG_BIT (tmp, FIRST_STACK_REG);
- if (TEST_HARD_REG_BIT (regstack.reg_set, FIRST_STACK_REG + 1))
- SET_HARD_REG_BIT (tmp, FIRST_STACK_REG + 1);
- GO_IF_HARD_REG_EQUAL (regstack.reg_set, tmp, eh2);
- gcc_unreachable ();
- eh2:
+ gcc_assert (source_stack->top == 0);
+ gcc_assert (target_stack->top == -1);
+ return false;
+ }
- target_stack->top = -1;
+ /* Handle 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)
+ {
+ gcc_assert (target_stack->top == -1);
+ return false;
}
+ /* 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. */
+ gcc_assert (! (e->flags & EDGE_ABNORMAL));
+
+ /* Make a copy of source_stack as change_stack is destructive. */
+ regstack = *source_stack;
+
/* 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 (EDGE_COUNT (block->succs) == 1 && !(e->flags & EDGE_ABNORMAL))
+ if (EDGE_COUNT (source->succs) == 1)
{
- /* change_stack kills values in regstack. */
- tmpstack = regstack;
-
- change_stack (BB_END (block), &tmpstack, target_stack,
- (JUMP_P (BB_END (block))
- ? EMIT_BEFORE : EMIT_AFTER));
+ current_block = source;
+ change_stack (BB_END (source), ®stack, target_stack,
+ (JUMP_P (BB_END (source)) ? 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. */
- gcc_assert (!(e->flags & EDGE_ABNORMAL));
-
current_block = NULL;
start_sequence ();
/* ??? change_stack needs some point to emit insns after. */
after = emit_note (NOTE_INSN_DELETED);
- tmpstack = regstack;
- change_stack (after, &tmpstack, target_stack, EMIT_BEFORE);
+ change_stack (after, ®stack, target_stack, EMIT_BEFORE);
seq = get_insns ();
end_sequence ();
gcc_assert (any_malformed_asm);
win:
bi->stack_out = regstack;
+ bi->done = true;
}
/* Convert registers in all blocks reachable from BLOCK. */
}
convert_regs_1 (file, block);
- BLOCK_INFO (block)->done = 1;
}
while (sp != stack);