Bug 43290 - ICE in dwarf2out_frame_debug_expr
Summary: ICE in dwarf2out_frame_debug_expr
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: debug (show other bugs)
Version: 4.4.4
: P3 normal
Target Milestone: 4.5.0
Assignee: Jakub Jelinek
URL:
Keywords: ice-on-valid-code
Depends on:
Blocks:
 
Reported: 2010-03-08 14:45 UTC by Jakub Jelinek
Modified: 2011-10-07 01:37 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2010-03-08 17:00:56


Attachments
gcc44-pr43290-1.patch (564 bytes, patch)
2010-03-08 16:39 UTC, Jakub Jelinek
Details | Diff
gcc44-pr43290-2.patch (435 bytes, patch)
2010-03-08 16:45 UTC, Jakub Jelinek
Details | Diff
gcc45-pr43290.patch (1.32 KB, patch)
2010-03-10 00:33 UTC, Jakub Jelinek
Details | Diff
gcc45-pr43290.patch (2.24 KB, patch)
2010-03-10 08:07 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jakub Jelinek 2010-03-08 14:45:16 UTC
I have only reproducer for this on redhat/gcc-4_4-branch, though I believe the problem is just latent on vanilla 4.4 branch and likely on the trunk too, therefore I want to discuss this here.

namespace std
{
  template <class> struct char_traits;
}
typedef struct { union { char __wchb[4]; }; } mbstate_t;
namespace std
{
  template <typename _StateT> struct fpos
  {
    long long _M_off;
    _StateT _M_state;
    fpos (long long):_M_off (), _M_state () { }
    _StateT state () { return _M_state; }
  };
  typedef fpos <mbstate_t> streampos;
}
namespace std
{
  template <> struct char_traits <char>
  {
    typedef streampos pos_type;
    typedef long long off_type;
    typedef mbstate_t state_type;
  };
}
struct pthread_mutex_t;
namespace
{
  enum _Ios_Openmode { _S_in = 3, _S_out };
  enum _Ios_Seekdir { _S_beg };
  struct ios_base
  {
    typedef _Ios_Openmode openmode;
    static const openmode in = _S_in;
    static const openmode out = _S_out;
    typedef _Ios_Seekdir seekdir;
    static const seekdir beg = _S_beg;
  };
  template < typename _CharT, typename > struct basic_streambuf
  {
    typedef _CharT char_type;
    char_type * _M_in_beg;
    char_type *eback () { return _M_in_beg; }
    char_type *gptr () {}
  };
}
namespace std
{
  typedef struct pthread_mutex_t __c_lock;
  template <typename> class __basic_file;
  template <> struct __basic_file <char>
  {
    __basic_file (__c_lock * = 0);
    bool is_open ();
  };
  template <typename _CharT, typename _Traits> struct basic_filebuf : public basic_streambuf <_CharT, _Traits>
  {
    typedef _CharT char_type;
    typedef _Traits traits_type;
    typedef typename traits_type::pos_type pos_type;
    typedef typename traits_type::off_type off_type;
    typedef __basic_file < char >__file_type;
    typedef typename traits_type::state_type __state_type;
    __file_type _M_file;
    char_type *_M_pback_cur_save;
    bool _M_pback_init;
    void _M_destroy_pback () throw ()
    {
_M_pback_cur_save += this->gptr () != this->eback ();
_M_pback_init = false;
    }
    bool is_open () throw () { return _M_file.is_open (); }
    pos_type seekpos (pos_type, ios_base::openmode = ios_base::in | ios_base::out);
    pos_type _M_seek (off_type, ios_base::seekdir, __state_type);
  };
  template <typename _CharT, typename _Traits>
  typename basic_filebuf <_CharT, _Traits>::pos_type
  basic_filebuf <_CharT, _Traits>::seekpos (pos_type __pos, ios_base::openmode)
  {
    pos_type __ret = (off_type ());
    if (this->is_open ())
      {
_M_destroy_pback ();
__ret = _M_seek (off_type (), ios_base::beg, __pos.state ());
      }
    return __ret;
  }
  template class basic_filebuf <char, char_traits <char> >;
}

ICEs on redhat/gcc-4_4-branch when compiled with -O3 -mavx -fPIC -m32 -mtune=core2 with:
snb.ii: In member function ‘typename std::basic_filebuf<_CharT, _Traits>::pos_type std::basic_filebuf<_CharT, _Traits>::seekpos(typename _Traits::pos_type, <unnamed>::_Ios_Openmode) [with _CharT = char, _Traits = std::char_traits<char>]’:
snb.ii:87: internal compiler error: in dwarf2out_frame_debug_expr, at dwarf2out.c:2492

