智能引入intrinsic函数。支持VC、GCC,兼容Windows、Linux、Mac OS X
http://blog.csdn.net/zyl910/article/details/8011147
现在很多编译器支持intrinsic函数,这给编写SSE等SIMD代码带来了方便。但是各个编译器略有差异,于是我编写了zintrin.h,智能引入intrinsic函数。
一、各种编译器的区别
1.1 Visual C++(Windows)
最早支持intrinsic函数的VC编译器是VC 6.0。它在装上Visual Studio 6.0 Service Pack 5、Visual C++ 6.0 Processor Pack这两个补丁后,便提供了mmintrin.h、mm3dnow.h、xmmintrin.h、emmintrin.h,用于支持MMX、3DNow!、SSE、SSE2的intrinsic函数。 从VC2005开始,提供了intrin.h,用于引入所有的intrinsic函数。 详见—— http://www.cnblogs.com/zyl910/archive/2012/02/28/vs_intrin_table.html Intrinsics头文件与SIMD指令集、Visual Studio版本对应表
如果希望得知当前编译环境是否支持某种intrinsic函数,只能利用_MSC_VER判断VC的版本 来间接确认。 而且实际过程中会发现一些兼容性小问题,例如——VC不支持x64下的MMX指令、VC2008之前没有_mm_cvtss_f32 等。
1.2 GCC(Linux下的GCC、Windows下的MinGW)
gcc也支持intrinsic函数。例如在Fedora 17中,“/usr/lib/gcc/i686-redhat-linux/4.7.0/include/”目录下有Intrinsics头文件。而对于Windows中的MinGW,Intrinsics头文件是在MinGW的“\lib\gcc\mingw32\4.6.2\include”子目录中。 详见—— http://www.cnblogs.com/zyl910/archive/2012/08/27/intrin_table_gcc.html GCC中的Intrinsics头文件与SIMD指令集、宏、参数的对应表
gcc允许通过命令行参数来控制是否打开某种指令集的支持,例如“-mmmx”用于打开MMX支持。可在终端中执行“gcc --target-help”,得到详细的参数列表。
当通过命令行参数打开指令集支持后,gcc会自动定义对应的预处理宏。例如用“-mmmx”打开MMX支持后,gcc会自动定义“__MMX__”这个预定义宏。这一类的预定义宏有—— __MMX__ __3dNOW__ __SSE__ __SSE2__ __SSE3__ __SSSE3__ __SSE4_1__ __SSE4_2__ __SSE4A__ __AES__ __PCLMUL__ __AVX__ __AVX2__ __F16C__ __FMA__ __FMA4__ __XOP__ __LWP__ __RDRND__ __FSGSBASE__ __LZCNT__ __POPCNT__ __BMI__ __BMI2__ __TBM__
gcc用于引入所有x86平台intrinsic函数的头文件是“x86intrin.h”,它会根据那些指令集预定义宏来引入相关的intrinsic函数。例如有“__MMX__”宏时,x86intrin.h会引入MMX的intrinsic函数。
1.3 Mac OS X 中的 llvm-gcc
我在Mac OS X系统中找了很久,貌似它不支持intrinsic函数。详细版本是—— 操作系统:Mac OS X Lion 10.7.4(11E53) 编程工具:Xcode 4.4.1(1448),并装好了它的“Command Line Tools”。
__llvm__这个预定义宏可用来判断是不是llvm-gcc。
二、设计
2.1 思路
不同的编译器引入intrinsic函数的办法—— 对于VS2005之前的版本,只能手动逐个逐个的包含emmintrin.h、mm3dnow.h; 对于VS2005之后的版本,可以利用intrin.h引入所有intrinsic函数; 对于GCC,首先应该判断__llvm__宏来排除llvm-gcc,然后利用x86intrin.h引入所有intrinsic函数。
这样做太麻烦了,我想编写一个头文件智能引入intrinsic函数。这就是zintrin.h。
其次—— VC中,没有直接判断是否支持某种intrinsic函数的办法,只能利用_MSC_VER判断VC的版本 来间接确认。而且还有x64环境下不支持MMX等特殊情况。 对于GCC,虽然可以利用__MMX__等宏判断是否打开了指令集支持,但这并不代表支持intrinsic函数。例如Mac OS X 中的 llvm-gcc,默认打开了__MMX__、__SSE__、__SSE2__,但它不支持intrinsic函数。
于是我想,如果有一种统一的方式判断当前编译环境是否支持某种intrinsic函数的办法就好了。
2.2 功能说明
功能—— 1. 引入了编译器支持的所有intrinsic函数. 2. 提供了 INTRIN_MMX 等一系列宏用于判断当前编译环境是否支持该intrin函数. 3. 兼容性补丁. 例如 _mm_cvtss_f32 等.
用于判断当前编译环境是否支持该intrin函数的宏: INTRIN_MMX INTRIN_3dNOW INTRIN_SSE INTRIN_SSE2 INTRIN_SSE3 INTRIN_SSSE3 INTRIN_SSE4_1 INTRIN_SSE4_2 INTRIN_SSE4A INTRIN_AES INTRIN_PCLMUL INTRIN_AVX INTRIN_AVX2 INTRIN_F16C INTRIN_FMA INTRIN_FMA4 INTRIN_XOP INTRIN_LWP INTRIN_RDRND INTRIN_FSGSBASE INTRIN_LZCNT INTRIN_POPCNT INTRIN_BMI INTRIN_BMI2 INTRIN_TBM
三、源码
3.1 zintrin.h
全部代码——
- #ifndef __ZINTRIN_H_INCLUDED
- #define __ZINTRIN_H_INCLUDED
- // 根据不同的编译器做不同的处理.
- #if defined(__GNUC__) // GCC
- #if (defined(__i386__) || defined(__x86_64__) ) && !defined(__llvm__) // Mac OS X 的 llvm 不支持 intrin 函数.
- // header files
- #include <x86intrin.h>
- #include <cpuid.h>
- // macros
- #ifdef __MMX__
- #define INTRIN_MMX 1
- #endif
- #ifdef __3dNOW__
- #define INTRIN_3dNOW 1
- #endif
- #ifdef __SSE__
- #define INTRIN_SSE 1
- #endif
- #ifdef __SSE2__
- #define INTRIN_SSE2 1
- #endif
- #ifdef __SSE3__
- #define INTRIN_SSE3 1
- #endif
- #ifdef __SSSE3__
- #define INTRIN_SSSE3 1
- #endif
- #ifdef __SSE4_1__
- #define INTRIN_SSE4_1 1
- #endif
- #ifdef __SSE4_2__
- #define INTRIN_SSE4_2 1
- #endif
- #ifdef __SSE4A__
- #define INTRIN_SSE4A 1
- #endif
- #ifdef __AES__
- #define INTRIN_AES 1
- #endif
- #ifdef __PCLMUL__
- #define INTRIN_PCLMUL 1
- #endif
- #ifdef __AVX__
- #define INTRIN_AVX 1
- #endif
- #ifdef __AVX2__
- #define INTRIN_AVX2 1
- #endif
- #ifdef __F16C__
- #define INTRIN_F16C 1
- #endif
- #ifdef __FMA__
- #define INTRIN_FMA 1
- #endif
- #ifdef __FMA4__
- #define INTRIN_FMA4 1
- #endif
- #ifdef __XOP__
- #define INTRIN_XOP 1
- #endif
- #ifdef __LWP__
- #define INTRIN_LWP 1
- #endif
- #ifdef __RDRND__
- #define INTRIN_RDRND 1
- #endif
- #ifdef __FSGSBASE__
- #define INTRIN_FSGSBASE 1
- #endif
- #ifdef __LZCNT__
- #define INTRIN_LZCNT 1
- #endif
- #ifdef __POPCNT__
- #define INTRIN_POPCNT 1
- #endif
- #ifdef __BMI__
- #define INTRIN_BMI 1
- #endif
- #ifdef __BMI2__
- #define INTRIN_BMI2 1
- #endif
- #ifdef __TBM__
- #define INTRIN_TBM 1
- #endif
- #endif // #if !defined(__llvm__)
- #elif defined(_MSC_VER) // MSVC
- // header files
- #if _MSC_VER >=1400 // VC2005
- #include <intrin.h>
- #elif _MSC_VER >=1200 // VC6
- #if (defined(_M_IX86) || defined(_M_X64))
- #include <emmintrin.h> // MMX, SSE, SSE2
- #include <mm3dnow.h> // 3DNow!
- #endif
- #endif // #if _MSC_VER >=1400
- #include <malloc.h> // _mm_malloc, _mm_free.
- // macros
- #if (defined(_M_IX86) || defined(_M_X64))
- #if _MSC_VER >=1200 // VC6
- #if defined(_M_X64) && !defined(__INTEL_COMPILER)
- // VC编译器不支持64位下的MMX.
- #else
- #define INTRIN_MMX 1 // mmintrin.h
- #define INTRIN_3dNOW 1 // mm3dnow.h
- #endif
- #define INTRIN_SSE 1 // xmmintrin.h
- #define INTRIN_SSE2 1 // emmintrin.h
- #endif
- #if _MSC_VER >=1300 // VC2003
- #endif
- #if _MSC_VER >=1400 // VC2005
- #endif
- #if _MSC_VER >=1500 // VC2008
- #define INTRIN_SSE3 1 // pmmintrin.h
- #define INTRIN_SSSE3 1 // tmmintrin.h
- #define INTRIN_SSE4_1 1 // smmintrin.h
- #define INTRIN_SSE4_2 1 // nmmintrin.h
- #define INTRIN_SSE4A 1 // intrin.h
- #define INTRIN_LZCNT 1 // intrin.h
- #define INTRIN_POPCNT 1 // nmmintrin.h
- #endif
- #if _MSC_VER >=1600 // VC2010
- #define INTRIN_AES 1 // wmmintrin.h
- #define INTRIN_PCLMUL 1 // wmmintrin.h
- #define INTRIN_AVX 1 // immintrin.h
- #define INTRIN_FMA4 1 // ammintrin.h
- #define INTRIN_XOP 1 // ammintrin.h
- #define INTRIN_LWP 1 // ammintrin.h
- #endif
- #if _MSC_VER >=1700 // VC2012
- #define INTRIN_AVX2 0 //TODO:待查证. 先设为0.
- #define INTRIN_FMA 0
- #define INTRIN_F16C 0
- #define INTRIN_RDRND 0
- #define INTRIN_FSGSBASE 0
- #define INTRIN_BMI 0
- #define INTRIN_BMI2 0
- #define INTRIN_TBM 0
- #endif
- #endif
- //TODO:待查证 VS配合intel C编译器时intrin函数的支持性.
- // VC2008之前没有_mm_cvtss_f32
- #if _MSC_VER <1500 // VC2008
- // float _mm_cvtss_f32(__m128 _A);
- #ifndef _mm_cvtss_f32
- #define _mm_cvtss_f32(__m128_A) ( *(float*)(void*)&(__m128_A) )
- #endif
- #endif
- #else
- //#error Only supports GCC or MSVC.
- #endif // #if defined(__GNUC__)
- #endif // #ifndef __ZINTRIN_H_INCLUDED
#ifndef __ZINTRIN_H_INCLUDED #define __ZINTRIN_H_INCLUDED // 根据不同的编译器做不同的处理. #if defined(__GNUC__) // GCC #if (defined(__i386__) || defined(__x86_64__) ) && !defined(__llvm__) // Mac OS X 的 llvm 不支持 intrin 函数. // header files #include <x86intrin.h> #include <cpuid.h> // macros #ifdef __MMX__ #define INTRIN_MMX 1 #endif #ifdef __3dNOW__ #define INTRIN_3dNOW 1 #endif #ifdef __SSE__ #define INTRIN_SSE 1 #endif #ifdef __SSE2__ #define INTRIN_SSE2 1 #endif #ifdef __SSE3__ #define INTRIN_SSE3 1 #endif #ifdef __SSSE3__ #define INTRIN_SSSE3 1 #endif #ifdef __SSE4_1__ #define INTRIN_SSE4_1 1 #endif #ifdef __SSE4_2__ #define INTRIN_SSE4_2 1 #endif #ifdef __SSE4A__ #define INTRIN_SSE4A 1 #endif #ifdef __AES__ #define INTRIN_AES 1 #endif #ifdef __PCLMUL__ #define INTRIN_PCLMUL 1 #endif #ifdef __AVX__ #define INTRIN_AVX 1 #endif #ifdef __AVX2__ #define INTRIN_AVX2 1 #endif #ifdef __F16C__ #define INTRIN_F16C 1 #endif #ifdef __FMA__ #define INTRIN_FMA 1 #endif #ifdef __FMA4__ #define INTRIN_FMA4 1 #endif #ifdef __XOP__ #define INTRIN_XOP 1 #endif #ifdef __LWP__ #define INTRIN_LWP 1 #endif #ifdef __RDRND__ #define INTRIN_RDRND 1 #endif #ifdef __FSGSBASE__ #define INTRIN_FSGSBASE 1 #endif #ifdef __LZCNT__ #define INTRIN_LZCNT 1 #endif #ifdef __POPCNT__ #define INTRIN_POPCNT 1 #endif #ifdef __BMI__ #define INTRIN_BMI 1 #endif #ifdef __BMI2__ #define INTRIN_BMI2 1 #endif #ifdef __TBM__ #define INTRIN_TBM 1 #endif #endif // #if !defined(__llvm__) #elif defined(_MSC_VER) // MSVC // header files #if _MSC_VER >=1400 // VC2005 #include <intrin.h> #elif _MSC_VER >=1200 // VC6 #if (defined(_M_IX86) || defined(_M_X64)) #include <emmintrin.h> // MMX, SSE, SSE2 #include <mm3dnow.h> // 3DNow! #endif #endif // #if _MSC_VER >=1400 #include <malloc.h> // _mm_malloc, _mm_free. // macros #if (defined(_M_IX86) || defined(_M_X64)) #if _MSC_VER >=1200 // VC6 #if defined(_M_X64) && !defined(__INTEL_COMPILER) // VC编译器不支持64位下的MMX. #else #define INTRIN_MMX 1 // mmintrin.h #define INTRIN_3dNOW 1 // mm3dnow.h #endif #define INTRIN_SSE 1 // xmmintrin.h #define INTRIN_SSE2 1 // emmintrin.h #endif #if _MSC_VER >=1300 // VC2003 #endif #if _MSC_VER >=1400 // VC2005 #endif #if _MSC_VER >=1500 // VC2008 #define INTRIN_SSE3 1 // pmmintrin.h #define INTRIN_SSSE3 1 // tmmintrin.h #define INTRIN_SSE4_1 1 // smmintrin.h #define INTRIN_SSE4_2 1 // nmmintrin.h #define INTRIN_SSE4A 1 // intrin.h #define INTRIN_LZCNT 1 // intrin.h #define INTRIN_POPCNT 1 // nmmintrin.h #endif #if _MSC_VER >=1600 // VC2010 #define INTRIN_AES 1 // wmmintrin.h #define INTRIN_PCLMUL 1 // wmmintrin.h #define INTRIN_AVX 1 // immintrin.h #define INTRIN_FMA4 1 // ammintrin.h #define INTRIN_XOP 1 // ammintrin.h #define INTRIN_LWP 1 // ammintrin.h #endif #if _MSC_VER >=1700 // VC2012 #define INTRIN_AVX2 0 //TODO:待查证. 先设为0. #define INTRIN_FMA 0 #define INTRIN_F16C 0 #define INTRIN_RDRND 0 #define INTRIN_FSGSBASE 0 #define INTRIN_BMI 0 #define INTRIN_BMI2 0 #define INTRIN_TBM 0 #endif #endif //TODO:待查证 VS配合intel C编译器时intrin函数的支持性. // VC2008之前没有_mm_cvtss_f32 #if _MSC_VER <1500 // VC2008 // float _mm_cvtss_f32(__m128 _A); #ifndef _mm_cvtss_f32 #define _mm_cvtss_f32(__m128_A) ( *(float*)(void*)&(__m128_A) ) #endif #endif #else //#error Only supports GCC or MSVC. #endif // #if defined(__GNUC__) #endif // #ifndef __ZINTRIN_H_INCLUDED
3.2 testzintrin.c
全部代码——
- #include <stdio.h>
- #include "zintrin.h"
- #define PT_MAKE_STR(x) { #x, PT_MAKE_STR_ESC(x) }
- #define PT_MAKE_STR_ESC(x) #x
- typedefstruct tagMACRO_T
- {
- constchar *name;
- constchar *value;
- } MACRO_T;
- /* Intrinsics */
- const MACRO_T g_intrins[] =
- {
- {"[Intrinsics]", ""},
- #ifdef INTRIN_MMX
- PT_MAKE_STR(INTRIN_MMX),
- #endif
- #ifdef INTRIN_3dNOW
- PT_MAKE_STR(INTRIN_3dNOW),
- #endif
- #ifdef INTRIN_SSE
- PT_MAKE_STR(INTRIN_SSE),
- #endif
- #ifdef INTRIN_SSE2
- PT_MAKE_STR(INTRIN_SSE2),
- #endif
- #ifdef INTRIN_SSE3
- PT_MAKE_STR(INTRIN_SSE3),
- #endif
- #ifdef INTRIN_SSSE3
- PT_MAKE_STR(INTRIN_SSSE3),
- #endif
- #ifdef INTRIN_SSE4_1
- PT_MAKE_STR(INTRIN_SSE4_1),
- #endif
- #ifdef INTRIN_SSE4_2
- PT_MAKE_STR(INTRIN_SSE4_2),
- #endif
- #ifdef INTRIN_SSE4A
- PT_MAKE_STR(INTRIN_SSE4A),
- #endif
- #ifdef INTRIN_AES
- PT_MAKE_STR(INTRIN_AES),
- #endif
- #ifdef INTRIN_PCLMUL
- PT_MAKE_STR(INTRIN_PCLMUL),
- #endif
- #ifdef INTRIN_AVX
- PT_MAKE_STR(INTRIN_AVX),
- #endif
- #ifdef INTRIN_AVX2
- PT_MAKE_STR(INTRIN_AVX2),
- #endif
- #ifdef INTRIN_F16C
- PT_MAKE_STR(INTRIN_F16C),
- #endif
- #ifdef INTRIN_FMA
- PT_MAKE_STR(INTRIN_FMA),
- #endif
- #ifdef INTRIN_FMA4
- PT_MAKE_STR(INTRIN_FMA4),
- #endif
- #ifdef INTRIN_XOP
- PT_MAKE_STR(INTRIN_XOP),
- #endif
- #ifdef INTRIN_LWP
- PT_MAKE_STR(INTRIN_LWP),
- #endif
- #ifdef INTRIN_RDRND
- PT_MAKE_STR(INTRIN_RDRND),
- #endif
- #ifdef INTRIN_FSGSBASE
- PT_MAKE_STR(INTRIN_FSGSBASE),
- #endif
- #ifdef INTRIN_LZCNT
- PT_MAKE_STR(INTRIN_LZCNT),
- #endif
- #ifdef INTRIN_POPCNT
- PT_MAKE_STR(INTRIN_POPCNT),
- #endif
- #ifdef INTRIN_BMI
- PT_MAKE_STR(INTRIN_BMI),
- #endif
- #ifdef INTRIN_BMI2
- PT_MAKE_STR(INTRIN_BMI2),
- #endif
- #ifdef INTRIN_TBM
- PT_MAKE_STR(INTRIN_TBM),
- #endif
- };
- // 获取程序位数(被编译为多少位的代码)
- int GetProgramBits(void)
- {
- returnsizeof(int*) * 8;
- }
- void print_MACRO_T(const MACRO_T* pArray, int cnt)
- {
- int i;
- for( i = 0; i < cnt; ++i )
- {
- printf( "%s\t%s\n", pArray[i].name, pArray[i].value );
- }
- printf( "\n" );
- }
- int main(int argc, char* argv[])
- {
- printf("testzintrin v1.00 (%dbit)\n\n", GetProgramBits());
- print_MACRO_T(g_intrins, sizeof(g_intrins)/sizeof(g_intrins[0]));
- // _mm_malloc
- #ifdef INTRIN_SSE
- if(1)
- {
- void* p;
- p = _mm_malloc(0x10, 0x10);
- printf("_mm_malloc:\t%ph\n", p);
- _mm_free(p);
- }
- #endif
- // mmx
- #ifdef INTRIN_MMX
- _mm_empty();
- #endif
- // 3DNow!
- #ifdef INTRIN_3dNOW
- //_m_femms(); // AMD cpu only.
- #endif
- // sse
- #ifdef INTRIN_SSE
- if(1)
- {
- __m128 xmm1;
- float f;
- printf("&xmm1:\t%ph\n", &xmm1);
- xmm1 = _mm_setzero_ps(); // SSE instruction: xorps
- f = _mm_cvtss_f32(xmm1);
- printf("_mm_cvtss_f32:\t%f\n", f);
- }
- #endif
- // popcnt
- #ifdef INTRIN_POPCNT
- printf("popcnt(0xffffffffu):\t%u\n", _mm_popcnt_u32(0xffffffffu));
- #endif
- return 0;
- }
#include <stdio.h>
#include "zintrin.h"
#define PT_MAKE_STR(x) { #x, PT_MAKE_STR_ESC(x) }
#define PT_MAKE_STR_ESC(x) #x
typedef struct tagMACRO_T
{
const char *name;
const char *value;
} MACRO_T;
/* Intrinsics */
const MACRO_T g_intrins[] =
{
{"[Intrinsics]", ""},
#ifdef INTRIN_MMX
PT_MAKE_STR(INTRIN_MMX),
#endif
#ifdef INTRIN_3dNOW
PT_MAKE_STR(INTRIN_3dNOW),
#endif
#ifdef INTRIN_SSE
PT_MAKE_STR(INTRIN_SSE),
#endif
#ifdef INTRIN_SSE2
PT_MAKE_STR(INTRIN_SSE2),
#endif
#ifdef INTRIN_SSE3
PT_MAKE_STR(INTRIN_SSE3),
#endif
#ifdef INTRIN_SSSE3
PT_MAKE_STR(INTRIN_SSSE3),
#endif
#ifdef INTRIN_SSE4_1
PT_MAKE_STR(INTRIN_SSE4_1),
#endif
#ifdef INTRIN_SSE4_2
PT_MAKE_STR(INTRIN_SSE4_2),
#endif
#ifdef INTRIN_SSE4A
PT_MAKE_STR(INTRIN_SSE4A),
#endif
#ifdef INTRIN_AES
PT_MAKE_STR(INTRIN_AES),
#endif
#ifdef INTRIN_PCLMUL
PT_MAKE_STR(INTRIN_PCLMUL),
#endif
#ifdef INTRIN_AVX
PT_MAKE_STR(INTRIN_AVX),
#endif
#ifdef INTRIN_AVX2
PT_MAKE_STR(INTRIN_AVX2),
#endif
#ifdef INTRIN_F16C
PT_MAKE_STR(INTRIN_F16C),
#endif
#ifdef INTRIN_FMA
PT_MAKE_STR(INTRIN_FMA),
#endif
#ifdef INTRIN_FMA4
PT_MAKE_STR(INTRIN_FMA4),
#endif
#ifdef INTRIN_XOP
PT_MAKE_STR(INTRIN_XOP),
#endif
#ifdef INTRIN_LWP
PT_MAKE_STR(INTRIN_LWP),
#endif
#ifdef INTRIN_RDRND
PT_MAKE_STR(INTRIN_RDRND),
#endif
#ifdef INTRIN_FSGSBASE
PT_MAKE_STR(INTRIN_FSGSBASE),
#endif
#ifdef INTRIN_LZCNT
PT_MAKE_STR(INTRIN_LZCNT),
#endif
#ifdef INTRIN_POPCNT
PT_MAKE_STR(INTRIN_POPCNT),
#endif
#ifdef INTRIN_BMI
PT_MAKE_STR(INTRIN_BMI),
#endif
#ifdef INTRIN_BMI2
PT_MAKE_STR(INTRIN_BMI2),
#endif
#ifdef INTRIN_TBM
PT_MAKE_STR(INTRIN_TBM),
#endif
};
// 获取程序位数(被编译为多少位的代码)
int GetProgramBits(void)
{
return sizeof(int*) * 8;
}
void print_MACRO_T(const MACRO_T* pArray, int cnt)
{
int i;
for( i = 0; i < cnt; ++i )
{
printf( "%s\t%s\n", pArray[i].name, pArray[i].value );
}
printf( "\n" );
}
int main(int argc, char* argv[])
{
printf("testzintrin v1.00 (%dbit)\n\n", GetProgramBits());
print_MACRO_T(g_intrins, sizeof(g_intrins)/sizeof(g_intrins[0]));
// _mm_malloc
#ifdef INTRIN_SSE
if(1)
{
void* p;
p = _mm_malloc(0x10, 0x10);
printf("_mm_malloc:\t%ph\n", p);
_mm_free(p);
}
#endif
// mmx
#ifdef INTRIN_MMX
_mm_empty();
#endif
// 3DNow!
#ifdef INTRIN_3dNOW
//_m_femms(); // AMD cpu only.
#endif
// sse
#ifdef INTRIN_SSE
if(1)
{
__m128 xmm1;
float f;
printf("&xmm1:\t%ph\n", &xmm1);
xmm1 = _mm_setzero_ps(); // SSE instruction: xorps
f = _mm_cvtss_f32(xmm1);
printf("_mm_cvtss_f32:\t%f\n", f);
}
#endif
// popcnt
#ifdef INTRIN_POPCNT
printf("popcnt(0xffffffffu):\t%u\n", _mm_popcnt_u32(0xffffffffu));
#endif
return 0;
}
3.3 makefile
全部代码——
- # flags
- CC = gcc
- CFS = -Wall
- LFS =
- # args
- RELEASE =0
- BITS =
- CFLAGS = -msse
- # [args] 生成模式. 0代表debug模式, 1代表release模式. make RELEASE=1.
- ifeq ($(RELEASE),0)
- # debug
- CFS += -g
- else
- # release
- CFS += -static -O3 -DNDEBUG
- LFS += -static
- endif
- # [args] 程序位数. 32代表32位程序, 64代表64位程序, 其他默认. make BITS=32.
- ifeq ($(BITS),32)
- CFS += -m32
- LFS += -m32
- else
- ifeq ($(BITS),64)
- CFS += -m64
- LFS += -m64
- else
- endif
- endif
- # [args] 使用 CFLAGS 添加新的参数. make CFLAGS="-mpopcnt -msse4a".
- CFS += $(CFLAGS)
- .PHONY : all clean
- # files
- TARGETS = testzintrin
- OBJS = testzintrin.o
- all : $(TARGETS)
- testzintrin : $(OBJS)
- $(CC) $(LFS) -o $@ $^
- testzintrin.o : testzintrin.c zintrin.h
- $(CC) $(CFS) -c $<
- clean :
- rm -f $(OBJS) $(TARGETS) $(addsuffix .exe,$(TARGETS))
# flags CC = gcc CFS = -Wall LFS = # args RELEASE =0 BITS = CFLAGS = -msse # [args] 生成模式. 0代表debug模式, 1代表release模式. make RELEASE=1. ifeq ($(RELEASE),0) # debug CFS += -g else # release CFS += -static -O3 -DNDEBUG LFS += -static endif # [args] 程序位数. 32代表32位程序, 64代表64位程序, 其他默认. make BITS=32. ifeq ($(BITS),32) CFS += -m32 LFS += -m32 else ifeq ($(BITS),64) CFS += -m64 LFS += -m64 else endif endif # [args] 使用 CFLAGS 添加新的参数. make CFLAGS="-mpopcnt -msse4a". CFS += $(CFLAGS) .PHONY : all clean # files TARGETS = testzintrin OBJS = testzintrin.o all : $(TARGETS) testzintrin : $(OBJS) $(CC) $(LFS) -o $@ $^ testzintrin.o : testzintrin.c zintrin.h $(CC) $(CFS) -c $< clean : rm -f $(OBJS) $(TARGETS) $(addsuffix .exe,$(TARGETS))
四、测试
在以下编译器中成功编译—— VC6:x86版。 VC2003:x86版。 VC2005:x86版、x64版。 VC2010:x86版、x64版。 GCC 4.7.0(Fedora 17 x64):x86版、x64版。 GCC 4.6.2(MinGW(20120426)):x86版。 GCC 4.6.1(TDM-GCC(MinGW-w64)):x86版、x64版。 llvm-gcc-4.2(Mac OS X Lion 10.7.4, Xcode 4.4.1):x86版、x64版。

参考文献—— 《Predefined Macros》. http://msdn.microsoft.com/en-us/library/b0084kay(v=vs.110).aspx 《Intrinsics头文件与SIMD指令集、Visual Studio版本对应表》. http://www.cnblogs.com/zyl910/archive/2012/02/28/vs_intrin_table.html 《GCC中的Intrinsics头文件与SIMD指令集、宏、参数的对应表》. http://www.cnblogs.com/zyl910/archive/2012/08/27/intrin_table_gcc.html
浙公网安备 33010602011771号