zyl910

优化技巧、硬件体系、图像处理、图形学、游戏编程、国际化与文本信息处理。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

新版本——
http://www.cnblogs.com/zyl910/archive/2012/10/01/zintrin_v101.html

 

作者:zyl910

  现在很多编译器支持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 --target-help
$ gcc --target-help
下列选项与特定目标机相关:
  -m128bit-long-double        sizeof(long double) 等于 16
  -m32                        生成 32 位 i386 代码
  -m3dnow                     支持 3DNow! 内建函数
  -m64                        生成 64 位 x86-64 代码
  -m80387                     使用硬件浮点单元
  -m8bit-idiv                 将 32/64
                              位整数除法扩展为带运行时检查的 8
                              位无符号整数除法
  -m96bit-long-double         sizeof(long double) 等于 12
  -mabi=                      生成遵循给定 ABI 的代码
  -mabm                       支持生成高级位操作(ABM)指令。
  -maccumulate-outgoing-args  在函数序言中为输出参数预留空间
  -maes                       支持 AES 内建函数及代码生成
  -malign-double              一些双精度浮点数在双字边界上对齐
  -malign-functions=          函数入口对齐在 2 的此次方上
  -malign-jumps=              跳转目标对齐在 2 的此次方上
  -malign-loops=              循环代码对齐到 2 的此次方上
  -malign-stringops           对齐字符串操作的目标
  -mandroid                   为 Android 操作系统生成代码。
  -march=                     为给定的 CPU 生成代码
  -masm=                      使用给定的汇编风格
  -mavx                       支持
                              MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2
                              和 AVX 内建函数及代码生成
  -mavx2                      Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1,
                              SSE4.2, AVX and AVX2 built-in functions and code
                              generation
  -mavx256-split-unaligned-load Split 32-byte AVX unaligned load
  -mavx256-split-unaligned-store Split 32-byte AVX unaligned store
  -mbionic                    使用 Bionic C 标准库
  -mbmi                       支持 BMI 内建函数及代码生成
  -mbmi2                      Support BMI2 built-in functions and code
                              generation
  -mbranch-cost=              指定分支的代价(1-5,任意单位)
  -mcld                       在函数序言中生成 cld 指令
  -mcmodel=                   使用给定的 x86-64 代码模式
  -mcrc32                     支持生成 crc32 指令。
  -mcx16                      支持生成 cmpxchg16b 指令。
  -mdispatch-scheduler        Do dispatch scheduling if processor is bdver1 or
                              bdver2 and Haifa scheduling is selected.
  -mf16c                      支持 F16C 内建函数及代码生成
  -mfancy-math-387            为 FPU 生成 sin、cos 和 sqrt 指令
  -mfentry                    Emit profiling counter call at function entry
                              before prologue.
  -mfma                       支持
                              MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX
                              和 FMA 内建函数及代码生成
  -mfma4                      支持 FMA4 内建函数及代码生成
  -mforce-drap                总是使用动态对齐参数指针(DRAP)来重新对齐堆栈
  -mfp-ret-in-387             在 FPU 寄存器中存放函数返回值
  -mfpmath=                   为指定的指令集生成浮点数学代码
  -mfsgsbase                  支持 FSGSBASE 内建函数及代码生成
  -mglibc                     使用 GNU C 标准库
  -mhard-float                使用硬件浮点单元
  -mieee-fp                   浮点数间的比较严格遵循 IEEE 标准
  -mincoming-stack-boundary=  假定栈对齐到 2 的此次方上
  -minline-all-stringops      内联所有已知的字符串操作
  -minline-stringops-dynamically 内联 memset/memcpy
                              字符串操作,但仅为较小的块使用内联版本
  -mlarge-data-threshold=     在 x86-64
                              中等模式下大于指定阈值的数据将被存放在
                              .ldata 节中
  -mlwp                       支持 LWP 内建函数及代码生成
  -mlzcnt                     Support LZCNT built-in function and code
                              generation
  -mmmx                       支持 MMX 内建函数
  -mmovbe                     支持生成 movbe 指令。
  -mms-bitfields              使用本地 (MS) 位段存储方式
  -mno-sse4                   不支持 SSE4.1 和 SSE4.2
                              内建函数及代码生成
  -momit-leaf-frame-pointer   为叶函数(不调用其他函数的函数)忽略框架指针
  -mpc32                      Set 80387 floating-point precision to 32-bit
  -mpc64                      Set 80387 floating-point precision to 64-bit
  -mpc80                      Set 80387 floating-point precision to 80-bit
  -mpclmul                    支持 PCLMUL 内建函数及代码生成
  -mpopcnt                    支持生成 popcnt 指令。
  -mprefer-avx128             自动向量化时使用 128 位 AVX
                              指令而不是 256 位 AVX 指令
  -mpreferred-stack-boundary= 试图让栈保持对齐到 2 的此次方上
  -mpush-args                 使用 push 指令保存输出参数
  -mrdrnd                     支持 RDRND 内建函数及代码生成
  -mrecip                     生成倒数指令而不是 divss 和 sqrtss。
  -mrecip=                    Control generation of reciprocal estimates.
  -mred-zone                  在 x86-64 代码中使用红区
  -mregparm=                  用以传递整数参数的寄存器个数
  -mrtd                       更改调用约定
  -msahf                      支持在 x86-64 模式下生成 sahf 指令。
  -msoft-float                不使用硬件浮点单元
  -msse                       支持 MMX 和 SSE 内建函数及代码生成
  -msse2                      支持 MMX、SSE 和 SSE2
                              内建函数及代码生成
  -msse2avx                   支持带 VEX 前缀的 SSE 指令
  -msse3                      支持 MMX、SSE、SSE2 和 SSE3
                              内建函数及代码生成
  -msse4                      支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1
                              和 SSE4.2 内建函数及代码生成
  -msse4.1                    支持 MMX、SSE、SSE2、SSE3、SSSE3 和 SSE4.1
                              内建函数及代码生成
  -msse4.2                    支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1
                              和 SSE4.2 内建函数及代码生成
  -msse4a                     支持 MMX、SSE、SSE2、SSE3 和 SSE4A
                              内建函数及代码生成
  -msseregparm                在 SF 和 DF 模式下使用 SSE
                              寄存器调用约定
  -mssse3                     支持 MMX、SSE、SSE2、SSE3 和 SSSE3
                              内建函数及代码生成
  -mstack-arg-probe           启用堆栈探测
  -mstackrealign              在前言中重新对齐堆栈
  -mstringop-strategy=        选择生成字符串操作的策略
  -mtbm                       支持 TBM 内建函数及代码生成
  -mtls-dialect=              使用给定的线程局部存储模式
  -mtls-direct-seg-refs       当访问线程局部数据时直接引用 %gs
  -mtune=                     为指定的 CPU 优化代码
  -muclibc                    使用 uClibc C 标准库
  -mveclibabi=                指定要使用的向量库 ABI
  -mvect8-ret-in-mem          将 8 字节向量在内存中返回
  -mvzeroupper                Generate vzeroupper instruction before a transfer
                              of control flow out of the function.
  -mx32                       Generate 32bit x86-64 code
  -mxop                       支持 XOP 内建函数及代码生成

  Known assembler dialects (for use with the -masm-dialect= option):
    att intel

  Known ABIs (for use with the -mabi= option):
    ms sysv

  Known code models (for use with the -mcmodel= option):
    32 kernel large medium small

  Valid arguments to -mfpmath=:
    387 387+sse 387,sse both sse sse+387 sse,387

  Known vectorization library ABIs (for use with the -mveclibabi= option):
    acml svml

  Valid arguments to -mstringop-strategy=:
    byte_loop libcall loop rep_4byte rep_8byte rep_byte unrolled_loop

  Known TLS dialects (for use with the -mtls-dialect= option):
    gnu gnu2

