//	Roast+ License

//	SIMD

#ifndef __SFJP_OPENMGL_roast_simd_core_HPP__
#define __SFJP_OPENMGL_roast_simd_core_HPP__

#include <stdio.h>
#include <memory.h>
#include "roast_pp.h"

#include <nmmintrin.h>   // MMX-SSE4.2命令セットを使用する場合インクルード //
#include <smmintrin.h>   // MMX-SSE4.1命令セットを使用する場合インクルード //
#include <intrin.h>      // MMX-SSE3命令セットを使用する場合インクルード   //
#include <emmintrin.h>   // MMX-SSE2命令セットを使用する場合インクルード   //
#include <xmmintrin.h>   // MMX-SSE命令セットを使用する場合インクルード    //
#include <mmintrin.h>    // MMX命令セットを使用する場合インクルード        //


//#define _ROAST_SIMD__ENABLE_FAST_INLINE

#define _ROAST_SIMD_XMM_MAX		(15)
#define _ROAST_SIMD_XMM_MAX_	(15)


#define _ROAST_SIMD__ALIGN_16				__declspec(align(16))
#define _ROAST_SIMD__ALIGN_16_FLOAT			_ROAST_SIMD__ALIGN_16 float
#define _ROAST_SIMD__ALIGN_16_CFLOAT		_ROAST_SIMD__ALIGN_16 const float
#define _ROAST_SIMD__ALIGN_16_CONST_FLOAT	_ROAST_SIMD__ALIGN_16_CFLOAT
#define _ROAST_SIMD__ALIGN_16_PVOID			void*
#define _ROAST_SIMD__NOAL_PDOUBLE			double*



/*	SSE Memory Type (128bit)	*/
typedef union
	__declspec(intrin_type)	//	__declspec(intrin_type)って何だろ？（調べてみたが”謎”らしい
	_ROAST_SIMD__ALIGN_16
{
	float               float_x4[4];

	__int8              char_x16[16];
	__int16             short_x8[8];
	__int32             int_x4[4];
	__int64             int64_x2[2];
	__int64             longlong_x2[2];
	unsigned __int8     byte_x16[16];
	unsigned __int16    ushort_x8[8];
	unsigned __int32    uint_x4[4];
	unsigned __int64    uint64_x2[2];
	unsigned __int64    ulonglong_x2[2];

	////////////////////////////////////////////

	float               f_x4[4];

	__int8              c_x16[16];
	__int16             s_x8[8];
	__int32             i_x4[4];
	__int64             i64_x2[2];
	__int64             ll_x2[2];
	unsigned __int8     b_x16[16];
	unsigned __int16    us_x8[8];
	unsigned __int32    ui_x4[4];
	unsigned __int64    ui64_x2[2];
	unsigned __int64    ull_x2[2];

	////////////////////////////////////////////

	float               f32[4];
	unsigned __int64    u64[2];
	__int8              i8[16];
	__int16             i16[8];
	__int32             i32[4];
	__int64             i64[2];
	unsigned __int8     u8[16];
	unsigned __int16    u16[8];
	unsigned __int32    u32[4];
/*
	float               m128_f32[4];
	unsigned __int64    m128_u64[2];
	__int8              m128_i8[16];
	__int16             m128_i16[8];
	__int32             m128_i32[4];
	__int64             m128_i64[2];
	unsigned __int8     m128_u8[16];
	unsigned __int16    m128_u16[8];
	unsigned __int32    m128_u32[4];
*/
} ROAST_SIMD_M128;



/* ********** Mnemonics ********************** */

/*	Move Mnemonics  */
#define ROAST_SIMD__MOVAPS(XMM_NUM,AL16FARY)		__asm movaps xmm ## XMM_NUM, xmmword ptr [AL16FARY]
#define ROAST_SIMD__MOVAPS_MX(AL16FARY,XMM_NUM)		__asm movaps [AL16FARY], xmm ## XMM_NUM

#define ROAST_SIMD__MOVDQA(TO_XMM_NUM,FROM)			__asm movdqa xmm ## TO_XMM_NUM, FROM
#define ROAST_SIMD__MOVUPD(TO_XMM_NUM,FROM)			__asm movupd xmm ## TO_XMM_NUM, FROM

