re PR rtl-optimization/23601 (reload may drop non-call exception information)

PR rtl-opt/23601
        * reload1.c (reload): Set MEM_NOTRAP_P in spill slots.
        (fixup_eh_region_note): New.
        (reload_as_needed): Call it.
        (fixup_abnormal_edges): Allow all throwing insns to be deleted;
        don't call find_many_sub_basic_blocks; call verify_flow_info.
        * function.c (assign_stack_local_1): Set MEM_NOTRAP_P.
        (keep_stack_depressed): Likewise.
        (assign_stack_temp_for_type): Likewise; use adjust_address_nv.

From-SVN: r103680
This commit is contained in:
Richard Henderson 2005-08-31 09:26:51 -07:00 committed by Richard Henderson
parent 5d3018cee7
commit be0c514c74
3 changed files with 122 additions and 40 deletions

View File

@ -1,3 +1,15 @@
2005-08-31 Richard Henderson <rth@redhat.com>
PR rtl-opt/23601
* reload1.c (reload): Set MEM_NOTRAP_P in spill slots.
(fixup_eh_region_note): New.
(reload_as_needed): Call it.
(fixup_abnormal_edges): Allow all throwing insns to be deleted;
don't call find_many_sub_basic_blocks; call verify_flow_info.
* function.c (assign_stack_local_1): Set MEM_NOTRAP_P.
(keep_stack_depressed): Likewise.
(assign_stack_temp_for_type): Likewise; use adjust_address_nv.
2005-08-31 Richard Henderson <rth@redhat.com>
* config/i386/i386.c (ix86_function_ok_for_sibcall): Fix test for

View File

