【问题标题】:Compiling SSE intrinsics in GCC gives an error在 GCC 中编译 SSE 内在函数会出错
【发布时间】:2014-04-02 09:14:39
【问题描述】:

我的 SSE 代码在 Windows 平台上运行良好,但是当我在 Linux 上运行它时,我遇到了很多问题。其中之一是:

这只是我的代码的示例说明:

int main(int ref, int ref_two)

{

 __128i a, b;

a.m128i_u8[0] = ref;

b.m128i_u8[0]  = ref_two;

.

.


.

.....

}

错误 1:

错误:在非结构或联合的情况下请求成员“m128i_u8”

在此线程中,它提供了使用适当的 _mm_set_XXX 内在函数而不是上述方法的解决方案,因为它仅适用于 Microsoft。 SSE intrinsics compiling MSDN code with GCC error?

我尝试了线程中提到的上述方法,我已经在我的程序中替换了 set 指令,但它严重影响了我的应用程序的性能。

我的代码很大,需要在 2000 处进行更改。所以我正在寻找更好的替代方案,而不影响我的应用程序的性能。

最近我从 Intel 获得了这个链接,上面说使用 -fms-diaelect 选项将其从 Windows 移植到 Linux。

http://software.intel.com/sites/products/documentation/doclib/iss/2013/compiler/cpp-lin/GUID-7A69898B-BDBB-4AA9-9820-E4A590945903.htm

有人试过上面的方法吗?有人找到将大型代码移植到 Linux 的解决方案吗?


@Paul,这是我的代码,我已经放置了一个计时器来测量这两种方法所花费的时间,结果令人震惊。

代码 1:115 毫秒(Microsoft 方法直接访问元素)

代码 2:151 毫秒(使用 set 指令)

我在代码中使用 set 时花费了 36 毫秒。

注意:如果我在我的单个指令中替换它需要 36 毫秒,想象一下如果我在我的程序中替换它 2000 次会导致性能下降。

这就是我正在寻找比设置指令更好的替代方案的原因

代码 1:

__m128i array;
unsigned char* temp_src;
unsigned char* temp_dst;

for (i=0; i< 20; i++)

{

for (j=0; j< 1600; j+= 16)

 {
   Timerstart(&x);  
   array =  _mm_loadu_si128 ((__m128i *)(src));
   array.m128i_u8[0] =  36;
   y+ = Timerstop(x);
   _mm_store_si128( (__m128i *)temp_dst,array);

  }
 }

代码2:

 __m128i array;
 unsigned char* temp_src;
 unsigned char* temp_dst;

 for (i=0; i< 20; i++)
 {
 for (j=0; j< 1600; j+= 16)

 {



       Timerstart(&x);
       array = _mm_set_epi8(*(src+15),*(src+14),*(src+13),*(src+12),
                             *(src+11),*(src+10),*(src+9), *(src+8),
                         *(src+7), *(src+6), *(src+5), *(src+4),
                             *(src+3), *(src+2), *(src+1), 36 );
       y+ = Timerstop(x);

       _mm_store_si128( (__m128i *)temp_dst,array);

  }
}

【问题讨论】:

  • 英特尔从未添加直接访问元素的标准方法是有原因的:因为实际上没有有效的方法来实现它。 (涉及 SSE4.1 插入/提取的例外情况)
  • 当一个编译器做了魔法并且您想在其他编译器上模仿它时,首先要做的是检查生成的程序集,以便您确切地知道那个魔法是什么。请注意,gcc 具有类似(甚至更短)的语法来访问向量的第 k 个元素,但 VS 不知道那个。

标签: gcc x86 intel sse simd


【解决方案1】:

您正在尝试使用非便携式 Microsoft 主义。只需坚持更便携的内在函数,例如_mm_set_epi8:

 __128i a = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ref);

这适用于所有平台和编译器。

如果您发现性能问题,那可能是因为您在循环中执行了一些低效的操作 - 没有看到实际代码,尽管无法就提高代码效率提出任何具体建议。

编辑

通常有更有效的方法来加载具有值组合的向量,例如在您的示例中,例如:

#include "smmintrin.h" // SSE4.1

for (...)
{
    for (...)
    {
        __m128i v = _mm_loadu_si128(0, (__m128i *)src); // load vector from src..src+15
        v = _mm_insert_epi8(v, 0, 36);                  // replace element 0 with constant `36`
       _mm_storeu_si128((__m128i *)dst, v);             // store vector at dst..dst+15
    }
}

这意味着只有 3 条指令。 (注意:如果您不能假设 SSE4.1 最小值,那么 _mm_insert_epi8 可以替换为两个按位内在函数 - 这仍然比使用 _mm_set_epi8 更有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 2021-06-10
    • 2011-08-06
    • 2012-01-28
    • 2016-10-16
    • 1970-01-01
    • 2014-12-10
    相关资源
    最近更新 更多