/* Test vdiv works correctly.  */
/* { dg-do run } */
/* { dg-options "-O3 --save-temps" } */

#include <arm_neon.h>

#define FLT_INFINITY (__builtin_inff ())
#define DBL_INFINITY (__builtin_inf ())

#define NAN (__builtin_nan (""))

#define PI 3.141592653589793
#define PI_4 0.7853981633974483
#define SQRT2 1.4142135623730951
#define SQRT1_2 0.7071067811865475

#define TESTA0 PI
#define TESTA1 -PI
#define TESTA2 PI
#define TESTA3 -PI
#define TESTA4 1.0
#define TESTA5 -1.0
#define TESTA6 1.0
#define TESTA7 -1.0
/* 2^25+1, float has 24 significand bits
   according to Single-precision floating-point format.  */
#define TESTA8_FLT 33554433
/* 2^54+1, double has 53 significand bits
   according to Double-precision floating-point format.  */
#define TESTA8_DBL 18014398509481985
#define TESTA9 -TESTA8
#define TESTA10 TESTA8
#define TESTA11 -TESTA8
#define TESTA12 NAN
#define TESTA13 1.0
#define TESTA14 INFINITY
#define TESTA15 -INFINITY
#define TESTA16 INFINITY
#define TESTA17 9.0
#define TESTA18 11.0
#define TESTA19 13.0

#define TESTB0 4.0
#define TESTB1 4.0
#define TESTB2 -4.0
#define TESTB3 -4.0
#define TESTB4 SQRT2
#define TESTB5 SQRT2
#define TESTB6 -SQRT2
#define TESTB7 -SQRT2
#define TESTB8 2.0
#define TESTB9 2.0
#define TESTB10 -2.0
#define TESTB11 -2.0
#define TESTB12 3.0
#define TESTB13 NAN
#define TESTB14 5.0
#define TESTB15 7.0
#define TESTB16 INFINITY
#define TESTB17 INFINITY
#define TESTB18 -INFINITY
#define TESTB19 0

#define ANSW0 PI_4
#define ANSW1 -PI_4
#define ANSW2 -PI_4
#define ANSW3 PI_4
#define ANSW4 SQRT1_2
#define ANSW5 -SQRT1_2
#define ANSW6 -SQRT1_2
#define ANSW7 SQRT1_2
#define ANSW8_FLT 16777216
#define ANSW8_DBL 9007199254740992
#define ANSW9 -ANSW8
#define ANSW10 -ANSW8
#define ANSW11 ANSW8
#define ANSW12 NAN
#define ANSW13 NAN
#define ANSW14 INFINITY
#define ANSW15 -INFINITY
#define ANSW16 NAN
#define ANSW17 0
#define ANSW18 0
#define ANSW19 INFINITY

#define CONCAT(a, b) a##b
#define CONCAT1(a, b) CONCAT (a, b)
#define REG_INFEX64 _
#define REG_INFEX128 q_
#define REG_INFEX(reg_len) REG_INFEX##reg_len
#define POSTFIX(reg_len, data_len) \
  CONCAT1 (REG_INFEX (reg_len), f##data_len)

#define DATA_TYPE_32 float
#define DATA_TYPE_64 double
#define DATA_TYPE(data_len) DATA_TYPE_##data_len

#define EPSILON_32 __FLT_EPSILON__
#define EPSILON_64 __DBL_EPSILON__
#define EPSILON(data_len) EPSILON_##data_len

#define LOAD_INST(reg_len, data_len) \
  CONCAT1 (vld1, POSTFIX (reg_len, data_len))
#define DIV_INST(reg_len, data_len) \
  CONCAT1 (vdiv, POSTFIX (reg_len, data_len))

#define ABS(a) __builtin_fabs (a)
#define ISNAN(a) __builtin_isnan (a)
#define FP_equals(a, b, epsilon)			\
  (							\
   ((a) == (b))						\
    || (ISNAN (a) && ISNAN (b))				\
    || (ABS (a - b) < epsilon)				\
  )

#define INHIB_OPTIMIZATION asm volatile ("" : : : "memory")

#define RUN_TEST(a, b, c, testseta, testsetb, answset, count,		\
		 reg_len, data_len, n)					\
{									\
  int i;								\
  INHIB_OPTIMIZATION;							\
  (a) = LOAD_INST (reg_len, data_len) (testseta[count]);		\
  (b) = LOAD_INST (reg_len, data_len) (testsetb[count]);		\
  (c) = LOAD_INST (reg_len, data_len) (answset[count]);			\
  INHIB_OPTIMIZATION;							\
  (a) = DIV_INST (reg_len, data_len) (a, b);				\
  for (i = 0; i < n; i++)						\
  {									\
    INHIB_OPTIMIZATION;							\
    if (!FP_equals ((a) [i], (c) [i], EPSILON (data_len)))		\
      return 1;								\
  }									\
}

