【问题标题】:Are there equivalents for the GNU __builtin_ia32 functions (for the Visual Studio Compiler)?GNU __builtin_ia32 函数(用于 Visual Studio 编译器)是否有等价物?
【发布时间】:2016-11-28 09:29:26
【问题描述】:

我想移植一个现有的 C++ 代码,该代码已针对使用 GNU 编译器运行向量操作进行了优化,以使用 Visual Studio 编译器进行编译。

本程序使用专门的 GNU 单指令多数据 (SIMD) 内在指令(参见例如 GCC - Vector Extensions)。

由于这些内在函数似乎只是 GNU 编译器,如果有人知道是否有办法将数据类型和函数移植到其他编译器(在我的例子中为 msvc12),我将非常高兴。

基本上有两个但非常密切相关的问题。 1. 可以为其他编译器以类似的方式构造以下数据类型吗? (这些是 16 字节变量,例如包含四个 int 或十六个 char。)

   // Integer types
   typedef char     v16qi __attribute__ ((vector_size (16), aligned (16)));
   typedef short     v8hi __attribute__ ((vector_size (16), aligned (16)));
   typedef int       v4si __attribute__ ((vector_size (16), aligned (16)));
   typedef long long v2di __attribute__ ((vector_size (16), aligned (16)));

   // Floating point types
   typedef float     v4sf __attribute__ ((vector_size (16), aligned (16)));
   typedef double    v2sf __attribute__ ((vector_size (16), aligned (16)));
  1. 在哪里可以找到以下函数的描述和独立于编译器的等效项?

    __builtin_ia32_loaddqu, __builtin_ia32_paddsb128, __builtin_ia32_paddusb128, __builtin_ia32_pavgb128, __builtin_ia32_pcmpgtb128, __builtin_ia32_pmovmskb128, __builtin_ia32_psadbw128, __builtin_ia32_psrlwi128, __builtin_ia32_psubsb128, __builtin_ia32_psubusb128, __builtin_ia32_punpckhbw128, __builtin_ia32_pxor128, __builtin_ia32_storedqu

我已经深入搜索了这个主题,但找不到我的问题的直接答案。我知道存在与 msvc12 一起使用的数据类型,例如 __m128__m128i__m128d(参见例如 Microsoft Developer Network - Streaming SIMD Extensions (SSE)),但我无法将两者结合在一起。

是否可以“简单地”替换 typedefs 和 __builtin_ia32 函数?

如果我应该对任何细节更具体,请发表评论。我试图让问题简短。 如果有任何帮助,我将不胜感激!非常感谢您的回答。

【问题讨论】:

  • AFAIK,如果您需要在 MSVC 上进行手动矢量化,最好的办法是重写代码以使用 Intel 的内在函数。使用 __m128i 数据类型和像 _mm_add_epi32 这样的内在函数。见software.intel.com/sites/landingpage/IntrinsicsGuide。 (以及x86 tag wiki 中的其他链接)。
  • AFAIK,MSVC 没有像 typedef short v8hi __attribute__ ((vector_size (16), aligned (16))); 这样的东西,可以让您使用 + 运算符来获取 PADDW。但是Agner Fog's (GPLed) vectorclass library 确实提供了 v4si 和 C++ 运算符重载等类。它至少可以移植到 MSVC、gcc、clang 和 icc。
  • 非常感谢您的回复,@PeterCordes!事实上,使用v8hi c = a + b 之类的东西非常方便。我会看看你提到的vectorclass库,它似乎真的很好。这和您答案中的链接将帮助我继续。坦克!
  • 请记住,Agner 的矢量类库是 GPL 的,因此您不能在闭源项目中使用它。还有其他类似的 SIMD 封装库,但我没有看过。

标签: c++ gcc simd intrinsics


【解决方案1】:

我可以避免代码中的一些函数。对于其余部分,以下为我完成了工作(我终于可以识别 emmintrin.h 中的相应函数以及 MinGW gcc 编译器的包含目录中的类似文件)与 @PeterCordes 评论的 Agner Fog 的矢量类库相结合on(感谢您的帮助)。

#ifdef _MSC_VER
#define __builtin_ia32_psadbw128(_A, _B)  _mm_sad_epu8((__m128i) _A, (__m128i) _B)
#define __builtin_ia32_paddsb128(_A, _B)  _mm_adds_epi8((__m128i) _A, (__m128i) _B)
#define __builtin_ia32_pmovmskb128(_A)    _mm_movemask_epi8((__m128i) _A)
#define __builtin_ia32_pcmpgtb128(_A, _B) _mm_cmpgt_epi8((__m128i) _A, (__m128i) _B)
#define __builtin_ia32_psubsb128(_A, _B)  _mm_subs_epi8((__m128i) _A, (__m128i) _B)
#define __builtin_ia32_psubusb128(_A, _B) _mm_subs_epu8((__m128i) _A, (__m128i) _B)
#define __builtin_ia32_pavgb128(_A, _B)   _mm_avg_epu8((__m128i) _A, (__m128i) _B)
#define __builtin_ia32_paddusb128(_A, _B) _mm_adds_epu8((__m128i) _A, (__m128i) _B)
#define __builtin_ia32_psrlwi128(_A, _B)  _mm_srli_epi16((__m128i) _A, _B)
#define __builtin_popcountll(_X)          _mm_popcnt_u64((unsigned long long) _X)
#endif

可能内联函数会比上面的defines 更优雅。

【讨论】:

  • 大多数人会反其道而行之,在他们的代码中使用英特尔的内在函数。我猜你是用另一种方式做的,所以你可以使用 GNU C 原生向量,所以像 + 这样的运算符使用正确的元素大小。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-31
  • 1970-01-01
  • 1970-01-01
  • 2019-12-15
  • 2011-05-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多