汇编器选项
=================

使用“-Wa,选项”将“选项”传递给汇编器。

  -Q                      ignored
  -V                      print assembler version number
  -k                      ignored
  -n                      Do not optimize code alignment
  -q                      quieten some warnings
  -s                      ignored
  --32/--64/--x32         generate 32bit/64bit/x32 code
  --divide                ignored
  -march=CPU[,+EXTENSION...]
                          generate code for CPU and EXTENSION, CPU is one of:
                           generic32, generic64, i386, i486, i586, i686,
                           pentium, pentiumpro, pentiumii, pentiumiii, pentium4,
                           prescott, nocona, core, core2, corei7, l1om, k1om,
                           k6, k6_2, athlon, opteron, k8, amdfam10, bdver1,
                           bdver2
                          EXTENSION is combination of:
                           8087, 287, 387, no87, mmx, nommx, sse, sse2, sse3,
                           ssse3, sse4.1, sse4.2, sse4, nosse, avx, avx2, noavx,
                           vmx, vmfunc, smx, xsave, xsaveopt, aes, pclmul,
                           fsgsbase, rdrnd, f16c, bmi2, fma, fma4, xop, lwp,
                           movbe, ept, lzcnt, hle, rtm, invpcid, clflush, nop,
                           syscall, rdtscp, 3dnow, 3dnowa, padlock, svme, sse4a,
                           abm, bmi, tbm
  -mtune=CPU              optimize for CPU, CPU is one of:
                           generic32, generic64, i8086, i186, i286, i386, i486,
                           i586, i686, pentium, pentiumpro, pentiumii,
                           pentiumiii, pentium4, prescott, nocona, core, core2,
                           corei7, l1om, k1om, k6, k6_2, athlon, opteron, k8,
                           amdfam10, bdver1, bdver2
  -msse2avx               encode SSE instructions with VEX prefix
  -msse-check=[none|error|warning]
                          check SSE instructions
  -mavxscalar=[128|256]   encode scalar AVX instructions with specific vector
                           length
  -mmnemonic=[att|intel]  use AT&T/Intel mnemonic
  -msyntax=[att|intel]    use AT&T/Intel syntax
  -mindex-reg             support pseudo index registers
  -mnaked-reg             don't require `%' prefix for registers
  -mold-gcc               support old (<= 2.8.1) versions of gcc

