http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59575
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #31943|0 |1 is obsolete| | --- Comment #26 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Comment on attachment 31943 --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=31943 gcc49-pr59575.patch >2014-01-23 Jakub Jelinek <ja...@redhat.com> > > PR target/59575 > * config/arm/arm.c (emit_multi_reg_push): Add dwarf_regs_mask argument, > don't record in REG_FRAME_RELATED_EXPR registers not set in that > bitmask. > (arm_expand_prologue): Adjust all callers. > (arm_unwind_emit_sequence): Allow saved, but not important for unwind > info, registers also at the lowest numbered registers side. Use > gcc_assert instead of abort, and SET_SRC/SET_DEST macros instead of > XEXP. > > * gcc.target/arm/pr59575.c: New test. > >--- gcc/config/arm/arm.c.jj 2014-01-17 15:16:14.000000000 +0100 >+++ gcc/config/arm/arm.c 2014-01-24 09:16:41.949843665 +0100 >@@ -177,7 +177,7 @@ static rtx arm_expand_builtin (tree, rtx > static tree arm_builtin_decl (unsigned, bool); > static void emit_constant_insn (rtx cond, rtx pattern); > static rtx emit_set_insn (rtx, rtx); >-static rtx emit_multi_reg_push (unsigned long); >+static rtx emit_multi_reg_push (unsigned long, unsigned long); > static int arm_arg_partial_bytes (cumulative_args_t, enum machine_mode, > tree, bool); > static rtx arm_function_arg (cumulative_args_t, enum machine_mode, >@@ -19574,9 +19574,11 @@ arm_emit_strd_push (unsigned long saved_ > /* Generate and emit an insn that we will recognize as a push_multi. > Unfortunately, since this insn does not reflect very well the actual > semantics of the operation, we need to annotate the insn for the benefit >- of DWARF2 frame unwind information. */ >+ of DWARF2 frame unwind information. DWARF_REGS_MASK is a subset of >+ MASK for registers that should be annotated for DWARF2 frame unwind >+ information. */ > static rtx >-emit_multi_reg_push (unsigned long mask) >+emit_multi_reg_push (unsigned long mask, unsigned long dwarf_regs_mask) > { > int num_regs = 0; > int num_dwarf_regs; >@@ -19586,16 +19588,19 @@ emit_multi_reg_push (unsigned long mask) > int dwarf_par_index; > rtx tmp, reg; > >+ /* We don't record the PC in the dwarf frame information. */ >+ dwarf_regs_mask &= ~(1 << PC_REGNUM); >+ > for (i = 0; i <= LAST_ARM_REGNUM; i++) >- if (mask & (1 << i)) >- num_regs++; >+ { >+ if (mask & (1 << i)) >+ num_regs++; >+ if (dwarf_regs_mask & (1 << i)) >+ num_dwarf_regs++; >+ } > > gcc_assert (num_regs && num_regs <= 16); >- >- /* We don't record the PC in the dwarf frame information. */ >- num_dwarf_regs = num_regs; >- if (mask & (1 << PC_REGNUM)) >- num_dwarf_regs--; >+ gcc_assert ((dwarf_regs_mask & ~mask) == 0); > > /* For the body of the insn we are going to generate an UNSPEC in > parallel with several USEs. This allows the insn to be recognized >@@ -19661,14 +19666,13 @@ emit_multi_reg_push (unsigned long mask) > gen_rtvec (1, reg), > UNSPEC_PUSH_MULT)); > >- if (i != PC_REGNUM) >+ if (dwarf_regs_mask & (1 << i)) > { > tmp = gen_rtx_SET (VOIDmode, > gen_frame_mem (SImode, stack_pointer_rtx), > reg); > RTX_FRAME_RELATED_P (tmp) = 1; >- XVECEXP (dwarf, 0, dwarf_par_index) = tmp; >- dwarf_par_index++; >+ XVECEXP (dwarf, 0, dwarf_par_index++) = tmp; > } > > break; >@@ -19683,7 +19687,7 @@ emit_multi_reg_push (unsigned long mask) > > XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg); > >- if (i != PC_REGNUM) >+ if (dwarf_regs_mask & (1 << i)) > { > tmp > = gen_rtx_SET (VOIDmode, >@@ -20690,7 +20694,7 @@ arm_expand_prologue (void) > /* Interrupt functions must not corrupt any registers. > Creating a frame pointer however, corrupts the IP > register, so we must push it first. */ >- emit_multi_reg_push (1 << IP_REGNUM); >+ emit_multi_reg_push (1 << IP_REGNUM, 1 << IP_REGNUM); > > /* Do not set RTX_FRAME_RELATED_P on this insn. > The dwarf stack unwinding code only wants to see one >@@ -20751,7 +20755,8 @@ arm_expand_prologue (void) > if (cfun->machine->uses_anonymous_args) > { > insn >- = emit_multi_reg_push ((0xf0 >> (args_to_push / 4)) & 0xf); >+ = emit_multi_reg_push ((0xf0 >> (args_to_push / 4)) & 0xf, >+ (0xf0 >> (args_to_push / 4)) & 0xf); > emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx); > saved_pretend_args = 1; > } >@@ -20795,7 +20800,8 @@ arm_expand_prologue (void) > /* Push the argument registers, or reserve space for them. */ > if (cfun->machine->uses_anonymous_args) > insn = emit_multi_reg_push >- ((0xf0 >> (args_to_push / 4)) & 0xf); >+ ((0xf0 >> (args_to_push / 4)) & 0xf, >+ (0xf0 >> (args_to_push / 4)) & 0xf); > else > insn = emit_insn > (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, >@@ -20820,6 +20826,8 @@ arm_expand_prologue (void) > > if (live_regs_mask) > { >+ unsigned long dwarf_regs_mask = live_regs_mask; >+ > saved_regs += bit_count (live_regs_mask) * 4; > if (optimize_size && !frame_pointer_needed > && saved_regs == offsets->saved_regs - offsets->saved_args) >@@ -20846,25 +20854,22 @@ arm_expand_prologue (void) > && current_tune->prefer_ldrd_strd > && !optimize_function_for_size_p (cfun)) > { >+ gcc_checking_assert (live_regs_mask == dwarf_regs_mask); > if (TARGET_THUMB2) >- { >- thumb2_emit_strd_push (live_regs_mask); >- } >+ thumb2_emit_strd_push (live_regs_mask); > else if (TARGET_ARM > && !TARGET_APCS_FRAME > && !IS_INTERRUPT (func_type)) >- { >- arm_emit_strd_push (live_regs_mask); >- } >+ arm_emit_strd_push (live_regs_mask); > else > { >- insn = emit_multi_reg_push (live_regs_mask); >+ insn = emit_multi_reg_push (live_regs_mask, live_regs_mask); > RTX_FRAME_RELATED_P (insn) = 1; > } > } > else > { >- insn = emit_multi_reg_push (live_regs_mask); >+ insn = emit_multi_reg_push (live_regs_mask, dwarf_regs_mask); > RTX_FRAME_RELATED_P (insn) = 1; > } > } >@@ -28692,32 +28697,43 @@ arm_unwind_emit_sequence (FILE * asm_out > int reg_size; > unsigned reg; > unsigned lastreg; >+ unsigned padfirst = 0, padlast = 0; > rtx e; > > e = XVECEXP (p, 0, 0); >- if (GET_CODE (e) != SET) >- abort (); >+ gcc_assert (GET_CODE (e) == SET); > > /* First insn will adjust the stack pointer. */ >- if (GET_CODE (e) != SET >- || !REG_P (XEXP (e, 0)) >- || REGNO (XEXP (e, 0)) != SP_REGNUM >- || GET_CODE (XEXP (e, 1)) != PLUS) >- abort (); >+ gcc_assert (GET_CODE (e) == SET >+ && REG_P (SET_DEST (e)) >+ && REGNO (SET_DEST (e)) == SP_REGNUM >+ && GET_CODE (SET_SRC (e)) == PLUS); > >- offset = -INTVAL (XEXP (XEXP (e, 1), 1)); >+ offset = -INTVAL (XEXP (SET_SRC (e), 1)); > nregs = XVECLEN (p, 0) - 1; >+ gcc_assert (nregs); > >- reg = REGNO (XEXP (XVECEXP (p, 0, 1), 1)); >+ reg = REGNO (SET_SRC (XVECEXP (p, 0, 1))); > if (reg < 16) > { >+ /* For -Os dummy registers can be pushed at the beginning to >+ avoid separate stack pointer adjustment. */ >+ e = XVECEXP (p, 0, 1); >+ e = XEXP (SET_DEST (e), 0); >+ if (GET_CODE (e) == PLUS) >+ padfirst = INTVAL (XEXP (e, 1)); >+ gcc_assert (padfirst == 0 || optimize_size); > /* The function prologue may also push pc, but not annotate it as it is > never restored. We turn this into a stack pointer adjustment. */ >- if (nregs * 4 == offset - 4) >- { >- fprintf (asm_out_file, "\t.pad #4\n"); >- offset -= 4; >- } >+ e = XVECEXP (p, 0, nregs); >+ e = XEXP (SET_DEST (e), 0); >+ if (GET_CODE (e) == PLUS) >+ padlast = offset - INTVAL (XEXP (e, 1)) - 4; >+ else >+ padlast = offset - 4; >+ gcc_assert (padlast == 0 || padlast == 4); >+ if (padlast == 4) >+ fprintf (asm_out_file, "\t.pad #4\n"); > reg_size = 4; > fprintf (asm_out_file, "\t.save {"); > } >@@ -28728,14 +28744,13 @@ arm_unwind_emit_sequence (FILE * asm_out > } > else > /* Unknown register type. */ >- abort (); >+ gcc_unreachable (); > > /* If the stack increment doesn't match the size of the saved registers, > something has gone horribly wrong. */ >- if (offset != nregs * reg_size) >- abort (); >+ gcc_assert (offset == padfirst + nregs * reg_size + padlast); > >- offset = 0; >+ offset = padfirst; > lastreg = 0; > /* The remaining insns will describe the stores. */ > for (i = 1; i <= nregs; i++) >@@ -28743,14 +28758,12 @@ arm_unwind_emit_sequence (FILE * asm_out > /* Expect (set (mem <addr>) (reg)). > Where <addr> is (reg:SP) or (plus (reg:SP) (const_int)). */ > e = XVECEXP (p, 0, i); >- if (GET_CODE (e) != SET >- || !MEM_P (XEXP (e, 0)) >- || !REG_P (XEXP (e, 1))) >- abort (); >- >- reg = REGNO (XEXP (e, 1)); >- if (reg < lastreg) >- abort (); >+ gcc_assert (GET_CODE (e) == SET >+ && MEM_P (SET_DEST (e)) >+ && REG_P (SET_SRC (e))); >+ >+ reg = REGNO (SET_SRC (e)); >+ gcc_assert (reg >= lastreg); > > if (i != 1) > fprintf (asm_out_file, ", "); >@@ -28763,23 +28776,22 @@ arm_unwind_emit_sequence (FILE * asm_out > > #ifdef ENABLE_CHECKING > /* Check that the addresses are consecutive. */ >- e = XEXP (XEXP (e, 0), 0); >+ e = XEXP (SET_DEST (e), 0); > if (GET_CODE (e) == PLUS) >- { >- offset += reg_size; >- if (!REG_P (XEXP (e, 0)) >- || REGNO (XEXP (e, 0)) != SP_REGNUM >- || !CONST_INT_P (XEXP (e, 1)) >- || offset != INTVAL (XEXP (e, 1))) >- abort (); >- } >- else if (i != 1 >- || !REG_P (e) >- || REGNO (e) != SP_REGNUM) >- abort (); >+ gcc_assert (REG_P (XEXP (e, 0)) >+ && REGNO (XEXP (e, 0)) == SP_REGNUM >+ && CONST_INT_P (XEXP (e, 1)) >+ && offset == INTVAL (XEXP (e, 1))); >+ else >+ gcc_assert (i == 1 >+ && REG_P (e) >+ && REGNO (e) == SP_REGNUM); >+ offset += reg_size; > #endif > } > fprintf (asm_out_file, "}\n"); >+ if (padfirst) >+ fprintf (asm_out_file, "\t.pad #%d\n", padfirst); > } > > /* Emit unwind directives for a SET. */ >--- gcc/testsuite/gcc.target/arm/pr59575.c.jj 2014-01-23 15:54:25.959922593 >+0100 >+++ gcc/testsuite/gcc.target/arm/pr59575.c 2014-01-23 15:54:12.000000000 >+0100 >@@ -0,0 +1,15 @@ >+/* PR target/59575 */ >+/* { dg-do compile } */ >+/* { dg-options "-Os -g -march=armv7-a" } */ >+ >+void foo (int *); >+int *bar (int, long long, int); >+ >+void >+test (int *p) >+{ >+ if (p) >+ foo (p); >+ else if (p = bar (0, 1, 2)) >+ foo (p); >+}