Commit 9a08d230 by Richard Henderson Committed by Richard Henderson

re PR debug/49864 (ICE: in maybe_record_trace_start, at dwarf2cfi.c:2439)

PR target/49864
	* reg-notes.def (REG_ARGS_SIZE): New.
	* calls.c (emit_call_1): Emit REG_ARGS_SIZE for call_pop.
	(expand_call): Add REG_ARGS_SIZE to emit_stack_restore.
	* cfgcleanup.c (old_insns_match_p): Don't allow cross-jumping to
	different stack levels.
	* combine-stack-adj.c (adjust_frame_related_expr): Remove.
	(maybe_move_args_size_note): New.
	(combine_stack_adjustments_for_block): Use it.
	* combine.c (distribute_notes): Place REG_ARGS_SIZE.
	* dwarf2cfi.c (dw_cfi_row_struct): Remove args_size member.
	(dw_trace_info): Add beg_true_args_size, end_true_args_size,
	beg_delay_args_size, end_delay_args_size, eh_head, args_size_undefined.
	(cur_cfa): New.
	(queued_args_size): Remove.
	(add_cfi_args_size): Assert size is non-negative.
	(stack_adjust_offset, dwarf2out_args_size): Remove.
	(dwarf2out_stack_adjust, dwarf2out_notice_stack_adjust): Remove.
	(notice_args_size, notice_eh_throw): New.
	(dwarf2out_frame_debug_def_cfa): Use cur_cfa.
	(dwarf2out_frame_debug_adjust_cfa): Likewise.
	(dwarf2out_frame_debug_cfa_offset): Likewise.
	(dwarf2out_frame_debug_expr): Likewise.  Don't stack_adjust_offset.
	(dwarf2out_frame_debug): Don't handle non-frame-related-p insns.
	(change_cfi_row): Don't emit args_size.
	(maybe_record_trace_start_abnormal): Split out from ...
	(maybe_record_trace_start): Here.  Set args_size_undefined.
	(create_trace_edges): Update to match.
	(scan_trace): Handle REG_ARGS_SIZE.
	(connect_traces): Connect args_size between EH insns.
	* emit-rtl.c (try_split): Handle REG_ARGS_SIZE.
	* explow.c (suppress_reg_args_size): New.
	(adjust_stack_1): Split out from ...
	(adjust_stack): ... here.
	(anti_adjust_stack): Use it.
	(allocate_dynamic_stack_space): Suppress REG_ARGS_SIZE.
	* expr.c (mem_autoinc_base): New.
	(fixup_args_size_notes): New.
	(emit_single_push_insn_1): Rename from emit_single_push_insn.
	(emit_single_push_insn): New.  Generate REG_ARGS_SIZE.
	* recog.c (peep2_attempt): Handle REG_ARGS_SIZE.
	* reload1.c (reload_as_needed): Likewise.
	* rtl.h (fixup_args_size_notes): Declare.