链接器选项
==============

使用“-Wl,选项”将“选项”传递给链接器。

elf_x86_64: 
  --audit=AUDITLIB            Specify a library to use for auditing
  -Bgroup                     Selects group name lookup rules for DSO
  --build-id[=STYLE]          Generate build ID note
  -P AUDITLIB, --depaudit=AUDITLIB
                              Specify a library to use for auditing dependencies
  --disable-new-dtags         Disable new dynamic tags
  --enable-new-dtags          Enable new dynamic tags
  --eh-frame-hdr              Create .eh_frame_hdr section
  --exclude-libs=LIBS         Make all symbols in LIBS hidden
  --hash-style=STYLE          Set hash style to sysv, gnu or both
  -z combreloc                Merge dynamic relocs into one section and sort
  -z common-page-size=SIZE    Set common page size to SIZE
  -z defs                     Report unresolved symbols in object files.
  -z execstack                Mark executable as requiring executable stack
  -z initfirst                Mark DSO to be initialized first at runtime
  -z interpose                Mark object to interpose all DSOs but executable
  -z lazy                     Mark object lazy runtime binding (default)
  -z loadfltr                 Mark object requiring immediate process
  -z max-page-size=SIZE       Set maximum page size to SIZE
  -z muldefs                  Allow multiple definitions
  -z nocombreloc              Don't merge dynamic relocs into one section
  -z nocopyreloc              Don't create copy relocs
  -z nodefaultlib             Mark object not to use default search paths
  -z nodelete                 Mark DSO non-deletable at runtime
  -z nodlopen                 Mark DSO not available to dlopen
  -z nodump                   Mark DSO not available to dldump
  -z noexecstack              Mark executable as not requiring executable stack
  -z norelro                  Don't create RELRO program header
  -z now                      Mark object non-lazy runtime binding
  -z origin                   Mark object requiring immediate $ORIGIN
                                processing at runtime
  -z relro                    Create RELRO program header
  --ld-generated-unwind-info  Generate exception handling info for PLT.
  --no-ld-generated-unwind-info Don't do so.
