/* PR middle-end/99612 - Missing warning on incorrect memory order without
   -Wsystem-headers
   Verify that constants are propagated through calls to inline functions
   even at -O0.
   Also verify that the informational notes after each warning mention
   the valid memore models for each function.
   { dg-do compile }
   { dg-options "-O0 -ftrack-macro-expansion=0" } */

#if !__cplusplus
# define bool _Bool
#endif

extern int ei;

static __attribute__ ((always_inline)) inline
int retval (int val)
{
  return val;
}

void test_load (int *pi)
{
  int relaxed = retval (__ATOMIC_RELAXED);
  *pi++ = __atomic_load_n (&ei, relaxed);

  int consume = retval (__ATOMIC_CONSUME);
  *pi++ = __atomic_load_n (&ei, consume);

  int acquire = retval (__ATOMIC_ACQUIRE);
  *pi++ = __atomic_load_n (&ei, acquire);

  int release = retval (__ATOMIC_RELEASE);
  *pi++ = __atomic_load_n (&ei, release);   // { dg-warning "invalid memory model 'memory_order_release'" }
  // { dg-message "valid models are 'memory_order_relaxed', 'memory_order_seq_cst', 'memory_order_acquire', 'memory_order_consume'" "note" { target *-*-* } .-1 }

  int acq_rel = retval (__ATOMIC_ACQ_REL);
  *pi++ = __atomic_load_n (&ei, acq_rel);   // { dg-warning "invalid memory model 'memory_order_acq_rel'" }

  int seq_cst = retval (__ATOMIC_SEQ_CST);
  *pi++ = __atomic_load_n (&ei, seq_cst);

  /* Verify a nonconstant range.  */
  int r0_1 = *pi++;
  if (r0_1 < 0 || 1 < r0_1)
    r0_1 = 0;
  *pi++ = __atomic_load_n (&ei, r0_1);

  /* Verify an unbounded range.  */
  int unknown = *pi++;
  *pi++ = __atomic_load_n (&ei, unknown);
}


void test_store (int *pi, int x)
{
  int relaxed = retval (__ATOMIC_RELAXED);
  __atomic_store_n (pi++, x, relaxed);

  int consume = retval (__ATOMIC_CONSUME);
  __atomic_store_n (pi++, x, consume);      // { dg-warning "invalid memory model 'memory_order_consume'" }
  // { dg-message "valid models are 'memory_order_relaxed', 'memory_order_seq_cst', 'memory_order_release'" "note" { target *-*-* } .-1 }

  int acquire = retval (__ATOMIC_ACQUIRE);
  __atomic_store_n (pi++, x, acquire);      // { dg-warning "invalid memory model 'memory_order_acquire'" }

  int release = retval (__ATOMIC_RELEASE);
  __atomic_store_n (pi++, x, release);

  int acq_rel = retval (__ATOMIC_ACQ_REL);
  __atomic_store_n (pi++, x, acq_rel);      // { dg-warning "invalid memory model 'memory_order_acq_rel'" }

  int seq_cst = retval (__ATOMIC_SEQ_CST);
  __atomic_store_n (pi++, x, seq_cst);

  int unknown = *pi++;
  __atomic_store_n (pi++, x, unknown);
}


/* All memory models are valid.  */

void test_exchange (int *pi, int x)
{
  int relaxed = retval (__ATOMIC_RELAXED);
  __atomic_exchange_n (pi++, x, relaxed);

  int consume = retval (__ATOMIC_CONSUME);
  __atomic_exchange_n (pi++, x, consume);

  int acquire = retval (__ATOMIC_ACQUIRE);
  __atomic_exchange_n (pi++, x, acquire);

  int release = retval (__ATOMIC_RELEASE);
  __atomic_exchange_n (pi++, x, release);

  int acq_rel = retval (__ATOMIC_ACQ_REL);
  __atomic_exchange_n (pi++, x, acq_rel);

  int seq_cst = retval (__ATOMIC_SEQ_CST);
  __atomic_exchange_n (pi++, x, seq_cst);

  int unknown = *pi++;
  __atomic_exchange_n (pi++, x, unknown);
}


