新版本——
http://www.cnblogs.com/zyl910/archive/2012/11/07/zintrin_v102.html
[C] zintrin.h: 智能引入intrinsic函数 V1.02版。支持VC2012,增加INTRIN_ALIGN、INTRIN_COMPILER_NAME宏

作者:zyl910。

  之前的zintrin V1.00版对Mac OS X平台支持性不佳。现在的V1.01版改进对Mac OS X的支持,还做了这些改进——增加INTRIN_WORDSIZE宏 等。

一、更新说明

1.1 改进对Mac OS X的支持

  前几天在使用Xcode时,发现mac下也有intrinsic头文件,详见http://www.cnblogs.com/zyl910/archive/2012/09/27/intrin_mac.html。
  但是在终端中调用gcc编译时,总是报告找不到cpuid.h、x86intrin.h等文件。
  后来才发现,“使用Xcode” 与 “终端中调用gcc”这两种情况下,编译器的include目录是不同的——
使用Xcode:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/4.0/include
终端中调用gcc:/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/include

  “/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/include”文件夹下的intrinsic头文件版本较老,没有提供cpuid.h、x86intrin.h等新版本的文件。

  该怎么办呢?
  方案一:用宏判断gcc的版本,然后引入最高支持的intrinsic头文件。
  方案二:强制要求用户配置好include目录。
  方案三:根据__MMX__等宏判断当前编译器是否启用该指令集,然后引入相应文件。

  方案一不行。因为现在gcc的版本一样,只是include目录不同。
  方案二也不好。因为这样给使用带来了麻烦。
  方案三不错。按需引入对应的文件。当发现启用AVX等新指令集时,x86intrin.h应该是可用的。

1.2 增加INTRIN_WORDSIZE宏

  某些intrinsic函数仅在64位下可用,例如_mm_popcnt_u64。所以需要一种能判断目标机器字长的办法。

  一般情况下,指针变量的长度就是机器字长,但是sizeof运算符不能用于宏预处理。

  这是可以利用C99的stdint.h,它提供了一系列宏用于判断各种数据类型的范围。其中有PTRDIFF_MAX,我们可以利用它来判断机器字长——

// INTRIN_WORDSIZE: 目标机器的字长.
#if PTRDIFF_MAX >= INT64_MAX#define INTRIN_WORDSIZE    64
#elif PTRDIFF_MAX >= INT32_MAX#define INTRIN_WORDSIZE    32
#else#define INTRIN_WORDSIZE    16
#endif

  有一点需要注意,根据C99标准——
对于纯C程序来说,PTRDIFF_MAX等宏默认是启用的。
但对于C++程序,PTRDIFF_MAX等宏默认不启用。只有在引入stdint.h之前定义了__STDC_LIMIT_MACROS,才会启用这些宏。

  当发现没有PTRDIFF_MAX等宏时,可以这样报告错误——

#include "stdint.h"
#if !defined(PTRDIFF_MAX) || !defined(INT32_MAX)
#error Need C99 marcos: __STDC_LIMIT_MACROS.
#endif

1.3 其他改进

  gcc不再引入cpuid.h。这是因为难以判断cpuid.h是否存在。而使用ccpuid模块能更方便的判断cpu指令集。

  不再假定未来VC版本支持AVX2等指令集。这是为了避免潜在的错误,宁缺毋滥。

  调整了一下INTRIN_常数的顺序。

二、全部代码

2.1 zintrin.h

  全部代码——

View Code

