zoukankan      html  css  js  c++  java
  • [C] zintrin.h : 智能引入intrinsic函数。支持VC、GCC,兼容Windows、Linux、Mac OS X

    新版本——
    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

    作者:zyl910
    版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0.
  • 相关阅读:
    使用.Net Core+IView+Vue集成上传图片功能
    Vue基于vue-quill-editor富文本编辑器使用心得
    Fiddler原理~知多少?
    ASP.NET Core WebApi中简单像素转换跟踪实现
    利用SQL Profiler 追踪数据库操作
    ASP.NET Core Web API 版本控制
    处理SQL Server中的重复行
    【3分钟就会系列】使用Ocelot+Consul搭建微服务吧!
    ASP.NET Core WebAPI控制器返回类型的最佳选项
    花10分钟搞懂开源框架吧
  • 原文地址:https://www.cnblogs.com/zyl910/p/zintrin.html
Copyright © 2011-2022 走看看