/* PR tree-optimization/100864 */

/* { dg-do run } */
/* { dg-options "-O1 -fdump-tree-optimized-raw" } */

#define op_ne !=
#define op_eq ==
#define op_lt <
#define op_le <=
#define op_gt >
#define op_ge >=

#define operators(t) \
t(ne) \
t(eq) \
t(lt) \
t(le) \
t(gt) \
t(ge)

#define cmpfunc(v, op) \
__attribute__((noipa)) \
_Bool func_##op##_##v(v int a, v int b, v _Bool e) \
{ \
  v _Bool c = (a op_##op b); \
  v _Bool d = !c; \
  return (e & d) | c; \
}

#define cmp_funcs(op) \
cmpfunc(, op) \
cmpfunc(volatile , op)

operators(cmp_funcs)

#define test(op) \
if (func_##op##_ (a, b, e) != func_##op##_volatile (a, b, e)) \
 __builtin_abort();

int main()
{
  for(int a = -3; a <= 3; a++)
    for(int b = -3; b <= 3; b++)
      {
       _Bool e = 0;
       operators(test)
       e = 1;
       operators(test)
      }
  return 0;
}

/* Check to make sure we optimize `(a&!b) | b` -> `a | b`. */
/* There are 6 different comparison operators testing here. */
/* bit_not_expr and bit_and_expr should show up for each one (volatile). */
/* Each operator should show up twice
   (except for `!=` which shows up 2*6 (each tester) + 2 (the 2 loops) extra = 16). */
/* bit_ior_expr will show up for each operator twice (non-volatile and volatile). */
/* { dg-final { scan-tree-dump-times "ne_expr,"      16 "optimized"} } */
/* { dg-final { scan-tree-dump-times "eq_expr,"       2 "optimized"} } */
/* { dg-final { scan-tree-dump-times "lt_expr,"       2 "optimized"} } */
/* { dg-final { scan-tree-dump-times "le_expr,"       2 "optimized"} } */
/* { dg-final { scan-tree-dump-times "gt_expr,"       2 "optimized"} } */
/* { dg-final { scan-tree-dump-times "ge_expr,"       2 "optimized"} } */
/* { dg-final { scan-tree-dump-times "bit_not_expr,"  6 "optimized"} } */
/* { dg-final { scan-tree-dump-times "bit_and_expr,"  6 "optimized"} } */
/* { dg-final { scan-tree-dump-times "bit_ior_expr," 12 "optimized"} } */