//
// arch/x86_64/rsp/vmul.h
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//

//
// TODO: CHECK ME.
//

static inline __m128i rsp_vmulf_vmulu(uint32_t iw, __m128i vs, __m128i vt,
  __m128i zero, __m128i *acc_lo, __m128i *acc_md, __m128i *acc_hi) {
  __m128i lo, hi, round, sign1, sign2, eq, neq, neg;

  lo = _mm_mullo_epi16(vs, vt);
  round = _mm_cmpeq_epi16(zero, zero);
  sign1 = _mm_srli_epi16(lo, 15);
  lo = _mm_add_epi16(lo, lo);
  round = _mm_slli_epi16(round, 15);
  hi = _mm_mulhi_epi16(vs, vt);
  sign2 = _mm_srli_epi16(lo, 15);
  *acc_lo = _mm_add_epi16(round, lo);
  sign1 = _mm_add_epi16(sign1, sign2);

  hi = _mm_slli_epi16(hi, 1);
  neq = eq = _mm_cmpeq_epi16(vs, vt);
  *acc_md = _mm_add_epi16(hi, sign1);

  neg = _mm_srai_epi16(*acc_md, 15);

  // VMULU
  if (iw & 0x1) {
    *acc_hi = _mm_andnot_si128(eq, neg);
    hi =_mm_or_si128(*acc_md, neg);
    return _mm_andnot_si128(*acc_hi, hi);
  }

  // VMULF
  else {
    eq = _mm_and_si128(eq, neg);
    *acc_hi = _mm_andnot_si128(neq, neg);
    return _mm_add_epi16(*acc_md, eq);
  }
}