Vanilla 4.4 branch generates very similar rtl, the only change seems to be slightly different sched2 decition.
It compiles seekpos into:
        .cfi_startproc
        .cfi_personality 0x9b,DW.ref.__gxx_personality_v0
        .cfi_lsda 0x1b,.LLSDA9
        # basic block 2
        leal    4(%esp), %ecx
        .cfi_def_cfa 1, 0
        andl    $-32, %esp
        pushl   -4(%ecx)
        pushl   %ebp
        movl    %esp, %ebp
        .cfi_escape 0x10,0x5,0x1,0x55
        subl    $120, %esp
        movl    %ebx, 108(%esp)
        movl    %ecx, 104(%esp)
        .cfi_escape 0xf,0x3,0x75,0x70,0x6
        movl    %esi, 112(%esp)
        movl    %edi, 116(%esp)
        call    .L17
.L17:
        popl    %ebx
        addl    $_GLOBAL_OFFSET_TABLE_+[.-.L17], %ebx
        .cfi_escape 0x10,0x7,0x2,0x75,0x7c
        .cfi_escape 0x10,0x6,0x2,0x75,0x78
        .cfi_escape 0x10,0x3,0x2,0x75,0x74
        movl    (%ecx), %esi
        movl    %ecx, -60(%ebp)

but redhat/gcc-4_4-branch reorders the %ecx stores, so after sp = sp - 120 there is:
        subl    $120, %esp
        movl    %ecx, -60(%ebp)
        movl    %ebx, 108(%esp)
        movl    %esi, 112(%esp)
        movl    %ecx, 104(%esp)
        movl    %edi, 116(%esp)
([ebp-60] = ecx got moved earlier, and [sp+108] = ecx got moved later).
Given that both of these ecx stores are frame related, I don't see anything wrong on that scheduling decision.
But when processing the frame related insns in dwarf2out, after sp = sp - 120 we have:
(gdb) p cfa
$1 = {offset = 0, base_offset = 0, reg = 2, indirect = 0, in_use = 0}
(gdb) p cfa_temp
$2 = {offset = 0, base_offset = 0, reg = 2, indirect = 0, in_use = 0}
(gdb) p cfa_store
$3 = {offset = 120, base_offset = 0, reg = 7, indirect = 0, in_use = 0}
and so ICE, because we don't know what offset to use:
2488    if (cfa_store.reg == (unsigned) regno)
2489      offset -= cfa_store.offset;
2490    else
2491      {
2492        gcc_assert (cfa_temp.reg == (unsigned) regno);
2493        offset -= cfa_temp.offset;
2494      }
The store using ebp comes from the code before IRA starting with
(set (reg:SI 71) (reg:SI %ecx)) and IRA spilling reg:SI 71 to the stack.
This insn has been created by ix86_get_drap_rtx ():
8098      drap_vreg = copy_to_reg (arg_ptr);
The second store of %ecx comes from prologue expansion.
Comment 1 H.J. Lu 2010-03-08 15:03:22 UTC
Can you make it to fail on trunk or 4.4 branch since it
could be caused by other changes on redhat/gcc-4_4-branch?
If not, can you find out which change on redhat/gcc-4_4-branch
causes this?
Comment 2 Jakub Jelinek 2010-03-08 15:12:48 UTC
I've tried, but haven't succeeded, that's why I said the bug is latent there.  If we can prove this situation can't ever happen on 4.4 or 4.5 (4.5 on this testcase doesn't use a drap reg at all, so we'd need some other testcase where it does), then I'll of course do something on our branch only.  But I believe this is just a general problem.  BTW, even the 4.4 generated unwind info is bad:
  DW_CFA_advance_loc: 4 to 00000004
  DW_CFA_def_cfa: r1 (ecx) ofs 0
  DW_CFA_advance_loc: 9 to 0000000d
  DW_CFA_expression: r5 (ebp) (DW_OP_reg5)
  DW_CFA_advance_loc: 11 to 00000018
  DW_CFA_def_cfa_expression (DW_OP_breg5: -16; DW_OP_deref)
  DW_CFA_advance_loc: 20 to 0000002c
  DW_CFA_expression: r7 (edi) (DW_OP_breg5: -4)
  DW_CFA_expression: r6 (esi) (DW_OP_breg5: -8)
  DW_CFA_expression: r3 (ebx) (DW_OP_breg5: -12)

   0:   8d 4c 24 04             lea    0x4(%esp),%ecx
   4:   83 e4 e0                and    $0xffffffe0,%esp
   7:   ff 71 fc                pushl  -0x4(%ecx)
   a:   55                      push   %ebp
   b:   89 e5                   mov    %esp,%ebp
   d:   83 ec 78                sub    $0x78,%esp
  10:   89 5c 24 6c             mov    %ebx,0x6c(%esp)
  14:   89 4c 24 68             mov    %ecx,0x68(%esp)
  18:   89 74 24 70             mov    %esi,0x70(%esp)
  1c:   89 7c 24 74             mov    %edi,0x74(%esp)
  20:   e8 00 00 00 00          call   25 <_ZNSt13basic_filebufIcSt11char_traitsIcEE7seekposESt4fposI9mbstate_tEN12_GLOBAL__N_113_Ios_OpenmodeE+0x25>
  25:   5b                      pop    %ebx
  26:   81 c3 03 00 00 00       add    $0x3,%ebx
                        28: R_386_GOTPC _GLOBAL_OFFSET_TABLE_
  2c:   8b 31                   mov    (%ecx),%esi
  2e:   89 4d c4                mov    %ecx,-0x3c(%ebp)