extern void abort (void);

#define TESTA8 TESTA8_FLT
#define ANSW8 ANSW8_FLT
#define INFINITY FLT_INFINITY

int
test_vdiv_f32 ()
{
  int count;
  float32x2_t a;
  float32x2_t b;
  float32x2_t c;

  float32_t testseta[10][2] = {
    { TESTA0, TESTA1 }, { TESTA2, TESTA3 },
    { TESTA4, TESTA5 }, { TESTA6, TESTA7 },
    { TESTA8, TESTA9 }, { TESTA10, TESTA11 },
    { TESTA12, TESTA13 }, { TESTA14, TESTA15 },
    { TESTA16, TESTA17 }, { TESTA18, TESTA19 }
  };

  float32_t testsetb[10][2] = {
    { TESTB0, TESTB1 }, { TESTB2, TESTB3 },
    { TESTB4, TESTB5 }, { TESTB6, TESTB7 },
    { TESTB8, TESTB9 }, { TESTB10, TESTB11 },
    { TESTB12, TESTB13 }, { TESTB14, TESTB15 },
    { TESTB16, TESTB17 }, { TESTB18, TESTB19 }
  };

  float32_t answset[10][2] = {
    { ANSW0, ANSW1 }, { ANSW2, ANSW3 },
    { ANSW4, ANSW5 }, { ANSW6, ANSW7 },
    { ANSW8, ANSW9 }, { ANSW10, ANSW11 },
    { ANSW12, ANSW13 }, { ANSW14, ANSW15 },
    { ANSW16, ANSW17 }, { ANSW18, ANSW19 }
  };

  for (count = 0; count < 10; count++)
    {
      RUN_TEST (a, b, c, testseta, testsetb, answset, count, 64, 32, 2);
    }

  return 0;
}

/* { dg-final { scan-assembler-times "fdiv\\tv\[0-9\]+\.2s, v\[0-9\]+\.2s, v\[0-9\]+\.2s" 1 } } */

#undef TESTA8
#undef ANSW8
#undef INFINITY

#define TESTA8 TESTA8_DBL
#define ANSW8 ANSW8_DBL
#define INFINITY DBL_INFINITY

int
test_vdiv_f64 ()
{
  int count;
  float64x1_t a;
  float64x1_t b;
  float64x1_t c;

  float64_t testseta[20][1] = {
    { TESTA0 }, { TESTA1 }, { TESTA2 }, { TESTA3 },
    { TESTA4 }, { TESTA5 }, { TESTA6 }, { TESTA7 },
    { TESTA8 }, { TESTA9 }, { TESTA10 }, { TESTA11 },
    { TESTA12 }, { TESTA13 }, { TESTA14 }, { TESTA15 },
    { TESTA16 }, { TESTA17 }, { TESTA18 }, { TESTA19 }
  };

  float64_t testsetb[20][1] = {
    { TESTB0 }, { TESTB1 }, { TESTB2 }, { TESTB3 },
    { TESTB4 }, { TESTB5 }, { TESTB6 }, { TESTB7 },
    { TESTB8 }, { TESTB9 }, { TESTB10 }, { TESTB11 },
    { TESTB12 }, { TESTB13 }, { TESTB14 }, { TESTB15 },
    { TESTB16 }, { TESTB17 }, { TESTB18 }, { TESTB19 }
  };

  float64_t answset[20][1] = {
    { ANSW0 }, { ANSW1 }, { ANSW2 }, { ANSW3 },
    { ANSW4 }, { ANSW5 }, { ANSW6 }, { ANSW7 },
    { ANSW8 }, { ANSW9 }, { ANSW10 }, { ANSW11 },
    { ANSW12 }, { ANSW13 }, { ANSW14 }, { ANSW15 },
    { ANSW16 }, { ANSW17 }, { ANSW18 }, { ANSW19 }
  };

  for (count = 0; count < 20; count++)
    {
      RUN_TEST (a, b, c, testseta, testsetb, answset, count, 64, 64, 1);
    }
  return 0;
}