void test_compare_exchange (int *pi, int *pj, bool weak)
{
#define cmpxchg(x, expect, desire, sucs_ord, fail_ord) \
  __atomic_compare_exchange_n (x, expect, desire, weak, sucs_ord, fail_ord)

  int relaxed = retval (__ATOMIC_RELAXED);
  cmpxchg (&ei, pi++, *pj++, relaxed, relaxed);

  int consume = retval (__ATOMIC_CONSUME);
  cmpxchg (&ei, pi++, *pj++, relaxed, consume);   // { dg-warning "failure memory model 'memory_order_consume' cannot be stronger than success memory model 'memory_order_relaxed'" }

  int acquire = retval (__ATOMIC_ACQUIRE);
  cmpxchg (&ei, pi++, *pj++, relaxed, acquire);   // { dg-warning "failure memory model 'memory_order_acquire' cannot be stronger than success memory model 'memory_order_relaxed'" }

  int release = retval (__ATOMIC_RELEASE);
  cmpxchg (&ei, pi++, *pj++, relaxed, release);   // { dg-warning "invalid failure memory model 'memory_order_release'" }

  int acq_rel = retval (__ATOMIC_ACQ_REL);
  cmpxchg (&ei, pi++, *pj++, relaxed, acq_rel);   // { dg-warning "invalid failure memory model 'memory_order_acq_rel'" }

  int seq_cst = retval (__ATOMIC_SEQ_CST);
  cmpxchg (&ei, pi++, *pj++, relaxed, seq_cst);   // { dg-warning "failure memory model 'memory_order_seq_cst' cannot be stronger than success memory model 'memory_order_relaxed'" }


  cmpxchg (&ei, pi++, *pj++, consume, relaxed);
  cmpxchg (&ei, pi++, *pj++, consume, consume);
  cmpxchg (&ei, pi++, *pj++, consume, acquire);   // { dg-warning "failure memory model 'memory_order_acquire' cannot be stronger than success memory model 'memory_order_consume'" }
  cmpxchg (&ei, pi++, *pj++, consume, release);   // { dg-warning "invalid failure memory model 'memory_order_release'" }
  cmpxchg (&ei, pi++, *pj++, consume, acq_rel);   // { dg-warning "invalid failure memory model 'memory_order_acq_rel'" }
  cmpxchg (&ei, pi++, *pj++, consume, seq_cst);   // { dg-warning "failure memory model 'memory_order_seq_cst' cannot be stronger than success memory model 'memory_order_consume'" }

  cmpxchg (&ei, pi++, *pj++, acquire, relaxed);
  cmpxchg (&ei, pi++, *pj++, acquire, consume);
  cmpxchg (&ei, pi++, *pj++, acquire, acquire);
  cmpxchg (&ei, pi++, *pj++, acquire, release);   // { dg-warning "invalid failure memory model 'memory_order_release'" }
  cmpxchg (&ei, pi++, *pj++, acquire, acq_rel);   // { dg-warning "invalid failure memory model 'memory_order_acq_rel'" }
  cmpxchg (&ei, pi++, *pj++, acquire, seq_cst);   // { dg-warning "failure memory model 'memory_order_seq_cst' cannot be stronger than success memory model 'memory_order_acquire'" }

  cmpxchg (&ei, pi++, *pj++, release, relaxed);
  cmpxchg (&ei, pi++, *pj++, release, consume);
  cmpxchg (&ei, pi++, *pj++, release, acquire);
  cmpxchg (&ei, pi++, *pj++, release, release);   // { dg-warning "invalid failure memory model 'memory_order_release'" }
  cmpxchg (&ei, pi++, *pj++, release, acq_rel);   // { dg-warning "invalid failure memory model 'memory_order_acq_rel'" }
  cmpxchg (&ei, pi++, *pj++, release, seq_cst);   // { dg-warning "failure memory model 'memory_order_seq_cst' cannot be stronger than success memory model 'memory_order_release'" }

  cmpxchg (&ei, pi++, *pj++, acq_rel, relaxed);
  cmpxchg (&ei, pi++, *pj++, acq_rel, consume);
  cmpxchg (&ei, pi++, *pj++, acq_rel, acquire);
  cmpxchg (&ei, pi++, *pj++, acq_rel, release);   // { dg-warning "invalid failure memory model 'memory_order_release'" }
  cmpxchg (&ei, pi++, *pj++, acq_rel, acq_rel);   // { dg-warning "invalid failure memory model 'memory_order_acq_rel'" }
  cmpxchg (&ei, pi++, *pj++, acq_rel, seq_cst);   // { dg-warning "failure memory model 'memory_order_seq_cst' cannot be stronger than success memory model 'memory_order_acq_rel'" }

  cmpxchg (&ei, pi++, *pj++, seq_cst, relaxed);
  cmpxchg (&ei, pi++, *pj++, seq_cst, consume);
  cmpxchg (&ei, pi++, *pj++, seq_cst, acquire);
  cmpxchg (&ei, pi++, *pj++, seq_cst, release);   // { dg-warning "invalid failure memory model 'memory_order_release'" }
  cmpxchg (&ei, pi++, *pj++, seq_cst, acq_rel);   // { dg-warning "invalid failure memory model 'memory_order_acq_rel'" }
  cmpxchg (&ei, pi++, *pj++, seq_cst, seq_cst);

  int unknown = *pi++;
  cmpxchg (&ei, pi++, *pj++, unknown, seq_cst);
  cmpxchg (&ei, pi++, *pj++, relaxed, unknown);
}