1) Saying that %r5 (ebp) is saved in DW_OP_reg5 looks quite redundant to me.
2) More importantly, %ebx is said to be saved in DW_OP_breg5 - 12 only after
add $0x3, %ebx, so when e.g. a debugger stops in between pop %ebx and add $3, %ebx, it will think caller's %ebx still lives in %ebx register, which is wrong.
Comment 3 H.J. Lu 2010-03-08 15:27:18 UTC
(In reply to comment #2)
> I've tried, but haven't succeeded, that's why I said the bug is latent there. 
> If we can prove this situation can't ever happen on 4.4 or 4.5 (4.5 on this
> testcase doesn't use a drap reg at all, so we'd need some other testcase where
> it does), then I'll of course do something on our branch only.  But I believe
> this is just a general problem.  BTW, even the 4.4 generated unwind info is
> bad:

Can you make a run-time testcase out of it?
Comment 4 Jakub Jelinek 2010-03-08 15:44:05 UTC
Ah, the %ebp saved in DW_OP_reg5 is just a 4.4 bug, fixed by http://gcc.gnu.org/ml/gcc-patches/2009-05/msg00235.html (the fix is in 4.5 and 4.4-RH).  Saying that %ebp is saved in DW_OP_breg5 0 is correct and desirable.
Comment 5 H.J. Lu 2010-03-08 15:47:47 UTC
(In reply to comment #4)
> Ah, the %ebp saved in DW_OP_reg5 is just a 4.4 bug, fixed by
> http://gcc.gnu.org/ml/gcc-patches/2009-05/msg00235.html (the fix is in 4.5 and
> 4.4-RH).  Saying that %ebp is saved in DW_OP_breg5 0 is correct and desirable.
> 

Can we backport it to 4.4?
Comment 6 Jakub Jelinek 2010-03-08 16:38:38 UTC
Not sure if there haven't been follow-ups.  There were at least 100 changes to dwarf2out.c since 4.4 release, and at least 10 of them were related to the indirect vs. direct stuff.
Comment 7 Jakub Jelinek 2010-03-08 16:39:18 UTC
Created attachment 20043 [details]
gcc44-pr43290-1.patch

One alternative fix that cures this testcase on redhat/gcc-4_4-branch.
Comment 8 Jakub Jelinek 2010-03-08 16:45:55 UTC
Created attachment 20044 [details]
gcc44-pr43290-2.patch

