确定激活哪个内部标志

时间:2014-12-01 00:18:55

标签: c++ gcc sse intrinsics

在详细说明之前,我有以下功能,

  

设_e,_w是一个大小相等的数组。设_stepSize是浮点类型。

void GradientDescent::backUpWeights(FLOAT tdError) {
  AI::FLOAT multiplier = _stepSize * tdError;
  for (UINT i = 0; i < n; i++){
    _w[i] += _e[i]*multiplier
  }

  // Assumed that the tilecode ensure that _w.size() or _e.size() is even.
}

这个功能很好,但如果一个cpu有内在的,特别是对于这个例子,SSE4,那么下面的函数允许我关闭秒(对于相同的输入),即使已经包含-O3 gcc标志和为这一个添加了额外的-msse4a。

void GradientDescent::backUpWeights(FLOAT tdError) {
  AI::FLOAT multiplier = _stepSize * tdError;
  __m128d multSSE = _mm_set_pd(multiplier, multiplier);
  __m128d* eSSE = (__m128d*)_e;
  __m128d* wSSE = (__m128d*)_w;
  size_t n = getSize()>>1;
  for (UINT i = 0; i < n; i++){
    wSSE[i] = _mm_add_pd(wSSE[i],_mm_mul_pd(multSSE, eSSE[i]));
  }

  // Assumed that the tilecode ensure that _w.size() or _e.size() is even.
}

问题:

我现在的问题是我想要这样的东西,

void GradientDescent::backUpWeights(FLOAT tdError) {
AI::FLOAT multiplier = _stepSize * tdError;
#ifdef _mssa4a_defined_
  __m128d multSSE = _mm_set_pd(multiplier, multiplier);
  __m128d* eSSE = (__m128d*)_e;
  __m128d* wSSE = (__m128d*)_w;
  size_t n = getSize()>>1;
  for (UINT i = 0; i < n; i++){
    wSSE[i] = _mm_add_pd(wSSE[i],_mm_mul_pd(multSSE, eSSE[i]));
  }
#else  // No intrinsic
  for (UINT i = 0; i < n; i++){
    _w[i] += _e[i]*multiplier
  }
#endif

  // Assumed that the tilecode ensure that _w.size() or _e.size() is even.
}

因此,如果在gcc中,我声明-msse4a来编译这段代码,那么它将选择编译if语句中的代码。当然,我的计划是为所有内在实现它,而不仅仅是上面的SSE4A。

2 个答案:

答案 0 :(得分:3)

GCC,ICC(在Linux上)和Clang具有以下编译选项和相应的定义

options       define
-mfma         __FMA__
-mavx2        __AVX2__
-mavx         __AVX__
-msse4.2      __SSE4_2__
-msse4.1      __SSE4_1__
-mssse3       __SSSE3__
-msse3        __SSE3__
-msse2        __SSE2__
-m64          __SSE2__
-msse         __SSE__    

GCC和Clang中的选项和定义,但ICC中没有:

-msse4a       __SSE4A__
-mfma4        __FMA4__
-mxop         __XOP__

AVX512选项,在最近版本的GCC,Clang和ICC中定义

-mavx512f     __AVX512F__    //foundation instructions
-mavx512pf    __AVX512PF__   //pre-fetch instructions
-mavx512er    __AVX512ER__   //exponential and reciprocal instructions 
-mavx512cd    __AVX512CD__   //conflict detection instructions

AVX512选项将likely be in GCC, Clang, and ICC soon (if not already)

-mavx512bw    __AVX512BW__   //byte and word instructions
-mavx512dq    __AVX512DQ__   //doubleword and quadword Instructions
-mavx512vl    __AVX512VL__   //vector length extensions

请注意,其中许多交换机可以启用更多:例如-mfma启用并定义AVX2,AVX,SSE4.2 SSE4.1,SSSE3,SSE3,SSE2,SSE。

对于AVX512的ICC编译器选项,我不是100%。它可以是-xMIC-AVX512而不是-mavx512f

MSVC only appears to define __AVX__ and __AVX2__

在您的情况下,您的代码似乎只使用SSE2,因此如果您在64位模式下编译(这是64位用户空间中的默认模式或使用-m64显式编译),那么__SSE2__被定义为。但是,由于您使用了-msse4a,因此也会定义__SSE4A__

请注意,启用指令与确定指令集是否可用不同。如果您希望代码在多个指令集上工作,那么I suggest a CPU dispatcher

答案 1 :(得分:0)

我后来才知道没有办法做到这一点。这是一个简单而优雅的方式。对于带有sse4a内在函数的x86-64平台,请执行以下命令make-rule(假设您在build / *中的src / intrinsic /和build( .o文件)中存储内部源代码): p>

CXX=g++ -O3
CXXFLAGS=-std=c++14 -Wunused
CPPFLAGS=
CPP_INTRINSIC_FLAG:=-ffast-math

INTRINSIC_OBJECT := $(patsubst src/intrinsic/%.cpp,build/%.o,$(wildcard src/intrinsic/*.cpp))

x86-64-sse4: $(eval CPP_INTRINSIC_FLAG+=-msse4a -DSSE4A) $(INTRINSIC_OBJECT)

# Intrinsic objects
build/%.o: src/intrinsic/%.cpp
    $(CXX) $(CXXFLAGS) -c $(CPPFLAGS) $(CPP_INTRINSIC_FLAG) $(INCLUDE_PATHS) $^ -o $@