/* PR middle-end/47893 */
/* { dg-do run } */
/* { dg-options "-O2" } */
/* { dg-additional-options "-mtune=atom -fno-omit-frame-pointer -fno-strict-aliasing" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */
/* { dg-skip-if "Too much RAM needed" { "avr-*-*" } } */

extern void abort (void);

struct S
{
  unsigned s1:4, s2:2, s3:2, s4:2, s5:2, s6:1, s7:1, s8:1, s9:1, s10:1;
  int s11:16; unsigned s12:4; int s13:16; unsigned s14:2;
  int s15:16; unsigned s16:4; int s17:16; unsigned s18:2;
};

struct T
{
  unsigned t[3];
};

struct U
{
  unsigned u1, u2;
};

struct V;

struct W
{
  char w1[24]; struct V *w2; unsigned w3; char w4[28912];
  unsigned int w5; char w6[60];
};

struct X
{
  unsigned int x[2];
};

struct V
{
  int v1;
  struct X v2[3];
  char v3[28];
};

struct Y
{
  void *y1;
  char y2[3076];
  struct T y3[32];
  char y4[1052];
};

volatile struct S v1 = { .s15 = -1, .s16 = 15, .s17 = -1, .s18 = 3 };

__attribute__ ((noinline, noclone))
int
fn1 (int x)
{
  int r;
  __asm__ volatile ("" : "=r" (r) : "0" (1), "r" (x) : "memory");
  return r;
}

volatile int cnt;

__attribute__ ((noinline, noclone))
#ifdef __i386__
__attribute__ ((regparm (2)))
#endif
struct S
fn2 (struct Y *x, const struct X *y)
{
  if (++cnt > 1)
    abort ();
  __asm__ volatile ("" : : "r" (x), "r" (y) : "memory");
  return v1;
}

__attribute__ ((noinline, noclone))
void fn3 (void *x, unsigned y, const struct S *z, unsigned w)
{
  __asm__ volatile ("" : : "r" (x), "r" (y), "r" (z), "r" (w) : "memory");
}

volatile struct U v2;

__attribute__ ((noinline, noclone))
struct U
fn4 (void *x, unsigned y)
{
  __asm__ volatile ("" : : "r" (x), "r" (y) : "memory");
  return v2;
}

__attribute__ ((noinline, noclone))
struct S
fn5 (void *x)
{
  __asm__ volatile ("" : : "r" (x) : "memory");
  return v1;
}

volatile struct T v3;

__attribute__ ((noinline, noclone))
struct T fn6 (void *x)
{
  __asm__ volatile ("" : : "r" (x) : "memory");
  return v3;
}

__attribute__ ((noinline, noclone))
struct T fn7 (void *x, unsigned y, unsigned z)
{
  __asm__ volatile ("" : : "r" (x), "r" (y), "r" (z) : "memory");
  return v3;
}

static void
fn8 (struct Y *x, const struct V *y)
{
  void *a = x->y1;
  struct S b[4];
  unsigned i, c;
  c = fn1 (y->v1);
  for (i = 0; i < c; i++)
    b[i] = fn2 (x, &y->v2[i]);
  fn3 (a, y->v1, b, c);
}

static inline void
fn9 (void *x, struct S y __attribute__((unused)))
{
  fn4 (x, 8);
}

static void
fn10 (struct Y *x)
{
  void *a = x->y1;
  struct T b __attribute__((unused)) = fn6 (a);
  fn9 (a, fn5 (a));
}

__attribute__((noinline, noclone))
int
fn11 (unsigned int x, void *y, const struct W *z,
      unsigned int w, const char *v, const char *u)
{
  struct Y a, *t;
  unsigned i;
  t = &a;
  __builtin_memset (t, 0, sizeof *t);
  t->y1 = y;
  if (x == 0)
    {
      if (z->w3 & 1)
	fn10 (t);
      for (i = 0; i < w; i++)
	{
	  if (v[i] == 0)
	    t->y3[i] = fn7 (y, 0, u[i]);
	  else
	    return 0;
	}
    }
  else
    for (i = 0; i < w; i++)
      t->y3[i] = fn7 (y, v[i], u[i]);
  for (i = 0; i < z->w5; i++)
    fn8 (t, &z->w2[i]);
  return 0;
}

volatile int i;
const char *volatile p = "";

int
main ()
{
  struct V v = { .v1 = 0 };
  struct W w = { .w5 = 1, .w2 = &v };
  fn11 (i + 1, (void *) p, &w, i, (const char *) p, (const char *) p);
  if (cnt != 1)
    abort ();
  return 0;
}