Another fix.  Wonder why that insn is marked as frame related at all, for the drap saving the spill (and restore) generated by ix86_expand_prologue/ix86_expand_epilogue should be the canonical one, after all where the vDRAP was spilled to is something that could be clobbered before the epilogue if vDRAP starts living in the register again, etc.
Comment 9 H.J. Lu 2010-03-08 16:58:40 UTC
(In reply to comment #8)
> Created an attachment (id=20044) [edit]
> gcc44-pr43290-2.patch
> 
> Another fix.  Wonder why that insn is marked as frame related at all, for the
> drap saving the spill (and restore) generated by
> ix86_expand_prologue/ix86_expand_epilogue should be the canonical one, after
> all where the vDRAP was spilled to is something that could be clobbered before
> the epilogue if vDRAP starts living in the register again, etc.
> 

There may be a reason to do so at the time. If there are no
regressions in gcc testsuite, it probably is OK not to mark
drap as frame related.

Comment 10 Jakub Jelinek 2010-03-08 17:00:56 UTC
I'll test it, both on the trunk and 4.4-RH.

BTW, I've moved the 2) issue to PR43293.
Comment 11 Jakub Jelinek 2010-03-09 18:49:05 UTC
Subject: Bug 43290

Author: jakub
Date: Tue Mar  9 18:48:43 2010
New Revision: 157313

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=157313
Log:
	PR debug/43290
	* config/i386/i386.c (ix86_get_drap_rtx): Don't set
	RTX_FRAME_RELATED_P.

	* g++.dg/eh/unwind2.C: New test.

Added:
    trunk/gcc/testsuite/g++.dg/eh/unwind2.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/i386/i386.c
    trunk/gcc/testsuite/ChangeLog

Comment 12 Jakub Jelinek 2010-03-09 19:01:36 UTC
Fixed for 4.5+.
Comment 13 H.J. Lu 2010-03-09 22:39:34 UTC
(In reply to comment #9)
> (In reply to comment #8)
> > Created an attachment (id=20044) [edit]
> > gcc44-pr43290-2.patch
> > 
> > Another fix.  Wonder why that insn is marked as frame related at all, for the
> > drap saving the spill (and restore) generated by
> > ix86_expand_prologue/ix86_expand_epilogue should be the canonical one, after
> > all where the vDRAP was spilled to is something that could be clobbered before
> > the epilogue if vDRAP starts living in the register again, etc.
> > 
> 
> There may be a reason to do so at the time. If there are no
> regressions in gcc testsuite, it probably is OK not to mark
> drap as frame related.
> 

It is for PR 36728.
Comment 14 H.J. Lu 2010-03-09 22:44:23 UTC
Is there a way to add debug testcases from PR 36728 to gcc testsuite?
Comment 15 Jakub Jelinek 2010-03-09 22:54:32 UTC
Yes, sticking them in gcc/testsuite/gcc.dg/guality/ and using 
/* { dg-final { gdb-test <line> "<varname>" "<expectedvalue>" } } */

If my patch really broke that, then I think we'll need to use some REG_CFA_* note or something similar to be able to differentiate between this vDRAP = DRAP
insn and saving DRAP into a prologue save slot.
Comment 16 Jakub Jelinek 2010-03-10 00:33:09 UTC
Created attachment 20072 [details]
gcc45-pr43290.patch

Untested patch.
Comment 17 H.J. Lu 2010-03-10 05:37:49 UTC
(In reply to comment #15)
> Yes, sticking them in gcc/testsuite/gcc.dg/guality/ and using 
> /* { dg-final { gdb-test <line> "<varname>" "<expectedvalue>" } } */
> 
> If my patch really broke that, then I think we'll need to use some REG_CFA_*
> note or something similar to be able to differentiate between this vDRAP = DRAP
> insn and saving DRAP into a prologue save slot.
> 

I will add some testcases for PR 36728 to make sure that it isn't
broken.
Comment 18 Jakub Jelinek 2010-03-10 08:07:33 UTC
Created attachment 20073 [details]
gcc45-pr43290.patch

Updated patch.  This one includes testcases, and also fixes for -O+, when optimizing we really shouldn't be replacing random registers that once happened to be vDRAP or DRAP somewhere with DW_OP_fbreg and there is no point tracking it at all - after all when optimizing combiner or some other optimization pass
will very likely remove the vDRAP = DRAP insn anyway.  For -O1+ var-tracking is supposed to do the right job finding where the variable lives.
Comment 19 Jakub Jelinek 2010-03-10 18:17:26 UTC
Subject: Bug 43290

Author: jakub
Date: Wed Mar 10 18:17:10 2010
New Revision: 157363

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=157363
Log:
	PR debug/43290
	* reg-notes.def (REG_CFA_SET_VDRAP): New note.
	* dwarf2out.c (dwarf2out_frame_debug_expr): Remove rule 20 - setting
	of fde->vdrap_reg.
	(dwarf2out_frame_debug): Handle REG_CFA_SET_VDRAP note.
	(based_loc_descr): Only express drap or vdrap regno based expressions
	using DW_OP_fbreg when not optimizing.
	* config/i386/i386.c (ix86_get_drap_rtx): When not optimizing,
	make the vDRAP = DRAP assignment RTX_FRAME_RELATED_P and add
	REG_CFA_SET_VDRAP note.

	PR debug/36728
	* gcc.dg/guality/pr36728-1.c: New test.
	* gcc.dg/guality/pr36728-2.c: New test.

Added:
    trunk/gcc/testsuite/gcc.dg/guality/pr36728-1.c
    trunk/gcc/testsuite/gcc.dg/guality/pr36728-2.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/i386/i386.c
    trunk/gcc/dwarf2out.c
    trunk/gcc/reg-notes.def
    trunk/gcc/testsuite/ChangeLog

Comment 20 Ryan Hill 2011-03-04 21:54:01 UTC
We're hitting this on vanilla 4.4.5.  Any chance of a backport?

https://bugs.gentoo.org/357287
Comment 21 Ryan Hill 2011-03-09 02:28:21 UTC
this is an in-branch regression from 4.4.4 and prevents -march=native bootstrap on Sandy Bridge.  want a new bug?
Comment 22 Ryan Hill 2011-10-07 01:37:51 UTC
And now 4.4.6.