#ifndef __ZINTRIN_H_INCLUDED
#define __ZINTRIN_H_INCLUDED#include "stdint.h"
#if !defined(PTRDIFF_MAX) || !defined(INT32_MAX)
#error Need C99 marcos: __STDC_LIMIT_MACROS.
#endif// INTRIN_WORDSIZE: 目标机器的字长.
#if PTRDIFF_MAX >= INT64_MAX#define INTRIN_WORDSIZE    64
#elif PTRDIFF_MAX >= INT32_MAX#define INTRIN_WORDSIZE    32
#else#define INTRIN_WORDSIZE    16
#endif// 根据不同的编译器做不同的处理.
#if defined(__GNUC__)    // GCC#if (defined(__i386__) || defined(__x86_64__) )// header files//#include <cpuid.h>    // mac下有时找不到. 于是放弃, 使用ccpuid模块会更方便.//#include <x86intrin.h>    // mac下有时找不到. 于是根据宏来加载头文件.// macros
        #ifdef __MMX__#define INTRIN_MMX    1#include <mmintrin.h>#endif#ifdef __3dNOW__#define INTRIN_3dNOW    1#include <mm3dnow.h>#endif#ifdef __SSE__#define INTRIN_SSE    1#include <xmmintrin.h>#endif#ifdef __SSE2__#define INTRIN_SSE2    1#include <emmintrin.h>#endif#ifdef __SSE3__#define INTRIN_SSE3    1#include <pmmintrin.h>#endif#ifdef __SSSE3__#define INTRIN_SSSE3    1#include <tmmintrin.h>#endif#ifdef __SSE4_1__#define INTRIN_SSE4_1    1#include <smmintrin.h>#endif#ifdef __SSE4_2__#define INTRIN_SSE4_2    1#include <nmmintrin.h>#endif#ifdef __SSE4A__#define INTRIN_SSE4A    1#include <ammintrin.h>#endif#ifdef __AES__#define INTRIN_AES    1#include <x86intrin.h>#endif#ifdef __PCLMUL__#define INTRIN_PCLMUL    1#include <x86intrin.h>#endif#ifdef __AVX__#define INTRIN_AVX    1#include <x86intrin.h>#endif#ifdef __AVX2__#define INTRIN_AVX2    1#include <x86intrin.h>#endif#ifdef __F16C__#define INTRIN_F16C    1#include <x86intrin.h>#endif#ifdef __FMA__#define INTRIN_FMA    1#include <x86intrin.h>#endif#ifdef __FMA4__#define INTRIN_FMA4    1#include <x86intrin.h>#endif#ifdef __XOP__#define INTRIN_XOP    1#include <xopintrin.h>#endif#ifdef __LWP__#define INTRIN_LWP    1#include <x86intrin.h>#endif#ifdef __RDRND__#define INTRIN_RDRND    1#include <x86intrin.h>#endif#ifdef __FSGSBASE__#define INTRIN_FSGSBASE    1#include <x86intrin.h>#endif#ifdef __POPCNT__#define INTRIN_POPCNT    1#include <popcntintrin.h>#endif#ifdef __LZCNT__#define INTRIN_LZCNT    1#include <x86intrin.h>#endif#ifdef __TBM__#define INTRIN_TBM    1#include <x86intrin.h>#endif#ifdef __BMI__#define INTRIN_BMI    1#include <x86intrin.h>#endif#ifdef __BMI2__#define INTRIN_BMI2    1#include <x86intrin.h>#endif#endif    //#if (defined(__i386__) || defined(__x86_64__) )#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_POPCNT    1    // nmmintrin.h#define INTRIN_SSE4A    1    // intrin.h#define INTRIN_LZCNT    1    // intrin.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    1    //TODO:待查证, 注释掉.//#define INTRIN_FMA    1//#define INTRIN_F16C    1//#define INTRIN_RDRND    1//#define INTRIN_FSGSBASE    1//#define INTRIN_TBM    1//#define INTRIN_BMI    1//#define INTRIN_BMI2    1#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

2.2 testzintrin.c

  全部代码——

View Code