elf32_x86_64: 
  --audit=AUDITLIB            Specify a library to use for auditing
  -Bgroup                     Selects group name lookup rules for DSO
  --build-id[=STYLE]          Generate build ID note
  -P AUDITLIB, --depaudit=AUDITLIB
                              Specify a library to use for auditing dependencies
  --disable-new-dtags         Disable new dynamic tags
  --enable-new-dtags          Enable new dynamic tags
  --eh-frame-hdr              Create .eh_frame_hdr section
  --exclude-libs=LIBS         Make all symbols in LIBS hidden
  --hash-style=STYLE          Set hash style to sysv, gnu or both
  -z combreloc                Merge dynamic relocs into one section and sort
  -z common-page-size=SIZE    Set common page size to SIZE
  -z defs                     Report unresolved symbols in object files.
  -z execstack                Mark executable as requiring executable stack
  -z initfirst                Mark DSO to be initialized first at runtime
  -z interpose                Mark object to interpose all DSOs but executable
  -z lazy                     Mark object lazy runtime binding (default)
  -z loadfltr                 Mark object requiring immediate process
  -z max-page-size=SIZE       Set maximum page size to SIZE
  -z muldefs                  Allow multiple definitions
  -z nocombreloc              Don't merge dynamic relocs into one section
  -z nocopyreloc              Don't create copy relocs
  -z nodefaultlib             Mark object not to use default search paths
  -z nodelete                 Mark DSO non-deletable at runtime
  -z nodlopen                 Mark DSO not available to dlopen
  -z nodump                   Mark DSO not available to dldump
  -z noexecstack              Mark executable as not requiring executable stack
  -z norelro                  Don't create RELRO program header
  -z now                      Mark object non-lazy runtime binding
  -z origin                   Mark object requiring immediate $ORIGIN
                                processing at runtime
  -z relro                    Create RELRO program header
  --ld-generated-unwind-info  Generate exception handling info for PLT.
  --no-ld-generated-unwind-info Don't do so.
elf_i386: 
  --audit=AUDITLIB            Specify a library to use for auditing
  -Bgroup                     Selects group name lookup rules for DSO
  --build-id[=STYLE]          Generate build ID note
  -P AUDITLIB, --depaudit=AUDITLIB
                              Specify a library to use for auditing dependencies
  --disable-new-dtags         Disable new dynamic tags
  --enable-new-dtags          Enable new dynamic tags
  --eh-frame-hdr              Create .eh_frame_hdr section
  --exclude-libs=LIBS         Make all symbols in LIBS hidden
  --hash-style=STYLE          Set hash style to sysv, gnu or both
  -z combreloc                Merge dynamic relocs into one section and sort
  -z common-page-size=SIZE    Set common page size to SIZE
  -z defs                     Report unresolved symbols in object files.
  -z execstack                Mark executable as requiring executable stack
  -z initfirst                Mark DSO to be initialized first at runtime
  -z interpose                Mark object to interpose all DSOs but executable
  -z lazy                     Mark object lazy runtime binding (default)
  -z loadfltr                 Mark object requiring immediate process
  -z max-page-size=SIZE       Set maximum page size to SIZE
  -z muldefs                  Allow multiple definitions
  -z nocombreloc              Don't merge dynamic relocs into one section
  -z nocopyreloc              Don't create copy relocs
  -z nodefaultlib             Mark object not to use default search paths
  -z nodelete                 Mark DSO non-deletable at runtime
  -z nodlopen                 Mark DSO not available to dlopen
  -z nodump                   Mark DSO not available to dldump
  -z noexecstack              Mark executable as not requiring executable stack
  -z norelro                  Don't create RELRO program header
  -z now                      Mark object non-lazy runtime binding
  -z origin                   Mark object requiring immediate $ORIGIN
                                processing at runtime
  -z relro                    Create RELRO program header
  --ld-generated-unwind-info  Generate exception handling info for PLT.
  --no-ld-generated-unwind-info Don't do so.