From-SVN: r177218
parent cde7b553
2011-08-02 Richard Henderson <rth@redhat.com>
PR target/49864
* reg-notes.def (REG_ARGS_SIZE): New.
* calls.c (emit_call_1): Emit REG_ARGS_SIZE for call_pop.
(expand_call): Add REG_ARGS_SIZE to emit_stack_restore.
* cfgcleanup.c (old_insns_match_p): Don't allow cross-jumping to
different stack levels.
* combine-stack-adj.c (adjust_frame_related_expr): Remove.
(maybe_move_args_size_note): New.
(combine_stack_adjustments_for_block): Use it.
* combine.c (distribute_notes): Place REG_ARGS_SIZE.
* dwarf2cfi.c (dw_cfi_row_struct): Remove args_size member.
(dw_trace_info): Add beg_true_args_size, end_true_args_size,
beg_delay_args_size, end_delay_args_size, eh_head, args_size_undefined.
(cur_cfa): New.
(queued_args_size): Remove.
(add_cfi_args_size): Assert size is non-negative.
(stack_adjust_offset, dwarf2out_args_size): Remove.
(dwarf2out_stack_adjust, dwarf2out_notice_stack_adjust): Remove.
(notice_args_size, notice_eh_throw): New.
(dwarf2out_frame_debug_def_cfa): Use cur_cfa.
(dwarf2out_frame_debug_adjust_cfa): Likewise.
(dwarf2out_frame_debug_cfa_offset): Likewise.
(dwarf2out_frame_debug_expr): Likewise. Don't stack_adjust_offset.
(dwarf2out_frame_debug): Don't handle non-frame-related-p insns.
(change_cfi_row): Don't emit args_size.
(maybe_record_trace_start_abnormal): Split out from ...
(maybe_record_trace_start): Here. Set args_size_undefined.
(create_trace_edges): Update to match.
(scan_trace): Handle REG_ARGS_SIZE.
(connect_traces): Connect args_size between EH insns.
* emit-rtl.c (try_split): Handle REG_ARGS_SIZE.
* explow.c (suppress_reg_args_size): New.
(adjust_stack_1): Split out from ...
(adjust_stack): ... here.
(anti_adjust_stack): Use it.
(allocate_dynamic_stack_space): Suppress REG_ARGS_SIZE.
* expr.c (mem_autoinc_base): New.
(fixup_args_size_notes): New.
(emit_single_push_insn_1): Rename from emit_single_push_insn.
(emit_single_push_insn): New. Generate REG_ARGS_SIZE.
* recog.c (peep2_attempt): Handle REG_ARGS_SIZE.
* reload1.c (reload_as_needed): Likewise.
* rtl.h (fixup_args_size_notes): Declare.
2011-08-02 Paolo Carlini <paolo.carlini@oracle.com> 2011-08-02 Paolo Carlini <paolo.carlini@oracle.com>
PR bootstrap/49914 PR bootstrap/49914
......
...@@ -434,6 +434,8 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU ...@@ -434,6 +434,8 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU
rounded_stack_size_rtx = GEN_INT (rounded_stack_size); rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
stack_pointer_delta -= n_popped; stack_pointer_delta -= n_popped;
add_reg_note (call_insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
/* If popup is needed, stack realign must use DRAP */ /* If popup is needed, stack realign must use DRAP */
if (SUPPORTS_STACK_ALIGNMENT) if (SUPPORTS_STACK_ALIGNMENT)
crtl->need_drap = true; crtl->need_drap = true;
...@@ -3126,8 +3128,19 @@ expand_call (tree exp, rtx target, int ignore) ...@@ -3126,8 +3128,19 @@ expand_call (tree exp, rtx target, int ignore)
if (old_stack_level) if (old_stack_level)
{ {
rtx last, set;
emit_stack_restore (SAVE_BLOCK, old_stack_level); emit_stack_restore (SAVE_BLOCK, old_stack_level);
stack_pointer_delta = old_stack_pointer_delta; stack_pointer_delta = old_stack_pointer_delta;
/* ??? Is this assert warrented, given emit_stack_restore?
or should we just mark the last insn no matter what? */
last = get_last_insn ();
set = single_set (last);
gcc_assert (set != NULL);
gcc_assert (SET_DEST (set) == stack_pointer_rtx);
add_reg_note (last, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
pending_stack_adjust = old_pending_adj; pending_stack_adjust = old_pending_adj;
old_stack_allocated = stack_pointer_delta - pending_stack_adjust; old_stack_allocated = stack_pointer_delta - pending_stack_adjust;
stack_arg_under_construction = old_stack_arg_under_construction; stack_arg_under_construction = old_stack_arg_under_construction;
......
...@@ -1078,6 +1078,16 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2) ...@@ -1078,6 +1078,16 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
if (NOTE_INSN_BASIC_BLOCK_P (i1) && NOTE_INSN_BASIC_BLOCK_P (i2)) if (NOTE_INSN_BASIC_BLOCK_P (i1) && NOTE_INSN_BASIC_BLOCK_P (i2))
return dir_both; return dir_both;
/* ??? Do not allow cross-jumping between different stack levels. */
p1 = find_reg_note (i1, REG_ARGS_SIZE, NULL);
p2 = find_reg_note (i2, REG_ARGS_SIZE, NULL);
if (p1)
p1 = XEXP (p1, 0);
if (p2)
p2 = XEXP (p2, 0);
if (!rtx_equal_p (p1, p2))
return dir_none;
p1 = PATTERN (i1); p1 = PATTERN (i1);
p2 = PATTERN (i2); p2 = PATTERN (i2);
......
...@@ -296,68 +296,22 @@ record_stack_refs (rtx *xp, void *data) ...@@ -296,68 +296,22 @@ record_stack_refs (rtx *xp, void *data)
return 0; return 0;
} }
/* Adjust or create REG_FRAME_RELATED_EXPR note when merging a stack /* If INSN has a REG_ARGS_SIZE note, move it to LAST. */
adjustment into a frame related insn. */
static void static void
adjust_frame_related_expr (rtx last_sp_set, rtx insn, maybe_move_args_size_note (rtx last, rtx insn)
HOST_WIDE_INT this_adjust)
{ {
rtx note = find_reg_note (last_sp_set, REG_FRAME_RELATED_EXPR, NULL_RTX); rtx note, last_note;
rtx new_expr = NULL_RTX;
if (note == NULL_RTX && RTX_FRAME_RELATED_P (insn)) note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
if (note == NULL)
return; return;
if (note last_note = find_reg_note (last, REG_ARGS_SIZE, NULL_RTX);
&& GET_CODE (XEXP (note, 0)) == SEQUENCE if (last_note)
&& XVECLEN (XEXP (note, 0), 0) >= 2) XEXP (last_note, 0) = XEXP (note, 0);
{
rtx expr = XEXP (note, 0);
rtx last = XVECEXP (expr, 0, XVECLEN (expr, 0) - 1);
int i;
if (GET_CODE (last) == SET
&& RTX_FRAME_RELATED_P (last) == RTX_FRAME_RELATED_P (insn)
&& SET_DEST (last) == stack_pointer_rtx
&& GET_CODE (SET_SRC (last)) == PLUS
&& XEXP (SET_SRC (last), 0) == stack_pointer_rtx
&& CONST_INT_P (XEXP (SET_SRC (last), 1)))
{
XEXP (SET_SRC (last), 1)
= GEN_INT (INTVAL (XEXP (SET_SRC (last), 1)) + this_adjust);
return;
}
new_expr = gen_rtx_SEQUENCE (VOIDmode,
rtvec_alloc (XVECLEN (expr, 0) + 1));
for (i = 0; i < XVECLEN (expr, 0); i++)
XVECEXP (new_expr, 0, i) = XVECEXP (expr, 0, i);
}
else
{
new_expr = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (2));
if (note)
XVECEXP (new_expr, 0, 0) = XEXP (note, 0);
else
{
rtx expr = copy_rtx (single_set_for_csa (last_sp_set));
XEXP (SET_SRC (expr), 1)
= GEN_INT (INTVAL (XEXP (SET_SRC (expr), 1)) - this_adjust);
RTX_FRAME_RELATED_P (expr) = 1;
XVECEXP (new_expr, 0, 0) = expr;
}
}
XVECEXP (new_expr, 0, XVECLEN (new_expr, 0) - 1)
= copy_rtx (single_set_for_csa (insn));
RTX_FRAME_RELATED_P (XVECEXP (new_expr, 0, XVECLEN (new_expr, 0) - 1))
= RTX_FRAME_RELATED_P (insn);
if (note)
XEXP (note, 0) = new_expr;
else else
add_reg_note (last_sp_set, REG_FRAME_RELATED_EXPR, new_expr); add_reg_note (last, REG_ARGS_SIZE, XEXP (note, 0));
} }
/* Subroutine of combine_stack_adjustments, called for each basic block. */ /* Subroutine of combine_stack_adjustments, called for each basic block. */
...@@ -431,9 +385,8 @@ combine_stack_adjustments_for_block (basic_block bb) ...@@ -431,9 +385,8 @@ combine_stack_adjustments_for_block (basic_block bb)
last_sp_adjust + this_adjust, last_sp_adjust + this_adjust,
this_adjust)) this_adjust))
{ {
if (RTX_FRAME_RELATED_P (last_sp_set)) maybe_move_args_size_note (last_sp_set, insn);
adjust_frame_related_expr (last_sp_set, insn,
this_adjust);
/* It worked! */ /* It worked! */
delete_insn (insn); delete_insn (insn);
last_sp_adjust += this_adjust; last_sp_adjust += this_adjust;
......
...@@ -13273,6 +13273,16 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2, ...@@ -13273,6 +13273,16 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
} }
break; break;
case REG_ARGS_SIZE:
{
/* ??? How to distribute between i3-i1. Assume i3 contains the
entire adjustment. Assert i3 contains at least some adjust. */
int old_size, args_size = INTVAL (XEXP (note, 0));
old_size = fixup_args_size_notes (PREV_INSN (i3), i3, args_size);
gcc_assert (old_size != args_size);
}
break;
case REG_NORETURN: case REG_NORETURN:
case REG_SETJMP: case REG_SETJMP:
/* These notes must remain with the call. It should not be /* These notes must remain with the call. It should not be
......
...@@ -70,9 +70,6 @@ typedef struct GTY(()) dw_cfi_row_struct ...@@ -70,9 +70,6 @@ typedef struct GTY(()) dw_cfi_row_struct
/* The expressions for any register column that is saved. */ /* The expressions for any register column that is saved. */
cfi_vec reg_save; cfi_vec reg_save;
/* The value of any DW_CFA_GNU_args_size. */
HOST_WIDE_INT args_size;
} dw_cfi_row; } dw_cfi_row;
/* The caller's ORIG_REG is saved in SAVED_IN_REG. */ /* The caller's ORIG_REG is saved in SAVED_IN_REG. */
...@@ -109,6 +106,16 @@ typedef struct ...@@ -109,6 +106,16 @@ typedef struct
/* The row state at the beginning and end of the trace. */ /* The row state at the beginning and end of the trace. */
dw_cfi_row *beg_row, *end_row; dw_cfi_row *beg_row, *end_row;
/* Tracking for DW_CFA_GNU_args_size. The "true" sizes are those we find
while scanning insns. However, the args_size value is irrelevant at
any point except can_throw_internal_p insns. Therefore the "delay"
sizes the values that must actually be emitted for this trace. */
HOST_WIDE_INT beg_true_args_size, end_true_args_size;
HOST_WIDE_INT beg_delay_args_size, end_delay_args_size;
/* The first EH insn in the trace, where beg_delay_args_size must be set. */
rtx eh_head;
/* The following variables contain data used in interpreting frame related /* The following variables contain data used in interpreting frame related
expressions. These are not part of the "real" row state as defined by expressions. These are not part of the "real" row state as defined by
Dwarf, but it seems like they need to be propagated into a trace in case Dwarf, but it seems like they need to be propagated into a trace in case
...@@ -141,6 +148,9 @@ typedef struct ...@@ -141,6 +148,9 @@ typedef struct
/* True if this trace immediately follows NOTE_INSN_SWITCH_TEXT_SECTIONS. */ /* True if this trace immediately follows NOTE_INSN_SWITCH_TEXT_SECTIONS. */
bool switch_sections; bool switch_sections;
/* True if we've seen different values incoming to beg_true_args_size. */
bool args_size_undefined;
} dw_trace_info; } dw_trace_info;
DEF_VEC_O (dw_trace_info); DEF_VEC_O (dw_trace_info);
...@@ -179,6 +189,10 @@ static dw_trace_info *cur_trace; ...@@ -179,6 +189,10 @@ static dw_trace_info *cur_trace;
/* The current, i.e. most recently generated, row of the CFI table. */ /* The current, i.e. most recently generated, row of the CFI table. */
static dw_cfi_row *cur_row; static dw_cfi_row *cur_row;
/* A copy of the current CFA, for use during the processing of a
single insn. */
static dw_cfa_location *cur_cfa;
/* We delay emitting a register save until either (a) we reach the end /* We delay emitting a register save until either (a) we reach the end
of the prologue or (b) the register is clobbered. This clusters of the prologue or (b) the register is clobbered. This clusters
register saves so that there are fewer pc advances. */ register saves so that there are fewer pc advances. */
...@@ -194,10 +208,6 @@ DEF_VEC_ALLOC_O (queued_reg_save, heap); ...@@ -194,10 +208,6 @@ DEF_VEC_ALLOC_O (queued_reg_save, heap);
static VEC(queued_reg_save, heap) *queued_reg_saves; static VEC(queued_reg_save, heap) *queued_reg_saves;
/* The (really) current value for DW_CFA_GNU_args_size. We delay actually
emitting this data, i.e. updating CUR_ROW, without async unwind. */
static HOST_WIDE_INT queued_args_size;
/* True if any CFI directives were emitted at the current insn. */ /* True if any CFI directives were emitted at the current insn. */
static bool any_cfis_emitted; static bool any_cfis_emitted;
...@@ -413,6 +423,10 @@ add_cfi_args_size (HOST_WIDE_INT size) ...@@ -413,6 +423,10 @@ add_cfi_args_size (HOST_WIDE_INT size)
{ {
dw_cfi_ref cfi = new_cfi (); dw_cfi_ref cfi = new_cfi ();
/* While we can occasionally have args_size < 0 internally, this state
should not persist at a point we actually need an opcode. */
gcc_assert (size >= 0);
cfi->dw_cfi_opc = DW_CFA_GNU_args_size; cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
cfi->dw_cfi_oprnd1.dw_cfi_offset = size; cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
...@@ -663,16 +677,6 @@ cfi_row_equal_p (dw_cfi_row *a, dw_cfi_row *b) ...@@ -663,16 +677,6 @@ cfi_row_equal_p (dw_cfi_row *a, dw_cfi_row *b)
else if (!cfa_equal_p (&a->cfa, &b->cfa)) else if (!cfa_equal_p (&a->cfa, &b->cfa))
return false; return false;
/* Logic suggests that we compare args_size here. However, if
EXIT_IGNORE_STACK we don't bother tracking the args_size after
the last time it really matters within the function. This does
in fact lead to paths with differing arg_size, but in cases for
which it doesn't matter. */
/* ??? If we really want to sanity check the output of the optimizers,
find a way to backtrack from epilogues to the last EH site. This
would allow us to distinguish regions with garbage args_size and
regions where paths ought to agree. */
n_a = VEC_length (dw_cfi_ref, a->reg_save); n_a = VEC_length (dw_cfi_ref, a->reg_save);
n_b = VEC_length (dw_cfi_ref, b->reg_save); n_b = VEC_length (dw_cfi_ref, b->reg_save);
n_max = MAX (n_a, n_b); n_max = MAX (n_a, n_b);
...@@ -836,214 +840,66 @@ reg_save (unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset) ...@@ -836,214 +840,66 @@ reg_save (unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
update_row_reg_save (cur_row, reg, cfi); update_row_reg_save (cur_row, reg, cfi);
} }
/* Given a SET, calculate the amount of stack adjustment it /* A subroutine of scan_trace. Check INSN for a REG_ARGS_SIZE note
contains. */ and adjust data structures to match. */
static HOST_WIDE_INT
stack_adjust_offset (const_rtx pattern, HOST_WIDE_INT cur_args_size,
HOST_WIDE_INT cur_offset)
{
const_rtx src = SET_SRC (pattern);
const_rtx dest = SET_DEST (pattern);
HOST_WIDE_INT offset = 0;
enum rtx_code code;
if (dest == stack_pointer_rtx)
{
code = GET_CODE (src);
/* Assume (set (reg sp) (reg whatever)) sets args_size
level to 0. */
if (code == REG && src != stack_pointer_rtx)
{
offset = -cur_args_size;
#ifndef STACK_GROWS_DOWNWARD
offset = -offset;
#endif
return offset - cur_offset;
}
if (! (code == PLUS || code == MINUS)
|| XEXP (src, 0) != stack_pointer_rtx
|| !CONST_INT_P (XEXP (src, 1)))
return 0;
/* (set (reg sp) (plus (reg sp) (const_int))) */
offset = INTVAL (XEXP (src, 1));
if (code == PLUS)
offset = -offset;
return offset;
}
if (MEM_P (src) && !MEM_P (dest))
dest = src;
if (MEM_P (dest))
{
/* (set (mem (pre_dec (reg sp))) (foo)) */
src = XEXP (dest, 0);
code = GET_CODE (src);
switch (code)
{
case PRE_MODIFY:
case POST_MODIFY:
if (XEXP (src, 0) == stack_pointer_rtx)
{
rtx val = XEXP (XEXP (src, 1), 1);
/* We handle only adjustments by constant amount. */
gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS
&& CONST_INT_P (val));
offset = -INTVAL (val);
break;
}
return 0;
case PRE_DEC:
case POST_DEC:
if (XEXP (src, 0) == stack_pointer_rtx)
{
offset = GET_MODE_SIZE (GET_MODE (dest));
break;
}
return 0;
case PRE_INC:
case POST_INC:
if (XEXP (src, 0) == stack_pointer_rtx)
{
offset = -GET_MODE_SIZE (GET_MODE (dest));
break;
}
return 0;
default:
return 0;
}
}
else
return 0;
return offset;
}
/* Add a CFI to update the running total of the size of arguments
pushed onto the stack. */
static void static void
dwarf2out_args_size (HOST_WIDE_INT size) notice_args_size (rtx insn)
{ {
if (size == cur_row->args_size) HOST_WIDE_INT args_size, delta;
return; rtx note;
cur_row->args_size = size;
add_cfi_args_size (size);
}
/* Record a stack adjustment of OFFSET bytes. */ note = find_reg_note (insn, REG_ARGS_SIZE, NULL);
if (note == NULL)
static void return;
dwarf2out_stack_adjust (HOST_WIDE_INT offset)
{
dw_cfa_location loc = cur_row->cfa;
if (loc.reg == dw_stack_pointer_regnum) args_size = INTVAL (XEXP (note, 0));
loc.offset += offset; delta = args_size - cur_trace->end_true_args_size;
if (delta == 0)
return;
if (cur_trace->cfa_store.reg == dw_stack_pointer_regnum) cur_trace->end_true_args_size = args_size;
cur_trace->cfa_store.offset += offset;
/* ??? The assumption seems to be that if A_O_A, the only CFA adjustments /* If the CFA is computed off the stack pointer, then we must adjust
involving the stack pointer are inside the prologue and marked as the computation of the CFA as well. */
RTX_FRAME_RELATED_P. That said, should we not verify this assumption if (cur_cfa->reg == dw_stack_pointer_regnum)
by *asserting* A_O_A at this point? Why else would we have a change {
to the stack pointer? */ gcc_assert (!cur_cfa->indirect);
if (ACCUMULATE_OUTGOING_ARGS)
return;
/* Convert a change in args_size (always a positive in the
direction of stack growth) to a change in stack pointer. */
#ifndef STACK_GROWS_DOWNWARD #ifndef STACK_GROWS_DOWNWARD
offset = -offset; delta = -delta;
#endif #endif
cur_cfa->offset += delta;
queued_args_size += offset; }
if (queued_args_size < 0)
queued_args_size = 0;
def_cfa_1 (&loc);
if (flag_asynchronous_unwind_tables)
dwarf2out_args_size (queued_args_size);
} }
/* Check INSN to see if it looks like a push or a stack adjustment, and /* A subroutine of scan_trace. INSN is can_throw_internal. Update the
make a note of it if it does. EH uses this information to find out data within the trace related to EH insns and args_size. */
how much extra space it needs to pop off the stack. */
static void static void
dwarf2out_notice_stack_adjust (rtx insn, bool after_p) notice_eh_throw (rtx insn)
{ {
HOST_WIDE_INT offset; HOST_WIDE_INT args_size;
int i;
/* Don't handle epilogues at all. Certainly it would be wrong to do so
with this function. Proper support would require all frame-related
insns to be marked, and to be able to handle saving state around
epilogues textually in the middle of the function. */
if (prologue_epilogue_contains (insn))
return;
/* If INSN is an instruction from target of an annulled branch, the
effects are for the target only and so current argument size
shouldn't change at all. */
if (final_sequence
&& INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))
&& INSN_FROM_TARGET_P (insn))
return;
/* If only calls can throw, and we have a frame pointer, args_size = cur_trace->end_true_args_size;
save up adjustments until we see the CALL_INSN. */ if (cur_trace->eh_head == NULL)
if (!flag_asynchronous_unwind_tables
&& cur_row->cfa.reg != dw_stack_pointer_regnum)
{ {
if (CALL_P (insn) && !after_p) cur_trace->eh_head = insn;
{ cur_trace->beg_delay_args_size = args_size;
/* Extract the size of the args from the CALL rtx itself. */ cur_trace->end_delay_args_size = args_size;
insn = PATTERN (insn);
if (GET_CODE (insn) == PARALLEL)
insn = XVECEXP (insn, 0, 0);
if (GET_CODE (insn) == SET)
insn = SET_SRC (insn);
gcc_assert (GET_CODE (insn) == CALL);
dwarf2out_args_size (INTVAL (XEXP (insn, 1)));
}
return;
} }
else if (cur_trace->end_delay_args_size != args_size)
if (CALL_P (insn) && !after_p)
{ {
if (!flag_asynchronous_unwind_tables) cur_trace->end_delay_args_size = args_size;
dwarf2out_args_size (queued_args_size);
return;
}
else if (BARRIER_P (insn))
return;
else if (GET_CODE (PATTERN (insn)) == SET)
offset = stack_adjust_offset (PATTERN (insn), queued_args_size, 0);
else if (GET_CODE (PATTERN (insn)) == PARALLEL
|| GET_CODE (PATTERN (insn)) == SEQUENCE)
{
/* There may be stack adjustments inside compound insns. Search
for them. */
for (offset = 0, i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i),
queued_args_size, offset);
}
else
return;
if (offset == 0)
return;
dwarf2out_stack_adjust (offset); /* ??? If the CFA is the stack pointer, search backward for the last
CFI note and insert there. Given that the stack changed for the
args_size change, there *must* be such a note in between here and
the last eh insn. */
add_cfi_args_size (args_size);
}
} }
/* Short-hand inline for the very common D_F_R (REGNO (x)) operation. */ /* Short-hand inline for the very common D_F_R (REGNO (x)) operation. */
...@@ -1201,31 +1057,27 @@ reg_saved_in (rtx reg) ...@@ -1201,31 +1057,27 @@ reg_saved_in (rtx reg)
static void static void
dwarf2out_frame_debug_def_cfa (rtx pat) dwarf2out_frame_debug_def_cfa (rtx pat)
{ {
dw_cfa_location loc; memset (cur_cfa, 0, sizeof (*cur_cfa));
memset (&loc, 0, sizeof (loc));
if (GET_CODE (pat) == PLUS) if (GET_CODE (pat) == PLUS)
{ {
loc.offset = INTVAL (XEXP (pat, 1)); cur_cfa->offset = INTVAL (XEXP (pat, 1));
pat = XEXP (pat, 0); pat = XEXP (pat, 0);
} }
if (MEM_P (pat)) if (MEM_P (pat))
{ {
loc.indirect = 1; cur_cfa->indirect = 1;
pat = XEXP (pat, 0); pat = XEXP (pat, 0);
if (GET_CODE (pat) == PLUS) if (GET_CODE (pat) == PLUS)
{ {
loc.base_offset = INTVAL (XEXP (pat, 1)); cur_cfa->base_offset = INTVAL (XEXP (pat, 1));
pat = XEXP (pat, 0); pat = XEXP (pat, 0);
} }
} }
/* ??? If this fails, we could be calling into the _loc functions to /* ??? If this fails, we could be calling into the _loc functions to
define a full expression. So far no port does that. */ define a full expression. So far no port does that. */
gcc_assert (REG_P (pat)); gcc_assert (REG_P (pat));
loc.reg = dwf_regno (pat); cur_cfa->reg = dwf_regno (pat);
def_cfa_1 (&loc);
} }
/* A subroutine of dwarf2out_frame_debug, process a REG_ADJUST_CFA note. */ /* A subroutine of dwarf2out_frame_debug, process a REG_ADJUST_CFA note. */
...@@ -1233,7 +1085,6 @@ dwarf2out_frame_debug_def_cfa (rtx pat) ...@@ -1233,7 +1085,6 @@ dwarf2out_frame_debug_def_cfa (rtx pat)
static void static void
dwarf2out_frame_debug_adjust_cfa (rtx pat) dwarf2out_frame_debug_adjust_cfa (rtx pat)
{ {
dw_cfa_location loc = cur_row->cfa;
rtx src, dest; rtx src, dest;
gcc_assert (GET_CODE (pat) == SET); gcc_assert (GET_CODE (pat) == SET);
...@@ -1243,21 +1094,19 @@ dwarf2out_frame_debug_adjust_cfa (rtx pat) ...@@ -1243,21 +1094,19 @@ dwarf2out_frame_debug_adjust_cfa (rtx pat)
switch (GET_CODE (src)) switch (GET_CODE (src))
{ {
case PLUS: case PLUS:
gcc_assert (dwf_regno (XEXP (src, 0)) == loc.reg); gcc_assert (dwf_regno (XEXP (src, 0)) == cur_cfa->reg);
loc.offset -= INTVAL (XEXP (src, 1)); cur_cfa->offset -= INTVAL (XEXP (src, 1));
break; break;
case REG: case REG:
break; break;
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
loc.reg = dwf_regno (dest); cur_cfa->reg = dwf_regno (dest);
gcc_assert (loc.indirect == 0); gcc_assert (cur_cfa->indirect == 0);
def_cfa_1 (&loc);
} }
/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_OFFSET note. */ /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_OFFSET note. */
...@@ -1278,12 +1127,12 @@ dwarf2out_frame_debug_cfa_offset (rtx set) ...@@ -1278,12 +1127,12 @@ dwarf2out_frame_debug_cfa_offset (rtx set)
switch (GET_CODE (addr)) switch (GET_CODE (addr))
{ {
case REG: case REG:
gcc_assert (dwf_regno (addr) == cur_row->cfa.reg); gcc_assert (dwf_regno (addr) == cur_cfa->reg);
offset = -cur_row->cfa.offset; offset = -cur_cfa->offset;
break; break;
case PLUS: case PLUS:
gcc_assert (dwf_regno (XEXP (addr, 0)) == cur_row->cfa.reg); gcc_assert (dwf_regno (XEXP (addr, 0)) == cur_cfa->reg);
offset = INTVAL (XEXP (addr, 1)) - cur_row->cfa.offset; offset = INTVAL (XEXP (addr, 1)) - cur_cfa->offset;
break; break;
default: default:
gcc_unreachable (); gcc_unreachable ();
...@@ -1451,7 +1300,7 @@ dwarf2out_frame_debug_cfa_window_save (void) ...@@ -1451,7 +1300,7 @@ dwarf2out_frame_debug_cfa_window_save (void)
cfa current rule for calculating the CFA. It usually cfa current rule for calculating the CFA. It usually
consists of a register and an offset. This is consists of a register and an offset. This is
actually stored in cur_row->cfa, but abbreviated actually stored in *cur_cfa, but abbreviated
for the purposes of this documentation. for the purposes of this documentation.
cfa_store register used by prologue code to save things to the stack cfa_store register used by prologue code to save things to the stack
cfa_store.offset is the offset from the value of cfa_store.offset is the offset from the value of
...@@ -1606,7 +1455,6 @@ dwarf2out_frame_debug_cfa_window_save (void) ...@@ -1606,7 +1455,6 @@ dwarf2out_frame_debug_cfa_window_save (void)
static void static void
dwarf2out_frame_debug_expr (rtx expr) dwarf2out_frame_debug_expr (rtx expr)
{ {
dw_cfa_location cfa = cur_row->cfa;
rtx src, dest, span; rtx src, dest, span;
HOST_WIDE_INT offset; HOST_WIDE_INT offset;
dw_fde_ref fde; dw_fde_ref fde;
...@@ -1644,18 +1492,6 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1644,18 +1492,6 @@ dwarf2out_frame_debug_expr (rtx expr)
&& (!MEM_P (SET_DEST (elem)) || GET_CODE (expr) == SEQUENCE) && (!MEM_P (SET_DEST (elem)) || GET_CODE (expr) == SEQUENCE)
&& (RTX_FRAME_RELATED_P (elem) || par_index == 0)) && (RTX_FRAME_RELATED_P (elem) || par_index == 0))
dwarf2out_frame_debug_expr (elem); dwarf2out_frame_debug_expr (elem);
else if (GET_CODE (elem) == SET
&& par_index != 0
&& !RTX_FRAME_RELATED_P (elem))
{
/* Stack adjustment combining might combine some post-prologue
stack adjustment into a prologue stack adjustment. */
HOST_WIDE_INT offset
= stack_adjust_offset (elem, queued_args_size, 0);
if (offset != 0)
dwarf2out_stack_adjust (offset);
}
} }
return; return;
} }
...@@ -1681,7 +1517,7 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1681,7 +1517,7 @@ dwarf2out_frame_debug_expr (rtx expr)
{ {
/* Setting FP from SP. */ /* Setting FP from SP. */
case REG: case REG:
if (cfa.reg == dwf_regno (src)) if (cur_cfa->reg == dwf_regno (src))
{ {
/* Rule 1 */ /* Rule 1 */
/* Update the CFA rule wrt SP or FP. Make sure src is /* Update the CFA rule wrt SP or FP. Make sure src is
...@@ -1691,9 +1527,9 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1691,9 +1527,9 @@ dwarf2out_frame_debug_expr (rtx expr)
ARM copies SP to a temporary register, and from there to ARM copies SP to a temporary register, and from there to
FP. So we just rely on the backends to only set FP. So we just rely on the backends to only set
RTX_FRAME_RELATED_P on appropriate insns. */ RTX_FRAME_RELATED_P on appropriate insns. */
cfa.reg = dwf_regno (dest); cur_cfa->reg = dwf_regno (dest);
cur_trace->cfa_temp.reg = cfa.reg; cur_trace->cfa_temp.reg = cur_cfa->reg;
cur_trace->cfa_temp.offset = cfa.offset; cur_trace->cfa_temp.offset = cur_cfa->offset;
} }
else else
{ {
...@@ -1711,7 +1547,7 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1711,7 +1547,7 @@ dwarf2out_frame_debug_expr (rtx expr)
&& REGNO (src) == STACK_POINTER_REGNUM) && REGNO (src) == STACK_POINTER_REGNUM)
gcc_assert (REGNO (dest) == HARD_FRAME_POINTER_REGNUM gcc_assert (REGNO (dest) == HARD_FRAME_POINTER_REGNUM
&& fde->drap_reg != INVALID_REGNUM && fde->drap_reg != INVALID_REGNUM
&& cfa.reg != dwf_regno (src)); && cur_cfa->reg != dwf_regno (src));
else else
queue_reg_save (src, dest, 0); queue_reg_save (src, dest, 0);
} }
...@@ -1741,8 +1577,8 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1741,8 +1577,8 @@ dwarf2out_frame_debug_expr (rtx expr)
if (XEXP (src, 0) == hard_frame_pointer_rtx) if (XEXP (src, 0) == hard_frame_pointer_rtx)
{ {
/* Restoring SP from FP in the epilogue. */ /* Restoring SP from FP in the epilogue. */
gcc_assert (cfa.reg == dw_frame_pointer_regnum); gcc_assert (cur_cfa->reg == dw_frame_pointer_regnum);
cfa.reg = dw_stack_pointer_regnum; cur_cfa->reg = dw_stack_pointer_regnum;
} }
else if (GET_CODE (src) == LO_SUM) else if (GET_CODE (src) == LO_SUM)
/* Assume we've set the source reg of the LO_SUM from sp. */ /* Assume we've set the source reg of the LO_SUM from sp. */
...@@ -1752,8 +1588,8 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1752,8 +1588,8 @@ dwarf2out_frame_debug_expr (rtx expr)
if (GET_CODE (src) != MINUS) if (GET_CODE (src) != MINUS)
offset = -offset; offset = -offset;
if (cfa.reg == dw_stack_pointer_regnum) if (cur_cfa->reg == dw_stack_pointer_regnum)
cfa.offset += offset; cur_cfa->offset += offset;
if (cur_trace->cfa_store.reg == dw_stack_pointer_regnum) if (cur_trace->cfa_store.reg == dw_stack_pointer_regnum)
cur_trace->cfa_store.offset += offset; cur_trace->cfa_store.offset += offset;
} }
...@@ -1765,13 +1601,13 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1765,13 +1601,13 @@ dwarf2out_frame_debug_expr (rtx expr)
gcc_assert (frame_pointer_needed); gcc_assert (frame_pointer_needed);
gcc_assert (REG_P (XEXP (src, 0)) gcc_assert (REG_P (XEXP (src, 0))
&& dwf_regno (XEXP (src, 0)) == cfa.reg && dwf_regno (XEXP (src, 0)) == cur_cfa->reg
&& CONST_INT_P (XEXP (src, 1))); && CONST_INT_P (XEXP (src, 1)));
offset = INTVAL (XEXP (src, 1)); offset = INTVAL (XEXP (src, 1));
if (GET_CODE (src) != MINUS) if (GET_CODE (src) != MINUS)
offset = -offset; offset = -offset;
cfa.offset += offset; cur_cfa->offset += offset;
cfa.reg = dw_frame_pointer_regnum; cur_cfa->reg = dw_frame_pointer_regnum;
} }
else else
{ {
...@@ -1779,17 +1615,17 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1779,17 +1615,17 @@ dwarf2out_frame_debug_expr (rtx expr)
/* Rule 4 */ /* Rule 4 */
if (REG_P (XEXP (src, 0)) if (REG_P (XEXP (src, 0))
&& dwf_regno (XEXP (src, 0)) == cfa.reg && dwf_regno (XEXP (src, 0)) == cur_cfa->reg
&& CONST_INT_P (XEXP (src, 1))) && CONST_INT_P (XEXP (src, 1)))
{ {
/* Setting a temporary CFA register that will be copied /* Setting a temporary CFA register that will be copied
into the FP later on. */ into the FP later on. */
offset = - INTVAL (XEXP (src, 1)); offset = - INTVAL (XEXP (src, 1));
cfa.offset += offset; cur_cfa->offset += offset;
cfa.reg = dwf_regno (dest); cur_cfa->reg = dwf_regno (dest);
/* Or used to save regs to the stack. */ /* Or used to save regs to the stack. */
cur_trace->cfa_temp.reg = cfa.reg; cur_trace->cfa_temp.reg = cur_cfa->reg;
cur_trace->cfa_temp.offset = cfa.offset; cur_trace->cfa_temp.offset = cur_cfa->offset;
} }
/* Rule 5 */ /* Rule 5 */
...@@ -1799,10 +1635,10 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1799,10 +1635,10 @@ dwarf2out_frame_debug_expr (rtx expr)
{ {
/* Setting a scratch register that we will use instead /* Setting a scratch register that we will use instead
of SP for saving registers to the stack. */ of SP for saving registers to the stack. */
gcc_assert (cfa.reg == dw_stack_pointer_regnum); gcc_assert (cur_cfa->reg == dw_stack_pointer_regnum);
cur_trace->cfa_store.reg = dwf_regno (dest); cur_trace->cfa_store.reg = dwf_regno (dest);
cur_trace->cfa_store.offset cur_trace->cfa_store.offset
= cfa.offset - cur_trace->cfa_temp.offset; = cur_cfa->offset - cur_trace->cfa_temp.offset;
} }
/* Rule 9 */ /* Rule 9 */
...@@ -1863,17 +1699,15 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1863,17 +1699,15 @@ dwarf2out_frame_debug_expr (rtx expr)
fde->stack_realignment = INTVAL (XEXP (src, 1)); fde->stack_realignment = INTVAL (XEXP (src, 1));
cur_trace->cfa_store.offset = 0; cur_trace->cfa_store.offset = 0;
if (cfa.reg != dw_stack_pointer_regnum if (cur_cfa->reg != dw_stack_pointer_regnum
&& cfa.reg != dw_frame_pointer_regnum) && cur_cfa->reg != dw_frame_pointer_regnum)
fde->drap_reg = cfa.reg; fde->drap_reg = cur_cfa->reg;
} }
return; return;
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
def_cfa_1 (&cfa);
break; break;
case MEM: case MEM:
...@@ -1895,8 +1729,8 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1895,8 +1729,8 @@ dwarf2out_frame_debug_expr (rtx expr)
&& cur_trace->cfa_store.reg == dw_stack_pointer_regnum); && cur_trace->cfa_store.reg == dw_stack_pointer_regnum);
cur_trace->cfa_store.offset += offset; cur_trace->cfa_store.offset += offset;
if (cfa.reg == dw_stack_pointer_regnum) if (cur_cfa->reg == dw_stack_pointer_regnum)
cfa.offset = cur_trace->cfa_store.offset; cur_cfa->offset = cur_trace->cfa_store.offset;
if (GET_CODE (XEXP (dest, 0)) == POST_MODIFY) if (GET_CODE (XEXP (dest, 0)) == POST_MODIFY)
offset -= cur_trace->cfa_store.offset; offset -= cur_trace->cfa_store.offset;
...@@ -1925,12 +1759,12 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1925,12 +1759,12 @@ dwarf2out_frame_debug_expr (rtx expr)
&& fde->stack_realign && fde->stack_realign
&& src == hard_frame_pointer_rtx) && src == hard_frame_pointer_rtx)
{ {
gcc_assert (cfa.reg != dw_frame_pointer_regnum); gcc_assert (cur_cfa->reg != dw_frame_pointer_regnum);
cur_trace->cfa_store.offset = 0; cur_trace->cfa_store.offset = 0;
} }
if (cfa.reg == dw_stack_pointer_regnum) if (cur_cfa->reg == dw_stack_pointer_regnum)
cfa.offset = cur_trace->cfa_store.offset; cur_cfa->offset = cur_trace->cfa_store.offset;
if (GET_CODE (XEXP (dest, 0)) == POST_DEC) if (GET_CODE (XEXP (dest, 0)) == POST_DEC)
offset += -cur_trace->cfa_store.offset; offset += -cur_trace->cfa_store.offset;
...@@ -1954,8 +1788,8 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1954,8 +1788,8 @@ dwarf2out_frame_debug_expr (rtx expr)
regno = dwf_regno (XEXP (XEXP (dest, 0), 0)); regno = dwf_regno (XEXP (XEXP (dest, 0), 0));
if (cfa.reg == regno) if (cur_cfa->reg == regno)
offset -= cfa.offset; offset -= cur_cfa->offset;
else if (cur_trace->cfa_store.reg == regno) else if (cur_trace->cfa_store.reg == regno)
offset -= cur_trace->cfa_store.offset; offset -= cur_trace->cfa_store.offset;
else else
...@@ -1972,8 +1806,8 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -1972,8 +1806,8 @@ dwarf2out_frame_debug_expr (rtx expr)
{ {
unsigned int regno = dwf_regno (XEXP (dest, 0)); unsigned int regno = dwf_regno (XEXP (dest, 0));
if (cfa.reg == regno) if (cur_cfa->reg == regno)
offset = -cfa.offset; offset = -cur_cfa->offset;
else if (cur_trace->cfa_store.reg == regno) else if (cur_trace->cfa_store.reg == regno)
offset = -cur_trace->cfa_store.offset; offset = -cur_trace->cfa_store.offset;
else else
...@@ -2005,11 +1839,11 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -2005,11 +1839,11 @@ dwarf2out_frame_debug_expr (rtx expr)
if (REG_P (src) if (REG_P (src)
&& REGNO (src) != STACK_POINTER_REGNUM && REGNO (src) != STACK_POINTER_REGNUM
&& REGNO (src) != HARD_FRAME_POINTER_REGNUM && REGNO (src) != HARD_FRAME_POINTER_REGNUM
&& dwf_regno (src) == cfa.reg) && dwf_regno (src) == cur_cfa->reg)
{ {
/* We're storing the current CFA reg into the stack. */ /* We're storing the current CFA reg into the stack. */
if (cfa.offset == 0) if (cur_cfa->offset == 0)
{ {
/* Rule 19 */ /* Rule 19 */
/* If stack is aligned, putting CFA reg into stack means /* If stack is aligned, putting CFA reg into stack means
...@@ -2019,28 +1853,23 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -2019,28 +1853,23 @@ dwarf2out_frame_debug_expr (rtx expr)
value. */ value. */
if (fde if (fde
&& fde->stack_realign && fde->stack_realign
&& cfa.indirect == 0 && cur_cfa->indirect == 0
&& cfa.reg != dw_frame_pointer_regnum) && cur_cfa->reg != dw_frame_pointer_regnum)
{ {
dw_cfa_location cfa_exp; gcc_assert (fde->drap_reg == cur_cfa->reg);
gcc_assert (fde->drap_reg == cfa.reg);
cfa_exp.indirect = 1; cur_cfa->indirect = 1;
cfa_exp.reg = dw_frame_pointer_regnum; cur_cfa->reg = dw_frame_pointer_regnum;
cfa_exp.base_offset = offset; cur_cfa->base_offset = offset;
cfa_exp.offset = 0; cur_cfa->offset = 0;
fde->drap_reg_saved = 1; fde->drap_reg_saved = 1;
def_cfa_1 (&cfa_exp);
break; break;
} }
/* If the source register is exactly the CFA, assume /* If the source register is exactly the CFA, assume
we're saving SP like any other register; this happens we're saving SP like any other register; this happens
on the ARM. */ on the ARM. */
def_cfa_1 (&cfa);
queue_reg_save (stack_pointer_rtx, NULL_RTX, offset); queue_reg_save (stack_pointer_rtx, NULL_RTX, offset);
break; break;
} }
...@@ -2054,16 +1883,13 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -2054,16 +1883,13 @@ dwarf2out_frame_debug_expr (rtx expr)
x = XEXP (x, 0); x = XEXP (x, 0);
gcc_assert (REG_P (x)); gcc_assert (REG_P (x));
cfa.reg = dwf_regno (x); cur_cfa->reg = dwf_regno (x);
cfa.base_offset = offset; cur_cfa->base_offset = offset;
cfa.indirect = 1; cur_cfa->indirect = 1;
def_cfa_1 (&cfa);
break; break;
} }
} }
def_cfa_1 (&cfa);
span = NULL; span = NULL;
if (REG_P (src)) if (REG_P (src))
span = targetm.dwarf_register_span (src); span = targetm.dwarf_register_span (src);
...@@ -2094,33 +1920,17 @@ dwarf2out_frame_debug_expr (rtx expr) ...@@ -2094,33 +1920,17 @@ dwarf2out_frame_debug_expr (rtx expr)
} }
} }
/* Record call frame debugging information for INSN, which either /* Record call frame debugging information for INSN, which either sets
sets SP or FP (adjusting how we calculate the frame address) or saves a SP or FP (adjusting how we calculate the frame address) or saves a
register to the stack. If INSN is NULL_RTX, initialize our state. register to the stack. */
If AFTER_P is false, we're being called before the insn is emitted,
otherwise after. Call instructions get invoked twice. */
static void static void
dwarf2out_frame_debug (rtx insn, bool after_p) dwarf2out_frame_debug (rtx insn)
{ {
rtx note, n; rtx note, n;
bool handled_one = false; bool handled_one = false;
bool need_flush = false; bool need_flush = false;
if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn))
dwarf2out_flush_queued_reg_saves ();
if (!RTX_FRAME_RELATED_P (insn))
{
/* ??? This should be done unconditionally since stack adjustments
matter if the stack pointer is not the CFA register anymore but
is still used to save registers. */
if (!ACCUMULATE_OUTGOING_ARGS)
dwarf2out_notice_stack_adjust (insn, after_p);
return;
}
any_cfis_emitted = false; any_cfis_emitted = false;
for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
...@@ -2258,9 +2068,6 @@ change_cfi_row (dw_cfi_row *old_row, dw_cfi_row *new_row) ...@@ -2258,9 +2068,6 @@ change_cfi_row (dw_cfi_row *old_row, dw_cfi_row *new_row)
add_cfi (cfi); add_cfi (cfi);
} }
if (old_row->args_size != new_row->args_size)
add_cfi_args_size (new_row->args_size);
n_old = VEC_length (dw_cfi_ref, old_row->reg_save); n_old = VEC_length (dw_cfi_ref, old_row->reg_save);
n_new = VEC_length (dw_cfi_ref, new_row->reg_save); n_new = VEC_length (dw_cfi_ref, new_row->reg_save);
n_max = MAX (n_old, n_new); n_max = MAX (n_old, n_new);
...@@ -2384,14 +2191,10 @@ add_cfis_to_fde (void) ...@@ -2384,14 +2191,10 @@ add_cfis_to_fde (void)
trace from CUR_TRACE and CUR_ROW. */ trace from CUR_TRACE and CUR_ROW. */
static void static void
maybe_record_trace_start (rtx start, rtx origin, bool abnormal) maybe_record_trace_start (rtx start, rtx origin)
{ {
dw_trace_info *ti; dw_trace_info *ti;
HOST_WIDE_INT args_size;
/* Sync queued data before propagating to a destination,
lest we propagate out-of-date data. */
dwarf2out_flush_queued_reg_saves ();
dwarf2out_args_size (queued_args_size);
ti = get_trace_info (start); ti = get_trace_info (start);
gcc_assert (ti != NULL); gcc_assert (ti != NULL);
...@@ -2404,15 +2207,13 @@ maybe_record_trace_start (rtx start, rtx origin, bool abnormal) ...@@ -2404,15 +2207,13 @@ maybe_record_trace_start (rtx start, rtx origin, bool abnormal)
(origin ? INSN_UID (origin) : 0)); (origin ? INSN_UID (origin) : 0));
} }
args_size = cur_trace->end_true_args_size;
if (ti->beg_row == NULL) if (ti->beg_row == NULL)
{ {
/* This is the first time we've encountered this trace. Propagate /* This is the first time we've encountered this trace. Propagate
state across the edge and push the trace onto the work list. */ state across the edge and push the trace onto the work list. */
ti->beg_row = copy_cfi_row (cur_row); ti->beg_row = copy_cfi_row (cur_row);
/* On all abnormal edges, especially EH and non-local-goto, we take ti->beg_true_args_size = args_size;
care to free the pushed arguments. */
if (abnormal)
ti->beg_row->args_size = 0;
ti->cfa_store = cur_trace->cfa_store; ti->cfa_store = cur_trace->cfa_store;
ti->cfa_temp = cur_trace->cfa_temp; ti->cfa_temp = cur_trace->cfa_temp;
...@@ -2426,11 +2227,52 @@ maybe_record_trace_start (rtx start, rtx origin, bool abnormal) ...@@ -2426,11 +2227,52 @@ maybe_record_trace_start (rtx start, rtx origin, bool abnormal)
} }
else else
{ {
/* We ought to have the same state incoming to a given trace no /* We ought to have the same state incoming to a given trace no
matter how we arrive at the trace. Anything else means we've matter how we arrive at the trace. Anything else means we've
got some kind of optimization error. */ got some kind of optimization error. */
gcc_checking_assert (cfi_row_equal_p (cur_row, ti->beg_row)); gcc_checking_assert (cfi_row_equal_p (cur_row, ti->beg_row));
/* The args_size is allowed to conflict if it isn't actually used. */
if (ti->beg_true_args_size != args_size)
ti->args_size_undefined = true;
}
}
/* Similarly, but handle the args_size and CFA reset across EH
and non-local goto edges. */
static void
maybe_record_trace_start_abnormal (rtx start, rtx origin)
{
HOST_WIDE_INT save_args_size, delta;
dw_cfa_location save_cfa;
save_args_size = cur_trace->end_true_args_size;
if (save_args_size == 0)
{
maybe_record_trace_start (start, origin);
return;
}
delta = -save_args_size;
cur_trace->end_true_args_size = 0;
save_cfa = cur_row->cfa;
if (cur_row->cfa.reg == dw_stack_pointer_regnum)
{
/* Convert a change in args_size (always a positive in the
direction of stack growth) to a change in stack pointer. */
#ifndef STACK_GROWS_DOWNWARD
delta = -delta;
#endif
cur_row->cfa.offset += delta;
} }
maybe_record_trace_start (start, origin);
cur_trace->end_true_args_size = save_args_size;
cur_row->cfa = save_cfa;
} }
/* Propagate CUR_TRACE state to the destinations implied by INSN. */ /* Propagate CUR_TRACE state to the destinations implied by INSN. */
...@@ -2445,8 +2287,9 @@ create_trace_edges (rtx insn) ...@@ -2445,8 +2287,9 @@ create_trace_edges (rtx insn)
if (JUMP_P (insn)) if (JUMP_P (insn))
{ {
if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX)) if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
; return;
else if (tablejump_p (insn, NULL, &tmp))
if (tablejump_p (insn, NULL, &tmp))
{ {
rtvec vec; rtvec vec;
...@@ -2457,13 +2300,13 @@ create_trace_edges (rtx insn) ...@@ -2457,13 +2300,13 @@ create_trace_edges (rtx insn)
for (i = 0; i < n; ++i) for (i = 0; i < n; ++i)
{ {
lab = XEXP (RTVEC_ELT (vec, i), 0); lab = XEXP (RTVEC_ELT (vec, i), 0);
maybe_record_trace_start (lab, insn, false); maybe_record_trace_start (lab, insn);
} }
} }
else if (computed_jump_p (insn)) else if (computed_jump_p (insn))
{ {
for (lab = forced_labels; lab; lab = XEXP (lab, 1)) for (lab = forced_labels; lab; lab = XEXP (lab, 1))
maybe_record_trace_start (XEXP (lab, 0), insn, true); maybe_record_trace_start (XEXP (lab, 0), insn);
} }
else if (returnjump_p (insn)) else if (returnjump_p (insn))
; ;
...@@ -2473,14 +2316,14 @@ create_trace_edges (rtx insn) ...@@ -2473,14 +2316,14 @@ create_trace_edges (rtx insn)
for (i = 0; i < n; ++i) for (i = 0; i < n; ++i)
{ {
lab = XEXP (ASM_OPERANDS_LABEL (tmp, i), 0); lab = XEXP (ASM_OPERANDS_LABEL (tmp, i), 0);
maybe_record_trace_start (lab, insn, true); maybe_record_trace_start (lab, insn);
} }
} }
else else
{ {
lab = JUMP_LABEL (insn); lab = JUMP_LABEL (insn);
gcc_assert (lab != NULL); gcc_assert (lab != NULL);
maybe_record_trace_start (lab, insn, false); maybe_record_trace_start (lab, insn);
} }
} }
else if (CALL_P (insn)) else if (CALL_P (insn))
...@@ -2492,7 +2335,7 @@ create_trace_edges (rtx insn) ...@@ -2492,7 +2335,7 @@ create_trace_edges (rtx insn)
/* Process non-local goto edges. */ /* Process non-local goto edges. */
if (can_nonlocal_goto (insn)) if (can_nonlocal_goto (insn))
for (lab = nonlocal_goto_handler_labels; lab; lab = XEXP (lab, 1)) for (lab = nonlocal_goto_handler_labels; lab; lab = XEXP (lab, 1))
maybe_record_trace_start (XEXP (lab, 0), insn, true); maybe_record_trace_start_abnormal (XEXP (lab, 0), insn);
} }
else if (GET_CODE (PATTERN (insn)) == SEQUENCE) else if (GET_CODE (PATTERN (insn)) == SEQUENCE)
{ {
...@@ -2508,7 +2351,7 @@ create_trace_edges (rtx insn) ...@@ -2508,7 +2351,7 @@ create_trace_edges (rtx insn)
{ {
eh_landing_pad lp = get_eh_landing_pad_from_rtx (insn); eh_landing_pad lp = get_eh_landing_pad_from_rtx (insn);
if (lp) if (lp)
maybe_record_trace_start (lp->landing_pad, insn, true); maybe_record_trace_start_abnormal (lp->landing_pad, insn);
} }
} }
...@@ -2519,6 +2362,7 @@ static void ...@@ -2519,6 +2362,7 @@ static void
scan_trace (dw_trace_info *trace) scan_trace (dw_trace_info *trace)
{ {
rtx insn = trace->head; rtx insn = trace->head;
dw_cfa_location this_cfa;
if (dump_file) if (dump_file)
fprintf (dump_file, "Processing trace %u : start at %s %d\n", fprintf (dump_file, "Processing trace %u : start at %s %d\n",
...@@ -2526,61 +2370,99 @@ scan_trace (dw_trace_info *trace) ...@@ -2526,61 +2370,99 @@ scan_trace (dw_trace_info *trace)
INSN_UID (insn)); INSN_UID (insn));
trace->end_row = copy_cfi_row (trace->beg_row); trace->end_row = copy_cfi_row (trace->beg_row);
trace->end_true_args_size = trace->beg_true_args_size;
cur_trace = trace; cur_trace = trace;
cur_row = trace->end_row; cur_row = trace->end_row;
queued_args_size = cur_row->args_size;
this_cfa = cur_row->cfa;
cur_cfa = &this_cfa;
for (insn = NEXT_INSN (insn); insn ; insn = NEXT_INSN (insn)) for (insn = NEXT_INSN (insn); insn ; insn = NEXT_INSN (insn))
{ {
rtx pat; /* Do everything that happens "before" the insn. */
add_cfi_insn = PREV_INSN (insn); add_cfi_insn = PREV_INSN (insn);
/* Notice the end of a trace. */ /* Notice the end of a trace. */
if (BARRIER_P (insn) || save_point_p (insn)) if (BARRIER_P (insn))
{
/* Don't bother saving the unneeded queued registers at all. */
VEC_truncate (queued_reg_save, queued_reg_saves, 0);
break;
}
if (save_point_p (insn))
{ {
dwarf2out_flush_queued_reg_saves ();
dwarf2out_args_size (queued_args_size);
/* Propagate across fallthru edges. */ /* Propagate across fallthru edges. */
if (!BARRIER_P (insn)) dwarf2out_flush_queued_reg_saves ();
maybe_record_trace_start (insn, NULL, false); maybe_record_trace_start (insn, NULL);
break; break;
} }
if (DEBUG_INSN_P (insn) || !inside_basic_block_p (insn)) if (DEBUG_INSN_P (insn) || !inside_basic_block_p (insn))
continue; continue;
pat = PATTERN (insn); /* Flush data before calls and jumps, and of course if necessary. */
if (asm_noperands (pat) >= 0) if (can_throw_internal (insn))
{ {
dwarf2out_frame_debug (insn, false); dwarf2out_flush_queued_reg_saves ();
add_cfi_insn = insn; notice_eh_throw (insn);
} }
else else if (!NONJUMP_INSN_P (insn)
|| clobbers_queued_reg_save (insn)
|| find_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL))
dwarf2out_flush_queued_reg_saves ();
/* Do everything that happens "after" the insn. */
add_cfi_insn = insn;
/* Handle changes to the row state. */
if (RTX_FRAME_RELATED_P (insn))
dwarf2out_frame_debug (insn);
/* Look for REG_ARGS_SIZE, and handle it. */
if (GET_CODE (PATTERN (insn)) == SEQUENCE)
{ {
if (GET_CODE (pat) == SEQUENCE) rtx elt, pat = PATTERN (insn);
int i, n = XVECLEN (pat, 0);
if (INSN_ANNULLED_BRANCH_P (XVECEXP (pat, 0, 0)))
{ {
int i, n = XVECLEN (pat, 0); /* ??? Hopefully multiple delay slots are not annulled. */
for (i = 1; i < n; ++i) gcc_assert (n == 2);
dwarf2out_frame_debug (XVECEXP (pat, 0, i), false); elt = XVECEXP (pat, 0, 1);
}
/* If ELT is an instruction from target of an annulled branch,
the effects are for the target only and so the args_size
and CFA along the current path shouldn't change. */
if (INSN_FROM_TARGET_P (elt))
{
HOST_WIDE_INT restore_args_size;
if (CALL_P (insn)) restore_args_size = cur_trace->end_true_args_size;
dwarf2out_frame_debug (insn, false); cur_cfa = &cur_row->cfa;
else if (find_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL)
|| (cfun->can_throw_non_call_exceptions
&& can_throw_internal (insn)))
dwarf2out_flush_queued_reg_saves ();
/* Do not separate tablejump insns from their ADDR_DIFF_VEC. notice_args_size (elt);
Putting the note after the VEC should be ok. */ create_trace_edges (insn);
if (!tablejump_p (insn, NULL, &add_cfi_insn))
add_cfi_insn = insn;
dwarf2out_frame_debug (insn, true); cur_trace->end_true_args_size = restore_args_size;
cur_row->cfa = this_cfa;
cur_cfa = &this_cfa;
continue;
}
}
for (i = 1; i < n; ++i)
{
elt = XVECEXP (pat, 0, i);
notice_args_size (elt);
}
} }
else
notice_args_size (insn);
/* Between frame-related-p and args_size we might have otherwise
emitted two cfa adjustments. Do it now. */
def_cfa_1 (&this_cfa);
/* Note that a test for control_flow_insn_p does exactly the /* Note that a test for control_flow_insn_p does exactly the
same tests as are done to actually create the edges. So same tests as are done to actually create the edges. So
...@@ -2592,6 +2474,7 @@ scan_trace (dw_trace_info *trace) ...@@ -2592,6 +2474,7 @@ scan_trace (dw_trace_info *trace)
add_cfi_insn = NULL; add_cfi_insn = NULL;
cur_row = NULL; cur_row = NULL;
cur_trace = NULL; cur_trace = NULL;
cur_cfa = NULL;
} }
/* Scan the function and create the initial set of CFI notes. */ /* Scan the function and create the initial set of CFI notes. */
...@@ -2733,6 +2616,32 @@ connect_traces (void) ...@@ -2733,6 +2616,32 @@ connect_traces (void)
while (note != add_cfi_insn); while (note != add_cfi_insn);
} }
} }
/* Connect args_size between traces that have can_throw_internal insns. */
if (cfun->eh->lp_array != NULL)
{
HOST_WIDE_INT prev_args_size = 0;
for (i = 0; i < n; ++i)
{
ti = VEC_index (dw_trace_info, trace_info, i);
if (ti->switch_sections)
prev_args_size = 0;
if (ti->eh_head == NULL)
continue;
gcc_assert (!ti->args_size_undefined);
if (ti->beg_delay_args_size != prev_args_size)
{
/* ??? Search back to previous CFI note. */
add_cfi_insn = PREV_INSN (ti->eh_head);
add_cfi_args_size (ti->beg_delay_args_size);
}
prev_args_size = ti->end_delay_args_size;
}
}
} }
/* Set up the pseudo-cfg of instruction traces, as described at the /* Set up the pseudo-cfg of instruction traces, as described at the
...@@ -3380,9 +3289,6 @@ dump_cfi_row (FILE *f, dw_cfi_row *row) ...@@ -3380,9 +3289,6 @@ dump_cfi_row (FILE *f, dw_cfi_row *row)
FOR_EACH_VEC_ELT (dw_cfi_ref, row->reg_save, i, cfi) FOR_EACH_VEC_ELT (dw_cfi_ref, row->reg_save, i, cfi)
if (cfi) if (cfi)
output_cfi_directive (f, cfi); output_cfi_directive (f, cfi);
fprintf (f, "\t.cfi_GNU_args_size "HOST_WIDE_INT_PRINT_DEC "\n",
row->args_size);
} }
void debug_cfi_row (dw_cfi_row *row); void debug_cfi_row (dw_cfi_row *row);
......
...@@ -3614,6 +3614,10 @@ try_split (rtx pat, rtx trial, int last) ...@@ -3614,6 +3614,10 @@ try_split (rtx pat, rtx trial, int last)
break; break;
#endif #endif
case REG_ARGS_SIZE:
fixup_args_size_notes (NULL_RTX, insn_last, INTVAL (XEXP (note, 0)));
break;
default: default:
break; break;
} }
......
...@@ -873,14 +873,45 @@ promote_decl_mode (const_tree decl, int *punsignedp) ...@@ -873,14 +873,45 @@ promote_decl_mode (const_tree decl, int *punsignedp)
} }
/* Controls the behaviour of {anti_,}adjust_stack. */
static bool suppress_reg_args_size;
/* A helper for adjust_stack and anti_adjust_stack. */
static void
adjust_stack_1 (rtx adjust, bool anti_p)
{
rtx temp, insn;
#ifndef STACK_GROWS_DOWNWARD
/* Hereafter anti_p means subtract_p. */
anti_p = !anti_p;
#endif
temp = expand_binop (Pmode,
anti_p ? sub_optab : add_optab,
stack_pointer_rtx, adjust, stack_pointer_rtx, 0,
OPTAB_LIB_WIDEN);
if (temp != stack_pointer_rtx)
insn = emit_move_insn (stack_pointer_rtx, temp);
else
{
insn = get_last_insn ();
temp = single_set (insn);
gcc_assert (temp != NULL && SET_DEST (temp) == stack_pointer_rtx);
}
if (!suppress_reg_args_size)
add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
}
/* Adjust the stack pointer by ADJUST (an rtx for a number of bytes). /* Adjust the stack pointer by ADJUST (an rtx for a number of bytes).
This pops when ADJUST is positive. ADJUST need not be constant. */ This pops when ADJUST is positive. ADJUST need not be constant. */
void void
adjust_stack (rtx adjust) adjust_stack (rtx adjust)
{ {
rtx temp;
if (adjust == const0_rtx) if (adjust == const0_rtx)
return; return;
...@@ -889,17 +920,7 @@ adjust_stack (rtx adjust) ...@@ -889,17 +920,7 @@ adjust_stack (rtx adjust)
if (CONST_INT_P (adjust)) if (CONST_INT_P (adjust))
stack_pointer_delta -= INTVAL (adjust); stack_pointer_delta -= INTVAL (adjust);
temp = expand_binop (Pmode, adjust_stack_1 (adjust, false);
#ifdef STACK_GROWS_DOWNWARD
add_optab,
#else
sub_optab,
#endif
stack_pointer_rtx, adjust, stack_pointer_rtx, 0,
OPTAB_LIB_WIDEN);
if (temp != stack_pointer_rtx)
emit_move_insn (stack_pointer_rtx, temp);
} }
/* Adjust the stack pointer by minus ADJUST (an rtx for a number of bytes). /* Adjust the stack pointer by minus ADJUST (an rtx for a number of bytes).
...@@ -908,8 +929,6 @@ adjust_stack (rtx adjust) ...@@ -908,8 +929,6 @@ adjust_stack (rtx adjust)
void void
anti_adjust_stack (rtx adjust) anti_adjust_stack (rtx adjust)
{ {
rtx temp;
if (adjust == const0_rtx) if (adjust == const0_rtx)
return; return;
...@@ -918,17 +937,7 @@ anti_adjust_stack (rtx adjust) ...@@ -918,17 +937,7 @@ anti_adjust_stack (rtx adjust)
if (CONST_INT_P (adjust)) if (CONST_INT_P (adjust))
stack_pointer_delta += INTVAL (adjust); stack_pointer_delta += INTVAL (adjust);
temp = expand_binop (Pmode, adjust_stack_1 (adjust, true);
#ifdef STACK_GROWS_DOWNWARD
sub_optab,
#else
add_optab,
#endif
stack_pointer_rtx, adjust, stack_pointer_rtx, 0,
OPTAB_LIB_WIDEN);
if (temp != stack_pointer_rtx)
emit_move_insn (stack_pointer_rtx, temp);
} }
/* Round the size of a block to be pushed up to the boundary required /* Round the size of a block to be pushed up to the boundary required
...@@ -1416,14 +1425,18 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align, ...@@ -1416,14 +1425,18 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
} }
saved_stack_pointer_delta = stack_pointer_delta; saved_stack_pointer_delta = stack_pointer_delta;
suppress_reg_args_size = true;
if (flag_stack_check && STACK_CHECK_MOVING_SP) if (flag_stack_check && STACK_CHECK_MOVING_SP)
anti_adjust_stack_and_probe (size, false); anti_adjust_stack_and_probe (size, false);
else else
anti_adjust_stack (size); anti_adjust_stack (size);
/* Even if size is constant, don't modify stack_pointer_delta. /* Even if size is constant, don't modify stack_pointer_delta.
The constant size alloca should preserve The constant size alloca should preserve
crtl->preferred_stack_boundary alignment. */ crtl->preferred_stack_boundary alignment. */
stack_pointer_delta = saved_stack_pointer_delta; stack_pointer_delta = saved_stack_pointer_delta;
suppress_reg_args_size = false;
#ifdef STACK_GROWS_DOWNWARD #ifdef STACK_GROWS_DOWNWARD
emit_move_insn (target, virtual_stack_dynamic_rtx); emit_move_insn (target, virtual_stack_dynamic_rtx);
......
...@@ -3514,12 +3514,168 @@ push_block (rtx size, int extra, int below) ...@@ -3514,12 +3514,168 @@ push_block (rtx size, int extra, int below)
return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp); return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp);
} }
#ifdef PUSH_ROUNDING /* A utility routine that returns the base of an auto-inc memory, or NULL. */
static rtx
mem_autoinc_base (rtx mem)
{
if (MEM_P (mem))
{
rtx addr = XEXP (mem, 0);
if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC)
return XEXP (addr, 0);
}
return NULL;
}
/* A utility routine used here, in reload, and in try_split. The insns
after PREV up to and including LAST are known to adjust the stack,
with a final value of END_ARGS_SIZE. Iterate backward from LAST
placing notes as appropriate. PREV may be NULL, indicating the
entire insn sequence prior to LAST should be scanned.
The set of allowed stack pointer modifications is small:
(1) One or more auto-inc style memory references (aka pushes),
(2) One or more addition/subtraction with the SP as destination,
(3) A single move insn with the SP as destination,
(4) A call_pop insn.
Insns in the sequence that do not modify the SP are ignored.
The return value is the amount of adjustment that can be trivially
verified, via immediate operand or auto-inc. If the adjustment
cannot be trivially extracted, the return value is INT_MIN. */
int
fixup_args_size_notes (rtx prev, rtx last, int end_args_size)
{
int args_size = end_args_size;
bool saw_unknown = false;
rtx insn;
for (insn = last; insn != prev; insn = PREV_INSN (insn))
{
rtx dest, set, pat;
HOST_WIDE_INT this_delta = 0;
int i;
if (!NONDEBUG_INSN_P (insn))
continue;
pat = PATTERN (insn);
set = NULL;
/* Look for a call_pop pattern. */
if (CALL_P (insn))
{
/* We're not supposed to see non-pop call patterns here. */
gcc_assert (GET_CODE (pat) == PARALLEL);
/* All call_pop have a stack pointer adjust in the parallel.
The call itself is always first, and the stack adjust is
usually last, so search from the end. */
for (i = XVECLEN (pat, 0) - 1; i > 0; --i)
{
set = XVECEXP (pat, 0, i);
if (GET_CODE (set) != SET)
continue;
dest = SET_DEST (set);
if (dest == stack_pointer_rtx)
break;
}
/* We'd better have found the stack pointer adjust. */
gcc_assert (i > 0);
/* Fall through to process the extracted SET and DEST
as if it was a standalone insn. */
}
else if (GET_CODE (pat) == SET)
set = pat;
else if ((set = single_set (insn)) != NULL)
;
else if (GET_CODE (pat) == PARALLEL)
{
/* ??? Some older ports use a parallel with a stack adjust
and a store for a PUSH_ROUNDING pattern, rather than a
PRE/POST_MODIFY rtx. Don't force them to update yet... */
/* ??? See h8300 and m68k, pushqi1. */
for (i = XVECLEN (pat, 0) - 1; i >= 0; --i)
{
set = XVECEXP (pat, 0, i);
if (GET_CODE (set) != SET)
continue;
dest = SET_DEST (set);
if (dest == stack_pointer_rtx)
break;
/* We do not expect an auto-inc of the sp in the parallel. */
gcc_checking_assert (mem_autoinc_base (dest)
!= stack_pointer_rtx);
gcc_checking_assert (mem_autoinc_base (SET_SRC (set))
!= stack_pointer_rtx);
}
if (i < 0)
continue;
}
else
continue;
dest = SET_DEST (set);
/* Look for direct modifications of the stack pointer. */
if (dest == stack_pointer_rtx)
{
gcc_assert (!saw_unknown);
/* Look for a trivial adjustment, otherwise assume nothing. */
if (GET_CODE (SET_SRC (set)) == PLUS
&& XEXP (SET_SRC (set), 0) == stack_pointer_rtx
&& CONST_INT_P (XEXP (SET_SRC (set), 1)))
this_delta = INTVAL (XEXP (SET_SRC (set), 1));
else
saw_unknown = true;
}
/* Otherwise only think about autoinc patterns. */
else if (mem_autoinc_base (dest) == stack_pointer_rtx)
{
rtx addr = XEXP (dest, 0);
gcc_assert (!saw_unknown);
switch (GET_CODE (addr))
{
case PRE_INC:
case POST_INC:
this_delta = GET_MODE_SIZE (GET_MODE (dest));
break;
case PRE_DEC:
case POST_DEC:
this_delta = -GET_MODE_SIZE (GET_MODE (dest));
break;
case PRE_MODIFY:
case POST_MODIFY:
addr = XEXP (addr, 1);
gcc_assert (GET_CODE (addr) == PLUS);
gcc_assert (XEXP (addr, 0) == stack_pointer_rtx);
gcc_assert (CONST_INT_P (XEXP (addr, 1)));
this_delta = INTVAL (XEXP (addr, 1));
break;
default:
gcc_unreachable ();
}
}
else
continue;
add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (args_size));
#ifdef STACK_GROWS_DOWNWARD
this_delta = -this_delta;
#endif
args_size -= this_delta;
}
return saw_unknown ? INT_MIN : args_size;
}
#ifdef PUSH_ROUNDING
/* Emit single push insn. */ /* Emit single push insn. */
static void static void
emit_single_push_insn (enum machine_mode mode, rtx x, tree type) emit_single_push_insn_1 (enum machine_mode mode, rtx x, tree type)
{ {
rtx dest_addr; rtx dest_addr;
unsigned rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode)); unsigned rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
...@@ -3603,6 +3759,30 @@ emit_single_push_insn (enum machine_mode mode, rtx x, tree type) ...@@ -3603,6 +3759,30 @@ emit_single_push_insn (enum machine_mode mode, rtx x, tree type)
} }
emit_move_insn (dest, x); emit_move_insn (dest, x);
} }
/* Emit and annotate a single push insn. */
static void
emit_single_push_insn (enum machine_mode mode, rtx x, tree type)
{
int delta, old_delta = stack_pointer_delta;
rtx prev = get_last_insn ();
rtx last;
emit_single_push_insn_1 (mode, x, type);
last = get_last_insn ();
/* Notice the common case where we emitted exactly one insn. */
if (PREV_INSN (last) == prev)
{
add_reg_note (last, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
return;
}
delta = fixup_args_size_notes (prev, last, stack_pointer_delta);
gcc_assert (delta == INT_MIN || delta == old_delta);
}
#endif #endif
/* Generate code to push X onto the stack, assuming it has mode MODE and /* Generate code to push X onto the stack, assuming it has mode MODE and
......
...@@ -3146,16 +3146,17 @@ static rtx ...@@ -3146,16 +3146,17 @@ static rtx
peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt) peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
{ {
int i; int i;
rtx last, note, before_try, x; rtx last, eh_note, as_note, before_try, x;
rtx old_insn, new_insn; rtx old_insn, new_insn;
bool was_call = false; bool was_call = false;
/* If we are splittind an RTX_FRAME_RELATED_P insn, do not allow it to /* If we are splitting an RTX_FRAME_RELATED_P insn, do not allow it to
match more than one insn, or to be split into more than one insn. */ match more than one insn, or to be split into more than one insn. */
old_insn = peep2_insn_data[peep2_current].insn; old_insn = peep2_insn_data[peep2_current].insn;
if (RTX_FRAME_RELATED_P (old_insn)) if (RTX_FRAME_RELATED_P (old_insn))
{ {
bool any_note = false; bool any_note = false;
rtx note;
if (match_len != 0) if (match_len != 0)
return NULL; return NULL;
...@@ -3236,6 +3237,7 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt) ...@@ -3236,6 +3237,7 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
for (i = 0; i <= match_len; ++i) for (i = 0; i <= match_len; ++i)
{ {
int j; int j;
rtx note;
j = peep2_buf_position (peep2_current + i); j = peep2_buf_position (peep2_current + i);
old_insn = peep2_insn_data[j].insn; old_insn = peep2_insn_data[j].insn;
...@@ -3281,9 +3283,21 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt) ...@@ -3281,9 +3283,21 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
break; break;
} }
i = peep2_buf_position (peep2_current + match_len); /* If we matched any instruction that had a REG_ARGS_SIZE, then
move those notes over to the new sequence. */
as_note = NULL;
for (i = match_len; i >= 0; --i)
{
int j = peep2_buf_position (peep2_current + i);
old_insn = peep2_insn_data[j].insn;
as_note = find_reg_note (old_insn, REG_ARGS_SIZE, NULL);
if (as_note)
break;
}
note = find_reg_note (peep2_insn_data[i].insn, REG_EH_REGION, NULL_RTX); i = peep2_buf_position (peep2_current + match_len);
eh_note = find_reg_note (peep2_insn_data[i].insn, REG_EH_REGION, NULL_RTX);
/* Replace the old sequence with the new. */ /* Replace the old sequence with the new. */
last = emit_insn_after_setloc (attempt, last = emit_insn_after_setloc (attempt,
...@@ -3293,7 +3307,7 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt) ...@@ -3293,7 +3307,7 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
delete_insn_chain (insn, peep2_insn_data[i].insn, false); delete_insn_chain (insn, peep2_insn_data[i].insn, false);
/* Re-insert the EH_REGION notes. */ /* Re-insert the EH_REGION notes. */
if (note || (was_call && nonlocal_goto_handler_labels)) if (eh_note || (was_call && nonlocal_goto_handler_labels))
{ {
edge eh_edge; edge eh_edge;
edge_iterator ei; edge_iterator ei;
...@@ -3302,8 +3316,8 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt) ...@@ -3302,8 +3316,8 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
break; break;
if (note) if (eh_note)
copy_reg_eh_region_note_backward (note, last, before_try); copy_reg_eh_region_note_backward (eh_note, last, before_try);
if (eh_edge) if (eh_edge)
for (x = last; x != before_try; x = PREV_INSN (x)) for (x = last; x != before_try; x = PREV_INSN (x))
...@@ -3336,6 +3350,10 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt) ...@@ -3336,6 +3350,10 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
peep2_do_cleanup_cfg |= purge_dead_edges (bb); peep2_do_cleanup_cfg |= purge_dead_edges (bb);
} }
/* Re-insert the ARGS_SIZE notes. */
if (as_note)
fixup_args_size_notes (before_try, last, INTVAL (XEXP (as_note, 0)));
/* If we generated a jump instruction, it won't have /* If we generated a jump instruction, it won't have
JUMP_LABEL set. Recompute after we're done. */ JUMP_LABEL set. Recompute after we're done. */
for (x = last; x != before_try; x = PREV_INSN (x)) for (x = last; x != before_try; x = PREV_INSN (x))
......
...@@ -201,3 +201,8 @@ REG_NOTE (CROSSING_JUMP) ...@@ -201,3 +201,8 @@ REG_NOTE (CROSSING_JUMP)
/* This kind of note is generated at each to `setjmp', and similar /* This kind of note is generated at each to `setjmp', and similar
functions that can return twice. */ functions that can return twice. */
REG_NOTE (SETJMP) REG_NOTE (SETJMP)
/* Indicates the cumulative offset of the stack pointer accounting
for pushed arguments. This will only be generated when
ACCUMULATE_OUTGOING_ARGS is false. */
REG_NOTE (ARGS_SIZE)
...@@ -4548,7 +4548,7 @@ reload_as_needed (int live_known) ...@@ -4548,7 +4548,7 @@ reload_as_needed (int live_known)
#if defined (AUTO_INC_DEC) #if defined (AUTO_INC_DEC)
int i; int i;
#endif #endif
rtx x; rtx x, marker;
memset (spill_reg_rtx, 0, sizeof spill_reg_rtx); memset (spill_reg_rtx, 0, sizeof spill_reg_rtx);
memset (spill_reg_store, 0, sizeof spill_reg_store); memset (spill_reg_store, 0, sizeof spill_reg_store);
...@@ -4559,6 +4559,10 @@ reload_as_needed (int live_known) ...@@ -4559,6 +4559,10 @@ reload_as_needed (int live_known)
set_initial_elim_offsets (); set_initial_elim_offsets ();
/* Generate a marker insn that we will move around. */
marker = emit_note (NOTE_INSN_DELETED);
unlink_insn_chain (marker, marker);
for (chain = reload_insn_chain; chain; chain = chain->next) for (chain = reload_insn_chain; chain; chain = chain->next)
{ {
rtx prev = 0; rtx prev = 0;
...@@ -4631,7 +4635,10 @@ reload_as_needed (int live_known) ...@@ -4631,7 +4635,10 @@ reload_as_needed (int live_known)
rtx next = NEXT_INSN (insn); rtx next = NEXT_INSN (insn);
rtx p; rtx p;
/* ??? PREV can get deleted by reload inheritance.
Work around this by emitting a marker note. */
prev = PREV_INSN (insn); prev = PREV_INSN (insn);
reorder_insns_nobb (marker, marker, prev);
/* Now compute which reload regs to reload them into. Perhaps /* Now compute which reload regs to reload them into. Perhaps
reusing reload regs from previous insns, or else output reusing reload regs from previous insns, or else output
...@@ -4649,10 +4656,22 @@ reload_as_needed (int live_known) ...@@ -4649,10 +4656,22 @@ reload_as_needed (int live_known)
and that we moved the structure into). */ and that we moved the structure into). */
subst_reloads (insn); subst_reloads (insn);
prev = PREV_INSN (marker);
unlink_insn_chain (marker, marker);
/* Adjust the exception region notes for loads and stores. */ /* Adjust the exception region notes for loads and stores. */
if (cfun->can_throw_non_call_exceptions && !CALL_P (insn)) if (cfun->can_throw_non_call_exceptions && !CALL_P (insn))
fixup_eh_region_note (insn, prev, next); fixup_eh_region_note (insn, prev, next);
/* Adjust the location of REG_ARGS_SIZE. */
p = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
if (p)
{
remove_note (insn, p);
fixup_args_size_notes (prev, PREV_INSN (next),
INTVAL (XEXP (p, 0)));
}
/* If this was an ASM, make sure that all the reload insns /* If this was an ASM, make sure that all the reload insns
we have generated are valid. If not, give an error we have generated are valid. If not, give an error
and delete them. */ and delete them. */
......
...@@ -2471,6 +2471,7 @@ extern void emit_jump (rtx); ...@@ -2471,6 +2471,7 @@ extern void emit_jump (rtx);
/* In expr.c */ /* In expr.c */
extern rtx move_by_pieces (rtx, rtx, unsigned HOST_WIDE_INT, extern rtx move_by_pieces (rtx, rtx, unsigned HOST_WIDE_INT,
unsigned int, int); unsigned int, int);
extern int fixup_args_size_notes (rtx, rtx, int);
/* In cfgrtl.c */ /* In cfgrtl.c */
extern void print_rtl_with_bb (FILE *, const_rtx); extern void print_rtl_with_bb (FILE *, const_rtx);
......
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