/*	Calculation Mnemonics  */
//#define ROAST_SIMD__MULPS_XM(XMM_NUM,M128VAL)		 __asm mulps xmm ## XMM_NUM, xmmword ptr [M128VAL]
#define ROAST_SIMD__MULPS_XM(TO_XMM_NUM, FROM_M128VAL)		__asm mulps xmm ## TO_XMM_NUM, FROM_M128VAL
#define ROAST_SIMD__MULPS   (TO_XMM_NUM, FROM_M128VAL)		ROAST_SIMD__MULPS_XM(TO_XMM_NUM, FROM_M128VAL)

#define ROAST_SIMD__MULPS_XX(TO_XMM_NUM, FROM_XMM_NUM)		__asm mulps xmm ## TO_XMM_NUM, xmm ## FROM_XMM_NUM




/* ######### Internal ########## */

//#	define ROAST_SIMD_CLASS_OR_NS				class
#	define ROAST_SIMD_CLASS_OR_NS				namespace
#	define ROAST_SIMD_STATIC
#	define ROAST_SIMD_2ND_NAMESPACE_START(X)	ROAST_SIMD_CLASS_OR_NS X {
#	define ROAST_SIMD_2ND_NAMESPACE_END			}
//#	define ROAST_SIMD_2ND_NAMESPACE_START(X)
//#	define ROAST_SIMD_2ND_NAMESPACE_END

/* Internal End. */



//////////////////////////////////////////////////////////////////////////////////////////////////////

/*	namespace roast	*/
namespace roast{

