http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58192

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jakub at gcc dot gnu.org,
                   |                            |rth at gcc dot gnu.org

--- Comment #5 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
The difference is that in the S1::<anon struct>::set(Foo) case
setup_incoming_promotions in combine.c says that the argument has non-zero mask
of 0xff, because the function is local to the TU, while for S2 all caller's
aren't guaranteed local and thus it isn't optimized.  The argument type is Foo
(QImode) passed in SImode register, guess combine.c expects that caller
zero-extends in this case, but it doesn't (in neither case).

enum class Foo : unsigned char { FOO };
struct S1
{
  struct
  {
    unsigned int i;
    void __attribute__((noinline))
    set (Foo foo)
    {
      i = static_cast<unsigned int> (foo);
    }
  } x;
};
struct S2
{
  struct X
  {
    unsigned int i;
    void __attribute__((noinline))
    set (Foo foo)
    {
      i = static_cast<unsigned int> (foo);
    }
  };
  X x;
};
struct T { unsigned short i; Foo f; unsigned char c; };

__attribute__((noinline)) void
baz (unsigned int x)
{
  if (x != 0) __builtin_abort ();
}

void
bar (T t)
{
  S1 s1;
  s1.x.set(t.f);
  baz (s1.x.i);
  S2 s2;
  s2.x.set(t.f);
  baz (s2.x.i);
}

int
main()
{
  T t = { 0xabcd, Foo::FOO, 0xef};
  bar (t);
}

For:
unsigned int v1, v2;

__attribute__((noinline, noclone)) static void
foo (unsigned char a)
{
  v1 = a;
}

__attribute__((noinline, noclone)) void
bar (unsigned char a)
{
  v2 = a;
}

void
baz (unsigned int a)
{
  foo (a);
  bar (a);
}
the situation is similar for foo/bar (foo optimizes and doesn't zero extend
from 8 to 32 bits, bar doesn't), but the caller in this case always zero
extends.

Reply via email to