/* Copyright (c) 2018 ZAO "MCST". All rights reserved. */

#if !defined _X86INTRIN_H_INCLUDED && !defined _IMMINTRIN_H_INCLUDED
# error "Never use <bmi2intrin.h> directly; include <x86intrin.h> instead."
#endif

#ifndef _BMI2INTRIN_H_INCLUDED
#define _BMI2INTRIN_H_INCLUDED

#ifdef __BMI2__

/* Define the default attributes for the functions in this file */
#define __DEFAULT_FUNCS_ATTRS __attribute__((/*__gnu_inline__,*/ __always_inline__, __artificial__))

__E2K_INLINE unsigned int __DEFAULT_FUNCS_ATTRS
_bzhi_u32 (unsigned int __X, unsigned int __Y)
{
  return __builtin_ia32_bzhi_si (__X, __Y);
}

__E2K_INLINE unsigned int __DEFAULT_FUNCS_ATTRS
_pdep_u32 (unsigned int __X, unsigned int __Y)
{
  return __builtin_ia32_pdep_si (__X, __Y);
}

__E2K_INLINE unsigned int __DEFAULT_FUNCS_ATTRS
_pext_u32 (unsigned int __X, unsigned int __Y)
{
  return __builtin_ia32_pext_si (__X, __Y);
}

__E2K_INLINE unsigned long long __DEFAULT_FUNCS_ATTRS
_bzhi_u64 (unsigned long long __X, unsigned long long __Y)
{
  return __builtin_ia32_bzhi_di (__X, __Y);
}

__E2K_INLINE unsigned long long __DEFAULT_FUNCS_ATTRS
_pdep_u64 (unsigned long long __X, unsigned long long __Y)
{
  return __builtin_ia32_pdep_di (__X, __Y);
}

__E2K_INLINE unsigned long long __DEFAULT_FUNCS_ATTRS
_pext_u64 (unsigned long long __X, unsigned long long __Y)
{
  return __builtin_ia32_pext_di (__X, __Y);
}

__E2K_INLINE unsigned long long __DEFAULT_FUNCS_ATTRS
_mulx_u64 (unsigned long long __X, unsigned long long __Y,
           unsigned long long *__P)
{
#if __iset__ >= 3
  *__P = __builtin_e2k_umulhd (__X, __Y);
#else /* __iset__ >= 3 */
  unsigned long long __xl = __X & 0xffffffff;
  unsigned long long __xh = __X >> 32;
  unsigned long long __yl = __Y & 0xffffffff;
  unsigned long long __yh = __Y >> 32;
  unsigned long long __x0 = __xl * __yl;
  unsigned long long __x1 = __xl * __yh;
  unsigned long long __x2 = __xh * __yl;
  unsigned long long __x3 = __xh * __yh;
  __x1 += __x0 >> 32;
  __x1 += __x2;
  if (__x1 < __x2)
    __x3 += 0x80000000;
  *__P = __x3 + (__x1 >> 32);
#endif /* __iset__ >= 3 */
  return __X * __Y;
}

__E2K_INLINE unsigned int __DEFAULT_FUNCS_ATTRS
_mulx_u32 (unsigned int __X, unsigned int __Y, unsigned int *__P)
{
  unsigned long long __res = __builtin_e2k_umulx (__X, __Y);
  *__P = (unsigned int) (__res >> 32);
  return (unsigned int) __res;
}

#undef __DEFAULT_FUNCS_ATTRS

#endif /* __BMI2__ */

#endif /* _BMI2INTRIN_H_INCLUDED */
