确定激活了哪个内部标志

Determine what intrinsic flag is activated

本文关键字:内部 标志 活了 激活      更新时间:2023-10-16

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

让_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。

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__

在最新版本的 GCC、Clang 和 ICC 中定义的 AVX512 选项

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

AVX512选项可能很快就会出现在GCC,Clang和ICC中(如果还没有的话(:

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

我不是 100% AVX512 的 ICC 编译器选项是什么。它可以是-xMIC-AVX512而不是-mavx512f.

MSVC 似乎只定义了__AVX__和__AVX2__。

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

请注意,启用指令与确定指令集是否可用不同。如果您希望您的代码在多个指令集上运行,那么我建议您使用 CPU 调度程序。

后来我才知道没有办法做到这一点。 不过,一个简单而优雅的方式是这样的。对于具有 sse4a 内部函数的 x86-64 平台,请执行以下 make 目标规则(假设您将内部源存储在 src/intrinsic/中,并将构建(.o 文件(存储在 build/* 中(:

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 $@