/* { dg-final { scan-assembler-times "fdiv\\td\[0-9\]+, d\[0-9\]+, d\[0-9\]+" 1 } } */

#undef TESTA8
#undef ANSW8
#undef INFINITY

#define TESTA8 TESTA8_FLT
#define ANSW8 ANSW8_FLT
#define INFINITY FLT_INFINITY

int
test_vdivq_f32 ()
{
  int count;
  float32x4_t a;
  float32x4_t b;
  float32x4_t c;

  float32_t testseta[5][4] = {
    { TESTA0, TESTA1, TESTA2, TESTA3 },
    { TESTA4, TESTA5, TESTA6, TESTA7 },
    { TESTA8, TESTA9, TESTA10, TESTA11 },
    { TESTA12, TESTA13, TESTA14, TESTA15 },
    { TESTA16, TESTA17, TESTA18, TESTA19 }
  };

  float32_t testsetb[5][4] = {
    { TESTB0, TESTB1, TESTB2, TESTB3 },
    { TESTB4, TESTB5, TESTB6, TESTB7 },
    { TESTB8, TESTB9, TESTB10, TESTB11 },
    { TESTB12, TESTB13, TESTB14, TESTB15 },
    { TESTB16, TESTB17, TESTB18, TESTB19 }
  };

  float32_t answset[5][4] = {
    { ANSW0, ANSW1, ANSW2, ANSW3 },
    { ANSW4, ANSW5, ANSW6, ANSW7 },
    { ANSW8, ANSW9, ANSW10, ANSW11 },
    { ANSW12, ANSW13, ANSW14, ANSW15 },
    { ANSW16, ANSW17, ANSW18, ANSW19 }
  };

  for (count = 0; count < 5; count++)
    {
      RUN_TEST (a, b, c, testseta, testsetb, answset, count, 128, 32, 4);
    }
  return 0;
}

/* { dg-final { scan-assembler-times "fdiv\\tv\[0-9\]+\.4s, v\[0-9\]+\.4s, v\[0-9\]+\.4s" 1 } } */

#undef TESTA8
#undef ANSW8
#undef INFINITY

#define TESTA8 TESTA8_DBL
#define ANSW8 ANSW8_DBL
#define INFINITY DBL_INFINITY

int
test_vdivq_f64 ()
{
  int count;
  float64x2_t a;
  float64x2_t b;
  float64x2_t c;

  float64_t testseta[10][2] = {
    { TESTA0, TESTA1 }, { TESTA2, TESTA3 },
    { TESTA4, TESTA5 }, { TESTA6, TESTA7 },
    { TESTA8, TESTA9 }, { TESTA10, TESTA11 },
    { TESTA12, TESTA13 }, { TESTA14, TESTA15 },
    { TESTA16, TESTA17 }, { TESTA18, TESTA19 }
  };

  float64_t testsetb[10][2] = {
    { TESTB0, TESTB1 }, { TESTB2, TESTB3 },
    { TESTB4, TESTB5 }, { TESTB6, TESTB7 },
    { TESTB8, TESTB9 }, { TESTB10, TESTB11 },
    { TESTB12, TESTB13 }, { TESTB14, TESTB15 },
    { TESTB16, TESTB17 }, { TESTB18, TESTB19 }
  };

  float64_t answset[10][2] = {
    { ANSW0, ANSW1 }, { ANSW2, ANSW3 },
    { ANSW4, ANSW5 }, { ANSW6, ANSW7 },
    { ANSW8, ANSW9 }, { ANSW10, ANSW11 },
    { ANSW12, ANSW13 }, { ANSW14, ANSW15 },
    { ANSW16, ANSW17 }, { ANSW18, ANSW19 }
  };

  for (count = 0; count < 10; count++)
    {
      RUN_TEST (a, b, c, testseta, testsetb, answset, count, 128, 64, 2);
    }

  return 0;
}

/* { dg-final { scan-assembler-times "fdiv\\tv\[0-9\]+\.2d, v\[0-9\]+\.2d, v\[0-9\]+\.2d" 1 } } */

int
main (int argc, char **argv)
{
  if (test_vdiv_f32 ())
    abort ();

  if (test_vdiv_f64 ())
    abort ();

  if (test_vdivq_f32 ())
    abort ();

  if (test_vdivq_f64 ())
    abort ();

  return 0;
}