elf_l1om: 
  --audit=AUDITLIB            Specify a library to use for auditing
  -Bgroup                     Selects group name lookup rules for DSO
  --build-id[=STYLE]          Generate build ID note
  -P AUDITLIB, --depaudit=AUDITLIB
                              Specify a library to use for auditing dependencies
  --disable-new-dtags         Disable new dynamic tags
  --enable-new-dtags          Enable new dynamic tags
  --eh-frame-hdr              Create .eh_frame_hdr section
  --exclude-libs=LIBS         Make all symbols in LIBS hidden
  --hash-style=STYLE          Set hash style to sysv, gnu or both
  -z combreloc                Merge dynamic relocs into one section and sort
  -z common-page-size=SIZE    Set common page size to SIZE
  -z defs                     Report unresolved symbols in object files.
  -z execstack                Mark executable as requiring executable stack
  -z initfirst                Mark DSO to be initialized first at runtime
  -z interpose                Mark object to interpose all DSOs but executable
  -z lazy                     Mark object lazy runtime binding (default)
  -z loadfltr                 Mark object requiring immediate process
  -z max-page-size=SIZE       Set maximum page size to SIZE
  -z muldefs                  Allow multiple definitions
  -z nocombreloc              Don't merge dynamic relocs into one section
  -z nocopyreloc              Don't create copy relocs
  -z nodefaultlib             Mark object not to use default search paths
  -z nodelete                 Mark DSO non-deletable at runtime
  -z nodlopen                 Mark DSO not available to dlopen
  -z nodump                   Mark DSO not available to dldump
  -z noexecstack              Mark executable as not requiring executable stack
  -z norelro                  Don't create RELRO program header
  -z now                      Mark object non-lazy runtime binding
  -z origin                   Mark object requiring immediate $ORIGIN
                                processing at runtime
  -z relro                    Create RELRO program header
  --ld-generated-unwind-info  Generate exception handling info for PLT.
  --no-ld-generated-unwind-info Don't do so.
elf_k1om: 
  --audit=AUDITLIB            Specify a library to use for auditing
  -Bgroup                     Selects group name lookup rules for DSO
  --build-id[=STYLE]          Generate build ID note
  -P AUDITLIB, --depaudit=AUDITLIB
                              Specify a library to use for auditing dependencies
  --disable-new-dtags         Disable new dynamic tags
  --enable-new-dtags          Enable new dynamic tags
  --eh-frame-hdr              Create .eh_frame_hdr section
  --exclude-libs=LIBS         Make all symbols in LIBS hidden
  --hash-style=STYLE          Set hash style to sysv, gnu or both
  -z combreloc                Merge dynamic relocs into one section and sort
  -z common-page-size=SIZE    Set common page size to SIZE
  -z defs                     Report unresolved symbols in object files.
  -z execstack                Mark executable as requiring executable stack
  -z initfirst                Mark DSO to be initialized first at runtime
  -z interpose                Mark object to interpose all DSOs but executable
  -z lazy                     Mark object lazy runtime binding (default)
  -z loadfltr                 Mark object requiring immediate process
  -z max-page-size=SIZE       Set maximum page size to SIZE
  -z muldefs                  Allow multiple definitions
  -z nocombreloc              Don't merge dynamic relocs into one section
  -z nocopyreloc              Don't create copy relocs
  -z nodefaultlib             Mark object not to use default search paths
  -z nodelete                 Mark DSO non-deletable at runtime
  -z nodlopen                 Mark DSO not available to dlopen
  -z nodump                   Mark DSO not available to dldump
  -z noexecstack              Mark executable as not requiring executable stack
  -z norelro                  Don't create RELRO program header
  -z now                      Mark object non-lazy runtime binding
  -z origin                   Mark object requiring immediate $ORIGIN
                                processing at runtime
  -z relro                    Create RELRO program header
  --ld-generated-unwind-info  Generate exception handling info for PLT.
  --no-ld-generated-unwind-info Don't do so.

 

  当通过命令行参数打开指令集支持后,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

 


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

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))

 


四、测试

  在以下编译器中成功编译——
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

 

源码下载——
https://files.cnblogs.com/zyl910/zintrin.rar

posted on 2012-09-23 23:09  zyl910  阅读(3600)  评论(0编辑  收藏  举报