#define __STDC_LIMIT_MACROS    1    // C99整数范围常量. [仅演示, 纯C程序可以不用, 而C++程序必须定义该宏.]#include <stdio.h>#include "zintrin.h"#define PT_MAKE_STR(x)    { #x, PT_MAKE_STR_ESC(x) }
#define PT_MAKE_STR_ESC(x)    #xtypedef struct tagMACRO_T
{const char *name;const char *value;
} MACRO_T;/* Intrinsics */
const MACRO_T g_intrins[] =
{{"[Intrinsics]", ""},#ifdef INTRIN_MMXPT_MAKE_STR(INTRIN_MMX),
#endif#ifdef INTRIN_3dNOWPT_MAKE_STR(INTRIN_3dNOW),
#endif#ifdef INTRIN_SSEPT_MAKE_STR(INTRIN_SSE),
#endif#ifdef INTRIN_SSE2PT_MAKE_STR(INTRIN_SSE2),
#endif#ifdef INTRIN_SSE3PT_MAKE_STR(INTRIN_SSE3),
#endif#ifdef INTRIN_SSSE3PT_MAKE_STR(INTRIN_SSSE3),
#endif#ifdef INTRIN_SSE4_1PT_MAKE_STR(INTRIN_SSE4_1),
#endif#ifdef INTRIN_SSE4_2PT_MAKE_STR(INTRIN_SSE4_2),
#endif#ifdef INTRIN_SSE4APT_MAKE_STR(INTRIN_SSE4A),
#endif#ifdef INTRIN_AESPT_MAKE_STR(INTRIN_AES),
#endif#ifdef INTRIN_PCLMULPT_MAKE_STR(INTRIN_PCLMUL),
#endif#ifdef INTRIN_AVXPT_MAKE_STR(INTRIN_AVX),
#endif#ifdef INTRIN_AVX2PT_MAKE_STR(INTRIN_AVX2),
#endif#ifdef INTRIN_F16CPT_MAKE_STR(INTRIN_F16C),
#endif#ifdef INTRIN_FMAPT_MAKE_STR(INTRIN_FMA),
#endif#ifdef INTRIN_FMA4PT_MAKE_STR(INTRIN_FMA4),
#endif#ifdef INTRIN_XOPPT_MAKE_STR(INTRIN_XOP),
#endif#ifdef INTRIN_LWPPT_MAKE_STR(INTRIN_LWP),
#endif#ifdef INTRIN_RDRNDPT_MAKE_STR(INTRIN_RDRND),
#endif#ifdef INTRIN_FSGSBASEPT_MAKE_STR(INTRIN_FSGSBASE),
#endif#ifdef INTRIN_POPCNTPT_MAKE_STR(INTRIN_POPCNT),
#endif#ifdef INTRIN_LZCNTPT_MAKE_STR(INTRIN_LZCNT),
#endif#ifdef INTRIN_TBMPT_MAKE_STR(INTRIN_TBM),
#endif#ifdef INTRIN_BMIPT_MAKE_STR(INTRIN_BMI),
#endif#ifdef INTRIN_BMI2PT_MAKE_STR(INTRIN_BMI2),
#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());printf("testzintrin v1.01 (%dbit)\n\n", INTRIN_WORDSIZE);print_MACRO_T(g_intrins, sizeof(g_intrins)/sizeof(g_intrins[0]));// _mm_malloc
#ifdef INTRIN_SSEif(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_SSEif(1){__m128 xmm1;float f;printf("&xmm1:\t%ph\n", &xmm1);xmm1 = _mm_setzero_ps();    // SSE instruction: xorpsf = _mm_cvtss_f32(xmm1);printf("_mm_cvtss_f32:\t%f\n", f);}
#endif// popcnt
#ifdef INTRIN_POPCNTprintf("popcnt(0xffffffffu):\t%u\n", _mm_popcnt_u32(0xffffffffu));#if INTRIN_WORDSIZE>=64printf("popcnt(0xffffffffffffffffull):\t%u\n", (int)_mm_popcnt_u64(0xffffffffffffffffull));#endif
#endifreturn 0;
}

2.3 makefile

  全部代码——

View Code

