#include "zmult.h"

#define reg register double /* XXX: long double */

#define timestwok(u,twok,pm4,pm5,pm6) \
  t3 = twok; \
  t0 = 0[u]; \
  t0 *= t3; \
  t7 = zmult_alpha48; \
  t4 = t7; \
  t1 = 1[u]; \
  t1 *= t3; \
  t2 = 2[u]; \
  t2 *= t3; \
  t3 *= 3[u]; \
  t4 += t0; \
  t4 -= t7; \
  t0 -= t4; \
  t5 = t7; \
  t5 += t1; \
  t5 -= t7; \
  t1 -= t5; \
  t6 = t7; \
  t6 += t2; \
  t6 -= t7; \
  t2 -= t6; \
  t7 += t3; \
  t7 -= zmult_alpha48; \
  t4 *= pm4; \
  t5 *= pm5; \
  t6 *= pm6; \
  t3 -= t7; \
  t7 *= zmult_twom48;

#define rotate(u,twok) \
  timestwok(u,twok,zmult_twom48,zmult_twom48,zmult_twom48); \
  t1 += t4; \
  1[u] = t1; \
  t2 += t5; \
  2[u] = t2; \
  t3 += t6; \
  3[u] = t3; \
  t0 -= t7; \
  0[u] = t0;

#define rotate_minus48(u,twok) \
  timestwok(u,twok,zmult_twom48,zmult_twom48,zmult_twom48); \
  t1 += t4; \
  0[u] = t1; \
  t2 += t5; \
  1[u] = t2; \
  t3 += t6; \
  2[u] = t3; \
  t0 = t7 - t0; \
  3[u] = t0;

#define rotate_plus48(u,twok) \
  timestwok(u,twok,zmult_twom48,zmult_twom48,zmult_minustwom48); \
  t1 += t4; \
  2[u] = t1; \
  t2 += t5; \
  3[u] = t2; \
  t3 = t6 - t3; \
  0[u] = t3; \
  t0 -= t7; \
  1[u] = t0;

#define rotate_minus96(u,twok) \
  timestwok(u,twok,zmult_minustwom48,zmult_twom48,zmult_twom48); \
  t1 = t4 - t1; \
  3[u] = t1; \
  t2 += t5; \
  0[u] = t2; \
  t3 += t6; \
  1[u] = t3; \
  t0 = t7 - t0; \
  2[u] = t0;

#define rotate_plus96(u,twok) \
  timestwok(u,twok,zmult_twom48,zmult_minustwom48,zmult_minustwom48); \
  t1 += t4; \
  3[u] = t1; \
  t2 = t5 - t2; \
  0[u] = t2; \
  t3 = t6 - t3; \
  1[u] = t3; \
  t0 -= t7; \
  2[u] = t0;

#define rotate_minus144(u,twok) \
  timestwok(u,twok,zmult_minustwom48,zmult_minustwom48,zmult_twom48); \
  t1 = t4 - t1; \
  2[u] = t1; \
  t2 = t5 - t2; \
  3[u] = t2; \
  t3 += t6; \
  0[u] = t3; \
  t0 = t7 - t0; \
  1[u] = t0;

#define rotate_0(u) \
  t4 = zmult_alpha48; \
  t0 = 0[u]; \
  t1 = 1[u]; \
  t2 = 2[u]; \
  t3 = 3[u]; \
  t7 = t4; \
  t4 += t0; \
  t4 -= t7; \
  t0 -= t4; \
  t5 = zmult_alpha48; \
  t5 += t1; \
  t5 -= t7; \
  t1 -= t5; \
  t6 = zmult_alpha48; \
  t6 += t2; \
  t6 -= t7; \
  t2 -= t6; \
  t7 += t3; \
  t7 -= zmult_alpha48; \
  t3 -= t7; \
  t4 *= zmult_twom48; \
  t1 += t4; \
  1[u] = t1; \
  t5 *= zmult_twom48; \
  t2 += t5; \
  2[u] = t2; \
  t6 *= zmult_twom48; \
  t3 += t6; \
  3[u] = t3; \
  t7 *= zmult_twom48; \
  t0 -= t7; \
  0[u] = t0;

#define rotate_12(u) rotate(u,zmult_two3[4])
#define rotate_24(u) rotate(u,zmult_two3[8])
#define rotate_36(u) rotate(u,zmult_two3[12])
#define rotate_48(u) rotate_plus48(u,zmult_two3[0])
#define rotate_60(u) rotate_plus48(u,zmult_two3[4])
#define rotate_72(u) rotate_plus48(u,zmult_two3[8])
#define rotate_84(u) rotate_plus48(u,zmult_two3[12])
#define rotate_un0(u) rotate_0(u)
#define rotate_un12(u) rotate_minus48(u,zmult_two3[12])
#define rotate_un24(u) rotate_minus48(u,zmult_two3[8])
#define rotate_un36(u) rotate_minus48(u,zmult_two3[4])
#define rotate_un48(u) rotate_minus48(u,zmult_two3[0])
#define rotate_un60(u) rotate_minus96(u,zmult_two3[12])
#define rotate_un72(u) rotate_minus96(u,zmult_two3[8])
#define rotate_un84(u) rotate_minus96(u,zmult_two3[4])
#define rotate_un4(u) rotate_minus48(u,zmult_two44)

void zmult_4fft_twist_12(double u[32])
{
  reg t0, t1, t2, t3, t4, t5, t6, t7;
  rotate_0(u);
  rotate_12(u + 4);
  rotate_24(u + 8);
  rotate_36(u + 12);
  rotate_48(u + 16);
  rotate_60(u + 20);
  rotate_72(u + 24);
  rotate_84(u + 28);
}

void zmult_4fft_untwist_12(double u[32])
{
  reg t0, t1, t2, t3, t4, t5, t6, t7;
  rotate_un0(u);
  rotate_un12(u + 4);
  rotate_un24(u + 8);
  rotate_un36(u + 12);
  rotate_un48(u + 16);
  rotate_un60(u + 20);
  rotate_un72(u + 24);
  rotate_un84(u + 28);
}

void zmult_4fft_16_carry(double u[64])
{
  reg t0, t1, t2, t3, t4, t5, t6, t7;
  int i;
  i = 8;
  do {
    rotate_0(u);
    rotate_0(u + 4);
    u += 8;
  } while (--i);
}

void zmult_4fft_16_scale(double u[64])
{
  reg t0, t1, t2, t3, t4, t5, t6, t7;
  int i;
  i = 8;
  do {
    rotate_un4(u);
    rotate_un4(u + 4);
    u += 8;
  } while (--i);
}
