diff options
author | Richard Henderson <rth@redhat.com> | 2011-08-02 15:18:35 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2011-08-02 15:18:35 -0700 |
commit | 9a08d23082fbeb95013dc74dd3611b6b2331e3cb (patch) | |
tree | 3dd838d8e7cbbe356e3db0a0c2bcb80fcfbb4daf /gcc/expr.c | |
parent | cde7b553dbabe7d7341998f54979af2190539cd7 (diff) | |
download | gcc-9a08d23082fbeb95013dc74dd3611b6b2331e3cb.zip gcc-9a08d23082fbeb95013dc74dd3611b6b2331e3cb.tar.gz gcc-9a08d23082fbeb95013dc74dd3611b6b2331e3cb.tar.bz2 |
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
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 184 |
1 files changed, 182 insertions, 2 deletions
@@ -3514,12 +3514,168 @@ push_block (rtx size, int extra, int below) 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. */ 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; 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) } 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 /* Generate code to push X onto the stack, assuming it has mode MODE and |