# flags
CC = gcc
CFS = -Wall
LFS = # args
RELEASE =0
BITS =
CFLAGS = -msse# [args] 生成模式. 0代表debug模式, 1代表release模式. make RELEASE=1.
ifeq ($(RELEASE),0)# debugCFS += -g
else# releaseCFS += -static -O3 -DNDEBUGLFS += -static
endif# [args] 程序位数. 32代表32位程序, 64代表64位程序, 其他默认. make BITS=32.
ifeq ($(BITS),32)CFS += -m32LFS += -m32
elseifeq ($(BITS),64)CFS += -m64LFS += -m64elseendif
endif# [args] 使用 CFLAGS 添加新的参数. make CFLAGS="-mpopcnt -msse4a".
CFS += $(CFLAGS).PHONY : all clean# files
TARGETS = testzintrin
OBJS = testzintrin.oall : $(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版。

参考文献——
《ISO/IEC 9899:1999 (C99)》。ISO/IEC,1999。www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
《Predefined Macros》. http://msdn.microsoft.com/en-us/library/b0084kay(v=vs.110).aspx
《[GCC] The C Preprocessor》中的《3.7.2 Common Predefined Macros》. GNU, 2011. http://gcc.gnu.org/onlinedocs/cpp/Predefined-Macros.html
《兼容C99标准的stdint.h》. http://www.cnblogs.com/zyl910/archive/2012/08/08/c99int.html
《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
《发现Mac OS X的llvm-gcc也是支持intrin函数的》. http://www.cnblogs.com/zyl910/archive/2012/09/27/intrin_mac.html
《[C] zintrin.h : 智能引入intrinsic函数。支持VC、GCC,兼容Windows、Linux、Mac OS X》. http://www.cnblogs.com/zyl910/archive/2012/09/23/zintrin.html

源码下载——
http://files.cnblogs.com/zyl910/zintrin_v101.rar

[C] zintrin.h: 智能引入intrinsic函数 V1.01版。改进对Mac OS X的支持,增加INTRIN_WORDSIZE宏...相关推荐

  1. [C] zintrin.h : 智能引入intrinsic函数。支持VC、GCC,兼容Windows、Linux、Mac OS X

    作者:zyl910. 现在很多编译器支持intrinsic函数,这给编写SSE等SIMD代码带来了方便.但是各个编译器略有差异,于是我编写了zintrin.h,智能引入intrinsic函数. 一.各 ...

  2. [C] 跨平台使用Intrinsic函数范例3——使用MMX、SSE2指令集 处理 32位整数数组求和...

    作者:zyl910. 本文面对对SSE等SIMD指令集有一定基础的读者,以32位整数数组求和为例演示了如何跨平台使用MMX.SSE2指令集.支持vc.gcc编译器,在Windows.Linux.Mac ...

  3. [C] 跨平台使用Intrinsic函数范例1——使用SSE、AVX指令集 处理 单精度浮点数组求和(支持vc、gcc,兼容Windows、Linux、Mac)...

    作者:zyl910. 本文面对对SSE等SIMD指令集有一定基础的读者,以单精度浮点数组求和为例演示了如何跨平台使用SSE.AVX指令集.因使用了stdint.zintrin.ccpuid这三个模块, ...

  4. 虚拟函数-1、静态联编与动态联编,引入虚函数

    在实际开发工作中,为提高代码的重用性,编写通用的功能模块,往往需要设计处理几种不同对象的通用程序,如示例2.1所示. 示例清单2.1 #include "stdio.h" #inc ...

  5. 基于ARM 的neon介绍以及常用intrinsic函数总结

    在介绍NEON前,必须要介绍一下SIMD. 1.什么是simd 众所周知,计算机程序需要编译成指令才能让 CPU 识别并执行运算.所以,CPU 指令处理数据的能力是衡量 CPU 性能的重要指标.为了提 ...

  6. html实现log函数,math。h中的log函数的应用

    以10为底的log函数: 形式为 double  log10(double  x) 以e为底的log函数(即 ln)double log (double x) 如何表达log 以a为底b的对数: 用换 ...

  7. Python 3.x 引入了函数注释

    Python 3.x 引入了函数注释,以增强函数的注释功能,下面是一个普通的自定义函数: def dog(name, age, species):return (name, age, species) ...

  8. 基于群智能算法的函数最值优化问题

    基于群智能算法的函数最值优化问题 摘要 针对求解函数的极值问题的群智能算法,大部分函数在定义域内都可以通过微分的方式求得极值点和找到最值.但是存在一些测试函数,他们的最值用求解的微分的方式只能使得计算 ...

  9. stdio.h里的一些函数

    stdio.h里的一些函数 fopen(file,"打开类型");r:read w:write b:binary(二进制) +:增加r:打开文本文件,只读r+:打开文本文件,读写w ...

最新文章

  1. linux longlong大小,Linux基本数据类型大小——int,char,long int,long long int
  2. python csv模块 一次读多行_python中csv模块读取reader只能读取一次
  3. 到2030年,智能农业或将养活85亿人!但网络安全威胁需要重视
  4. 迪克森沉思录之做Global SAP项目的弊端
  5. asp服务器推送消息,asp.net实时向客户端推送消息(SignalRWeb)
  6. 你真的知道Python的字符串是什么吗?
  7. Spring系列之一 Spring MVC
  8. HttpModule
  9. Asterisk标准通道变量
  10. requests中获取请求到文本编码格式
  11. SPH(光滑粒子流体动力学)流体模拟实现三:Marching Cube算法(1)
  12. Python深入理解yield
  13. NOIP2015题解
  14. 100道Python经典练习题.pdf(附答案)
  15. java经典算法(一)——zws
  16. 威金蠕虫(网吧杀手)肆虐互联网 九千用户十余企业遭攻击
  17. (转)Intel Atom处理器详细指标及市场前景
  18. 如何快速在PDF文件中插入图片
  19. 微商竟然靠这样引流?佛山抖音培训老师告诉你其中奥秘
  20. 【区间dp】关路灯 牛客网题解

热门文章

  1. sorry for yesterday
  2. NLayerAppV3-Distributed Service Layer(分布式服务层)
  3. POI 2018.10.21
  4. Linux远程远程控制程序TeamViewer
  5. 分析器错误(在浏览器中查看.aspx)
  6. 关于C# WinForm中进度条的实现方法
  7. WP7多国语言支持 from:http://blog.csdn.net/lee353086/article/details/6260676
  8. 窗口缩放导致页面排版错乱的解决方法
  9. 深度解析 H.265 视频解决方案
  10. Keil 5出现Error: L6218E: Undefined symbol解决方法