	/*	namespace simd	*/
	ROAST_SIMD_CLASS_OR_NS simd
	{

		//	########  Definitations  ####################

		//typedef ROAST_SIMD_M128 m128;	/*	SSE Memory Type (128bit)	*/
		typedef ROAST_SIMD_M128 m128;	/*	SSE Memory Type (128bit)	*/

		typedef __m128 _ROAST_SIMD_USE_M128;


		//////////////////////////////////////////////////////////////////


		//	########  MMX  ####################

		/*	あまりまともに実装する気はないです・・・	*/




		//	########  SSE  ####################
		ROAST_SIMD_2ND_NAMESPACE_START(sse)



/******************************************************************/


/*	=========================================================
	movaps
	4つの境界調整済みfloat配列をXMMx（x＝xmm_num）に格納する	*/

#define ___ROAST_SIMD__NEMONI__			movaps

//	xmm <= float*
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		const float*
#define ___ROAST_SIMD__VAL_NAME_		f_array_4
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__xmm_m128"

//	xmm <= __m128
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		_ROAST_SIMD_USE_M128
#define ___ROAST_SIMD__VAL_NAME_		m128val
#include "simd_core__xmm_m128"

//	float* <= xmm
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		float*
#define ___ROAST_SIMD__VAL_NAME_		f_array_4
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__m128_xmm"

//	__m128& <= xmm
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		__m128&
#define ___ROAST_SIMD__VAL_NAME_		m128val
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__m128_xmm"

//	(get) __m128 <= xmm
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		__m128
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__m128_xmm_get"

//	xmm <= xmm
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#include "simd_core__xmm_xmm"


/*	=========================================================
	movaps
	4つの境界調整されていないfloat配列をXMMx（x＝xmm_num）に格納する	*/


#undef ___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__NEMONI__			movups

//	xmm <= float*
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		const float*
#define ___ROAST_SIMD__VAL_NAME_		f_array_4
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__xmm_m128"

//	xmm <= __m128
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		_ROAST_SIMD_USE_M128
#define ___ROAST_SIMD__VAL_NAME_		m128val
#include "simd_core__xmm_m128"

//	float* <= xmm
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		float*
#define ___ROAST_SIMD__VAL_NAME_		f_array_4
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__m128_xmm"

//	__m128& <= xmm
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		__m128&
#define ___ROAST_SIMD__VAL_NAME_		m128val
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__m128_xmm"

//	(get) __m128 <= xmm
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		__m128
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__m128_xmm_get"

//	xmm <= xmm
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#include "simd_core__xmm_xmm"



/*
///// SSE /////


MOVAPS
  xmm1, xmm2/m128
  xmm2/m128, xmm1
  4つのパックド単精度浮動小数点値をXMMレジスタ同士の間、またはXMMレジスタとアライメントの合ったメモリとの間で転送

MOVUPS
  xmm1, xmm2/m128
  xmm2/m128, xmm1
  4つのパックド単精度浮動小数点値をXMMレジスタ同士の間、またはXMMレジスタとアライメントの合っていないメモリとの間で転送 SSE 

MOVHLPS
  xmm1, xmm2
  2つのパックド単精度浮動小数点値をXMMレジスタの上位クワッドワードから別のXMMレジスタの下位クワッドワードに転送 SSE 

MOVLHPS
  xmm1, xmm2
  2つのパックド単精度浮動小数点値をXMMレジスタの下位クワッドワードから別のXMMレジスタの上位クワッドワードに転送 SSE 

MOVHPS
  xmm, m64
  m64, xmm
  2つのパックド単精度浮動小数点値をXMMレジスタの上位クワッドワードとメモリとの間で転送 SSE 

MOVLPS
  xmm, m64
  m64, xmm
  2つのパックド単精度浮動小数点値をXMMレジスタの下位クワッドワードとメモリとの間で転送 SSE 

MOVSS
  xmm1, xmm2/m32
  xmm2/m32, xmm
  スカラ単精度浮動小数点値をXMMレジスタ同士の間、またはXMMレジスタとメモリとの間で転送 SSE 

MOVMSKPS
  r32, xmm
  4つのパックド単精度浮動小数点値から符号マスクを抽出し汎用レジスタに転送 SSE 

PMOVMSKB
  r32, mm
  r32, xmm
  SIMDレジスタのバイトマスクを汎用レジスタに転送 SSE 
*/


/******************************************************************/

		/*	4つのfloat配列をXMMx（x＝xmm_num）に格納する	*/
#define ___ROAST_SIMD__NEMONI_			mulps
#define ___ROAST_SIMD__VAL_TYPE_		const float*
#define ___ROAST_SIMD__VAL_NAME_		f_array_4
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__xmm_m128"

#define ___ROAST_SIMD__NEMONI_			mulps
#define ___ROAST_SIMD__VAL_TYPE_		_ROAST_SIMD_USE_M128
#define ___ROAST_SIMD__VAL_NAME_		m128val
#include "simd_core__xmm_m128"



		/*	無理・・・か・・・
		template <int xmm_n1, int xmm_n2>
			inline void mulps_2()
		{
			ROAST_SIMD__MULPS_XX(xmm_n1, xmm_n2);
		}
		*/


		//	########  SSE2  ####################
		ROAST_SIMD_2ND_NAMESPACE_END
		ROAST_SIMD_2ND_NAMESPACE_START(sse2)



#undef ___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__NEMONI__			movups

//	xmm <= float*
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		const float*
#define ___ROAST_SIMD__VAL_NAME_		f_array_4
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__xmm_m128"

//	xmm <= __m128
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		_ROAST_SIMD_USE_M128
#define ___ROAST_SIMD__VAL_NAME_		m128val
#include "simd_core__xmm_m128"

//	float* <= xmm
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		float*
#define ___ROAST_SIMD__VAL_NAME_		f_array_4
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__m128_xmm"

//	__m128& <= xmm
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		__m128&
#define ___ROAST_SIMD__VAL_NAME_		m128val
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__m128_xmm"

//	(get) __m128 <= xmm
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#define ___ROAST_SIMD__VAL_TYPE_		__m128
#define ___ROAST_SIMD__VAL_IS_POINTER	
#include "simd_core__m128_xmm_get"

//	xmm <= xmm
#define ___ROAST_SIMD__NEMONI_			___ROAST_SIMD__NEMONI__
#include "simd_core__xmm_xmm"

		
/*
///// SSE2 /////

MOVAPD
  xmm1, xmm2/m128
  xmm2/m128, xmm1
  2つのパックド倍精度浮動小数点値をXMMレジスタ同士の間、またはXMMレジスタとアライメントの合ったメモリとの間で転送 SSE2 

MOVUPD
  xmm1, xmm2/m128
  xmm2/m128, xmm1
  2つのパックド倍精度浮動小数点値をXMMレジスタ同士の間、またはXMMレジスタとアライメントの合っていないメモリとの間で転送 SSE2 

MOVDQA
  xmm1, xmm2/m128
  xmm2/m128, xmm1
  アライメントの合ったダブルクワッドワードを転送 SSE2 

MOVDQU
  xmm1, xmm2/m128
  xmm2/m128, xmm1
  アライメントの合っていないダブルクワッドワードを転送 SSE2 

MOVHPD
  xmm, m64
  m64, xmm
  上位パックド倍精度浮動小数点値をXMMレジスタの上位クワッドワードとメモリとの間で転送 SSE2 

MOVLPD
  xmm, m64
  m64, xmm
  下位パックド倍精度浮動小数点値をXMMレジスタの下位クワッドワードとメモリとの間で転送 SSE2 

MOVDQ2Q
  mm, xmm
  XMMレジスタの下位のクワッドワードをMMXレジスタに転送 SSE2 

MOVQ2DQ
  xmm, mm
  MMXレジスタからXMMレジスタの下位のクワッドワードに転送 SSE2 

MOVSD
  xmm1, xmm2/m64
  xmm2/m64, xmm
  スカラ倍精度浮動小数点値をXMMレジスタ同士の間、またはXMMレジスタとメモリとの間で転送 SSE2 

MOVMSKPD
  r32, xmm
  2つのパックド倍精度浮動小数点値から符号マスクを抽出し汎用レジスタに転送 SSE2 
*/

		/*	アライメントの合ったダブルクワッドワードを転送	*/
		inline ROAST_SIMD_STATIC void movdqa(int xmm_num, _ROAST_SIMD__ALIGN_16_PVOID p)
		{
			switch( xmm_num )
			{
			case 1: ROAST_SIMD__MOVDQA(1, p);
				break;
			case 2: ROAST_SIMD__MOVDQA(2, p);
				break;
			case 3: ROAST_SIMD__MOVDQA(3, p);
				break;
			case 4: ROAST_SIMD__MOVDQA(4, p);
				break;
			}
		}


		/*	2つのパックド倍精度浮動小数点値をXMMレジスタ同士の間、またはXMMレジスタと
			アライメントの合っていないメモリとの間で転送	*/
		inline ROAST_SIMD_STATIC void movupd(int xmm_num, _ROAST_SIMD__NOAL_PDOUBLE p_double)
		{
			switch( xmm_num )
			{
			case 1: ROAST_SIMD__MOVUPD(1, p_double);
				break;
			case 2: ROAST_SIMD__MOVUPD(2, p_double);
				break;
			case 3: ROAST_SIMD__MOVUPD(3, p_double);
				break;
			case 4: ROAST_SIMD__MOVUPD(4, p_double);
				break;
			}
		}

		//	########  SSE3  ####################
		ROAST_SIMD_2ND_NAMESPACE_END
		ROAST_SIMD_2ND_NAMESPACE_START(sse3)



		//	########  SSE4  ####################
		ROAST_SIMD_2ND_NAMESPACE_END
		ROAST_SIMD_2ND_NAMESPACE_START(sse4)



		/*
		//	########  SSE4.1  ####################
		ROAST_SIMD_2ND_NAMESPACE_END
		ROAST_SIMD_2ND_NAMESPACE_START(sse41)

		ROAST_SIMD_2ND_NAMESPACE_END
		*/


		//	########  SSE4.2  ####################
		ROAST_SIMD_2ND_NAMESPACE_END
		ROAST_SIMD_2ND_NAMESPACE_START(sse42)



		ROAST_SIMD_2ND_NAMESPACE_END
	};
}

#endif//__SFJP_OPENMGL_roast_simd_core_HPP__