/* All memory models are valid.  */

void test_add_fetch (unsigned *pi, unsigned x)
{
  int relaxed = retval (__ATOMIC_RELAXED);
  __atomic_add_fetch (pi++, x, relaxed);

  int consume = retval (__ATOMIC_CONSUME);
  __atomic_add_fetch (pi++, x, consume);

  int acquire = retval (__ATOMIC_ACQUIRE);
  __atomic_add_fetch (pi++, x, acquire);

  int release = retval (__ATOMIC_RELEASE);
  __atomic_add_fetch (pi++, x, release);

  int acq_rel = retval (__ATOMIC_ACQ_REL);
  __atomic_add_fetch (pi++, x, acq_rel);

  int seq_cst = retval (__ATOMIC_SEQ_CST);
  __atomic_add_fetch (pi++, x, seq_cst);

  int invalid;
  if (x & 1)
    {
      invalid = retval (123);
      __atomic_add_fetch (pi++, x, invalid);  // { dg-warning "invalid memory model 123 for '\(unsigned int \)?__atomic_add_fetch" }
    }
  else
    {
      invalid = retval (456);
      __atomic_add_fetch (pi++, x, invalid);  // { dg-warning "invalid memory model 456 for '\(unsigned int \)?__atomic_add_fetch" }
    }
}

void test_sub_fetch (unsigned *pi, unsigned x)
{
  int relaxed = retval (__ATOMIC_RELAXED);
  __atomic_sub_fetch (pi++, x, relaxed);

  int consume = retval (__ATOMIC_CONSUME);
  __atomic_sub_fetch (pi++, x, consume);

  int acquire = retval (__ATOMIC_ACQUIRE);
  __atomic_sub_fetch (pi++, x, acquire);

  int release = retval (__ATOMIC_RELEASE);
  __atomic_sub_fetch (pi++, x, release);

  int acq_rel = retval (__ATOMIC_ACQ_REL);
  __atomic_sub_fetch (pi++, x, acq_rel);

  int seq_cst = retval (__ATOMIC_SEQ_CST);
  __atomic_sub_fetch (pi++, x, seq_cst);

  int invalid;
  if (x & 1)
    {
      invalid = retval (123);
      __atomic_sub_fetch (pi++, x, invalid);  // { dg-warning "invalid memory model 123 for '\(unsigned int \)?__atomic_sub_fetch" }
    }
  else
    {
      invalid = retval (456);
      __atomic_sub_fetch (pi++, x, invalid);  // { dg-warning "invalid memory model 456 for '\(unsigned int \)?__atomic_sub_fetch" }
    }
}