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

#ifndef _WMMINTRIN_H_INCLUDED
#define _WMMINTRIN_H_INCLUDED

/* We need definitions from the SSE2 header file.  */
#include <emmintrin.h>

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

#if !defined (__AES__) && !defined (__PCLMUL__)
# error "AES/PCLMUL instructions not enabled"
#else

/* AES */

#ifdef __AES__
/* Performs 1 round of AES decryption of the first m128i using
   the second m128i as a round key.  */
__E2K_INLINE __m128i __DEFAULT_FUNCS_ATTRS
_mm_aesdec_si128 (__m128i __X, __m128i __Y)
{
  return (__m128i) __builtin_ia32_aesdec128 ((__v2di)__X, (__v2di)__Y);
}

/* Performs the last round of AES decryption of the first m128i
   using the second m128i as a round key.  */
__E2K_INLINE __m128i __DEFAULT_FUNCS_ATTRS
_mm_aesdeclast_si128 (__m128i __X, __m128i __Y)
{
  return (__m128i) __builtin_ia32_aesdeclast128 ((__v2di)__X,
						 (__v2di)__Y);
}

/* Performs 1 round of AES encryption of the first m128i using
   the second m128i as a round key.  */
__E2K_INLINE __m128i __DEFAULT_FUNCS_ATTRS
_mm_aesenc_si128 (__m128i __X, __m128i __Y)
{
  return (__m128i) __builtin_ia32_aesenc128 ((__v2di)__X, (__v2di)__Y);
}

/* Performs the last round of AES encryption of the first m128i
   using the second m128i as a round key.  */
__E2K_INLINE __m128i __DEFAULT_FUNCS_ATTRS
_mm_aesenclast_si128 (__m128i __X, __m128i __Y)
{
  return (__m128i) __builtin_ia32_aesenclast128 ((__v2di)__X, (__v2di)__Y);
}

/* Performs the InverseMixColumn operation on the source m128i
   and stores the result into m128i destination.  */
__E2K_INLINE __m128i __DEFAULT_FUNCS_ATTRS
_mm_aesimc_si128 (__m128i __X)
{
  return (__m128i) __builtin_ia32_aesimc128 ((__v2di)__X);
}

/* Generates a m128i round key for the input m128i AES cipher key and
   byte round constant.  The second parameter must be a compile time
   constant.  */
#define _mm_aeskeygenassist_si128(X, C)					\
  ((__m128i) __builtin_ia32_aeskeygenassist128 ((__v2di)(__m128i)(X),	\
						(int)(C)))

#endif  /* __AES__ */

/* PCLMUL */

#ifdef __PCLMUL__
/* Performs carry-less integer multiplication of 64-bit halves of
   128-bit input operands.  The third parameter inducates which 64-bit
   haves of the input parameters v1 and v2 should be used. It must be
   a compile time constant.  */
#define _mm_clmulepi64_si128(X, Y, I)					\
  ((__m128i) __builtin_ia32_pclmulqdq128 ((__v2di)(__m128i)(X),		\
					  (__v2di)(__m128i)(Y), (int)(I)))
#endif  /* __PCLMUL__  */

#endif /* __AES__/__PCLMUL__ */

#undef __DEFAULT_FUNCS_ATTRS

#endif /* _WMMINTRIN_H_INCLUDED */
