This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

block reordering problem


glibc ones more does not compile with the current mainline gcc on x86.
I haven't tried it for quite some time so I cannot say when the
problem got introduced.

I managed to get a reduced testcase which I append below.  Compile it
with

	-O3 -march=i686 -freorder-blocks

The interesting case is the fail branch of the ?: operator in foo.
Due to block reordering and the NULL pointer comparison this code is
ouf ot line.  The code I get for the function is this:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const char *
foo (const char *n, const char *m)
  30:   55                      push   %ebp
  31:   89 e5                   mov    %esp,%ebp
  33:   53                      push   %ebx
  34:   83 ec 14                sub    $0x14,%esp
  37:   8b 4d 08                mov    0x8(%ebp),%ecx
  3a:   8b 5d 0c                mov    0xc(%ebp),%ebx
{
  3d:   85 db                   test   %ebx,%ebx
  3f:   74 20                   je     61 <foo+0x31>
  41:   83 ec 08                sub    $0x8,%esp
  44:   51                      push   %ecx
  45:   53                      push   %ebx
  46:   e8 fc ff ff ff          call   47 <foo+0x17>
                        47: R_386_PC32  bar
  4b:   83 c4 10                add    $0x10,%esp
  const char *r = m ? bar (m, n) : local_strdup (n);
  4e:   83 ec 0c                sub    $0xc,%esp
  51:   50                      push   %eax
  52:   e8 fc ff ff ff          call   53 <foo+0x23>
                        53: R_386_PC32  baz
  return baz (r);
  57:   8b 5d fc                mov    0xfffffffc(%ebp),%ebx
  5a:   83 c4 10                add    $0x10,%esp
  5d:   89 ec                   mov    %ebp,%esp
  5f:   5d                      pop    %ebp
  60:   c3                      ret    
  61:   89 c8                   mov    %ecx,%eax
  63:   83 ec 0c                sub    $0xc,%esp
  66:   8a 10                   mov    (%eax),%dl
  68:   8d 40 01                lea    0x1(%eax),%eax
  6b:   84 d2                   test   %dl,%dl
  6d:   75 f7                   jne    66 <foo+0x36>
  6f:   29 c8                   sub    %ecx,%eax
  71:   50                      push   %eax
  72:   e8 fc ff ff ff          call   73 <foo+0x43>
                        73: R_386_PC32  malloc
  77:   83 c4 10                add    $0x10,%esp
  7a:   85 c0                   test   %eax,%eax
  7c:   0f 44 c3                cmove  %ebx,%eax
  7f:   eb cd                   jmp    4e <foo+0x1e>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The test at offset 0x3d is the test in the ?: operator.  At offset
0x61 you'll see the inlined strlen() call and then the malloc() call.
So far so good.  At offset 0x7a the memcpy() part of the
local_strdup() function should be but there is just the test with a
senseless conditional move.  At offset 0x4e there is just the call of
baz().  This means the memcpy() call (or the inlining) was optimized
out.

It tried making this into a runnable program but failed because -O3
wants to inline a lot and this makes the problem go away.

-- 
---------------.                          ,-.   1325 Chesapeake Terrace
Ulrich Drepper  \    ,-------------------'   \  Sunnyvale, CA 94089 USA
Red Hat          `--' drepper at redhat.com   `------------------------

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <stddef.h>
extern void *malloc (size_t) __attribute__ ((__malloc__));
size_t
strlen (__const char *__str)
{
  register char __dummy;
  register __const char *__tmp = __str;
  __asm__ __volatile__
    ("1:\n\t"
     "movb      (%0),%b1\n\t"
     "leal      1(%0),%0\n\t"
     "testb     %b1,%b1\n\t"
     "jne       1b"
     : "=r" (__tmp), "=&q" (__dummy)
     : "0" (__str)
     : "memory", "cc" );
  return __tmp - __str - 1;
}
void *
memcpy (void *__dest, __const void *__src, size_t __n)
{
  register unsigned long int __d0, __d1, __d2;
  register void *__tmp = __dest;
  __asm__ __volatile__
    ("cld\n\t"
     "shrl      $1,%%ecx\n\t"
     "jnc       1f\n\t"
     "movsb\n"
     "1:\n\t"
     "shrl      $1,%%ecx\n\t"
     "jnc       2f\n\t"
     "movsw\n"
     "2:\n\t"
     "rep; movsl"
     : "=&c" (__d0), "=&D" (__d1), "=&S" (__d2)
     : "0" (__n), "1" (__tmp), "2" (__src)
     : "memory", "cc");
  return __dest;
}


static inline char *
local_strdup (const char *s)
{
  size_t len = strlen (s) + 1;
  void *new = malloc (len);

  if (new == NULL)
    return NULL;

  return (char *) memcpy (new, s, len);
}

extern const char *bar (const char *, const char *);
extern const char *baz (const char *);
const char *
foo (const char *n, const char *m)
{
  const char *r = m ? bar (m, n) : local_strdup (n);
  return baz (r);
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]