Re: clang 3.2 RC2 miscompiles libgcc?

From: Dimitry Andric <dim_at_FreeBSD.org>
Date: Tue, 08 Jan 2013 10:22:17 +0100
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.
Received on Tue Jan 08 2013 - 08:22:21 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:40:33 UTC