Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 08 Jan 2013 10:22:17 +0100
From:      Dimitry Andric <dim@FreeBSD.org>
To:        David Chisnall <theraven@freebsd.org>
Cc:        Stefan Farfeleder <stefanf@freebsd.org>, Nathan Whitehorn <nwhitehorn@freebsd.org>, freebsd-current@freebsd.org
Subject:   Re: clang 3.2 RC2 miscompiles libgcc?
Message-ID:  <50EBE549.9070808@FreeBSD.org>
In-Reply-To: <1D415F08-5FFC-41B5-9A0D-E03757800E0C@freebsd.org>
References:  <20121227150724.GA1431@mole.fafoe.narf.at> <50DC65F5.6060004@freebsd.org> <50E0BD66.4070609@FreeBSD.org> <20130102135950.GA1464@mole.fafoe.narf.at> <20130104154940.GD1430@mole.fafoe.narf.at> <20130106141708.GA1418@mole.fafoe.narf.at> <50E9916F.3040500@FreeBSD.org> <20130106160331.GB1418@mole.fafoe.narf.at> <50EB5868.2050509@FreeBSD.org> <1D415F08-5FFC-41B5-9A0D-E03757800E0C@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On 2013-01-08 09:08, David Chisnall wrote:
> On 7 Jan 2013, at 23:21, Dimitry Andric wrote:
>> This is at least the direction I'm looking at.  It seems that in some
>> cases with __builtin_eh_return(), llvm does not see that registers can
>> be clobbered, and it doesn't save and restore them.
> Do you mean that some registers were clobbered by a prior call?  __builtin_eh_return() doesn't return, so whether it clobbers anything or not isn't something that should matter.  The preceding call is __builtin_frob_return_addr, which seems to be a no-op, so it shouldn't clobber any registers either...

No, I mean that gcc seems to take great care in saving and restoring
almost all important registers in a function, if that function contains
a call to __builtin_eh_return.

If you look at expand_eh_return() in contrib/gcc/except.c, you can see
that it sets the special variable 'current_function_calls_eh_return'.

This influences the code generation all over the place, and specifically
the saving of registers in contrib/gcc/config/i386/i386.c:

======================================================================
/* Return 1 if we need to save REGNO.  */
static int
ix86_save_reg (unsigned int regno, int maybe_eh_return)
{
   if (pic_offset_table_rtx
       && regno == REAL_PIC_OFFSET_TABLE_REGNUM
       && (regs_ever_live[REAL_PIC_OFFSET_TABLE_REGNUM]
	  || current_function_profile
	  || current_function_calls_eh_return
	  || current_function_uses_const_pool))
     {
       if (ix86_select_alt_pic_regnum () != INVALID_REGNUM)
	return 0;
       return 1;
     }

   if (current_function_calls_eh_return && maybe_eh_return)
     {
       unsigned i;
       for (i = 0; ; i++)
	{
	  unsigned test = EH_RETURN_DATA_REGNO (i);
	  if (test == INVALID_REGNUM)
	    break;
	  if (test == regno)
	    return 1;
	}
     }
[...]
/* Emit code to save registers in the prologue.  */

static void
ix86_emit_save_regs (void)
{
   unsigned int regno;
   rtx insn;

   for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0; )
     if (ix86_save_reg (regno, true))
       {
	insn = emit_insn (gen_push (gen_rtx_REG (Pmode, regno)));
	RTX_FRAME_RELATED_P (insn) = 1;
       }
}
======================================================================

On i386, most registers are touched anyway in _Unwind_Resume, so clang
will already save and restore them.  But on amd64, there are more
registers than local variables, so clang only seems to save a few; not
enough, in any case.  This is why I added the asm statement which
clobbers all those registers, forcing clang to save and restore them.

This fixes most of the crashes I was able to reproduce.  I think I still
have another unrelated issue in libgcc with clang, but this only occurs
when compiling the testcases with gcc 4.7, and very high optimization.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?50EBE549.9070808>