@ -474,6 +474,7 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size, int align,
function->x_frame_offset += size;
x = gen_rtx_MEM (mode, addr);
MEM_NOTRAP_P (x) = 1;
function->x_stack_slot_list
= gen_rtx_EXPR_LIST (VOIDmode, x, function->x_stack_slot_list);
@ -649,9 +650,7 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size,
p->size = best_p->size - rounded_size;
p->base_offset = best_p->base_offset + rounded_size;
p->full_size = best_p->full_size - rounded_size;
p->slot = gen_rtx_MEM (BLKmode,
plus_constant (XEXP (best_p->slot, 0),
rounded_size));
p->slot = adjust_address_nv (best_p->slot, BLKmode, rounded_size);
p->align = best_p->align;
p->address = 0;
p->type = best_p->type;
@ -743,6 +742,7 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size,
MEM_VOLATILE_P (slot) = TYPE_VOLATILE (type);
MEM_SET_IN_STRUCT_P (slot, AGGREGATE_TYPE_P (type));
}
MEM_NOTRAP_P (slot) = 1;
return slot;
}
@ -4822,6 +4822,7 @@ keep_stack_depressed (rtx insns)
info.sp_offset));
retaddr = gen_rtx_MEM (Pmode, retaddr);
MEM_NOTRAP_P (retaddr) = 1;
/* If there is a pending load to the equivalent register for SP
and we reference that register, we must load our address into

View File

@ -1125,6 +1125,7 @@ reload (rtx first, int global)
MEM_IN_STRUCT_P (reg) = MEM_SCALAR_P (reg) = 0;
MEM_ATTRS (reg) = 0;
}
MEM_NOTRAP_P (reg) = 1;
}
else if (reg_equiv_mem[i])
XEXP (reg_equiv_mem[i], 0) = addr;
@ -3758,6 +3759,55 @@ scan_paradoxical_subregs (rtx x)
}
}
/* A subroutine of reload_as_needed. If INSN has a REG_EH_REGION note,
examine all of the reload insns between PREV and NEXT exclusive, and
annotate all that may trap. */
static void
fixup_eh_region_note (rtx insn, rtx prev, rtx next)
{
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
unsigned int trap_count;
rtx i;
if (note == NULL)
return;
if (may_trap_p (PATTERN (insn)))
trap_count = 1;
else
{
remove_note (insn, note);
trap_count = 0;
}
for (i = NEXT_INSN (prev); i != next; i = NEXT_INSN (i))
if (INSN_P (i) && i != insn && may_trap_p (PATTERN (i)))
{
trap_count++;
REG_NOTES (i)
= gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (note, 0), REG_NOTES (i));
}
/* ??? Since we entered with one eh insn, we should exit with one eh insn;
otherwise we're unsure that we're not losing an exception. Except that
the instruction stream incoming to reload doesn't pass the "if
reg_eh_region is present, may_trap_p is true" smoke test.
Worse, even if it did, rtx_addr_can_trap_p returns false for some forms
of address that include constants regardless of the actual value of the
constant. If we decide that "int a[3]; a[100000]" should be considered
non-trapping, we should get that story straight across more of the
compiler. If we decide that it should trap, then we cannot decide
may_trap_p on the basis of rtx_addr_can_trap_p at all. Which may not
be such a big thing -- it doesn't seem hard to get MEM_NOTRAP_P set
correctly in the first place.
Fixing all that is not in the cards for gcc 4.2, so for the nonce we
allow all eh insns to evaporate. */
gcc_assert (trap_count <= 1);
}
/* Reload pseudo-registers into hard regs around each insn as needed.
Additional register load insns are output before the insn that needs it
and perhaps store insns after insns that modify the reloaded pseudo reg.
@ -3875,10 +3925,13 @@ reload_as_needed (int live_known)
and that we moved the structure into). */
subst_reloads (insn);
/* Adjust the exception region notes for loads and stores. */
if (flag_non_call_exceptions)
fixup_eh_region_note (insn, prev, next);
/* If this was an ASM, make sure that all the reload insns
we have generated are valid. If not, give an error
and delete them. */
if (asm_noperands (PATTERN (insn)) >= 0)
for (p = NEXT_INSN (prev); p != next; p = NEXT_INSN (p))
if (p != insn && INSN_P (p)
@ -8080,55 +8133,71 @@ fixup_abnormal_edges (void)
if (e && !CALL_P (BB_END (bb))
&& !can_throw_internal (BB_END (bb)))
{
rtx insn = BB_END (bb), stop = NEXT_INSN (BB_END (bb));
rtx next;
FOR_EACH_EDGE (e, ei, bb->succs)
if (e->flags & EDGE_FALLTHRU)
break;
/* Get past the new insns generated. Allow notes, as the insns may
be already deleted. */
rtx insn;
/* Get past the new insns generated. Allow notes, as the insns
may be already deleted. */
insn = BB_END (bb);
while ((NONJUMP_INSN_P (insn) || NOTE_P (insn))
&& !can_throw_internal (insn)
&& insn != BB_HEAD (bb))
insn = PREV_INSN (insn);
gcc_assert (CALL_P (insn) || can_throw_internal (insn));
BB_END (bb) = insn;
inserted = true;
insn = NEXT_INSN (insn);
while (insn && insn != stop)
if (CALL_P (insn) || can_throw_internal (insn))
{
next = NEXT_INSN (insn);
if (INSN_P (insn))
rtx stop, next;
stop = NEXT_INSN (BB_END (bb));
BB_END (bb) = insn;
insn = NEXT_INSN (insn);
FOR_EACH_EDGE (e, ei, bb->succs)
if (e->flags & EDGE_FALLTHRU)
break;
while (insn && insn != stop)
{
delete_insn (insn);
/* Sometimes there's still the return value USE.
If it's placed after a trapping call (i.e. that
call is the last insn anyway), we have no fallthru
edge. Simply delete this use and don't try to insert
on the non-existent edge. */
if (GET_CODE (PATTERN (insn)) != USE)
next = NEXT_INSN (insn);
if (INSN_P (insn))
{
/* We're not deleting it, we're moving it. */
INSN_DELETED_P (insn) = 0;
PREV_INSN (insn) = NULL_RTX;
NEXT_INSN (insn) = NULL_RTX;
delete_insn (insn);
insert_insn_on_edge (insn, e);
/* Sometimes there's still the return value USE.
If it's placed after a trapping call (i.e. that
call is the last insn anyway), we have no fallthru
edge. Simply delete this use and don't try to insert
on the non-existent edge. */
if (GET_CODE (PATTERN (insn)) != USE)
{
/* We're not deleting it, we're moving it. */
INSN_DELETED_P (insn) = 0;
PREV_INSN (insn) = NULL_RTX;
NEXT_INSN (insn) = NULL_RTX;
insert_insn_on_edge (insn, e);
inserted = true;
}
}
insn = next;
}
insn = next;
}
/* It may be that we don't find any such trapping insn. In this
case we discovered quite late that the insn that had been
marked as can_throw_internal in fact couldn't trap at all.
So we should in fact delete the EH edges out of the block. */
else
purge_dead_edges (bb);
}
}
/* We've possibly turned single trapping insn into multiple ones. */
if (flag_non_call_exceptions)
{
sbitmap blocks;
blocks = sbitmap_alloc (last_basic_block);
sbitmap_ones (blocks);
find_many_sub_basic_blocks (blocks);
}
if (inserted)
commit_edge_insertions ();
#ifdef ENABLE_CHECKING
/* Verify that we didn't turn one trapping insn into many, and that
we found and corrected all of the problems wrt fixups on the
fallthru edge. */
verify_flow_info ();
#endif
}