【问题标题】:SSE to C++ codeSSE 到 C++ 代码
【发布时间】:2017-09-21 17:40:31
【问题描述】:

我正在尝试将包含 SSE 指令的 c++ 源代码中的代码重写为仅 c++ 代码。我知道我会失去性能,但它是一个实验,我正在尝试执行。 我想知道是否有与 __mm_unpackhi_pd 和 __mm_unpacklo_pd 相同的 C++ 等效项。我对 SSE 的了解为零。

我正在尝试转换的代码的 sn-p 以供参考。任何知识或提示都会有所帮助。谢谢你。

for (unsigned chunk = 0; chunk < chunks; chunk++)
{
  unsigned start = chunk * chunksize;
  unsigned end =
    std::min((chunk + 1) * chunksize, (unsigned)2 * w);
  __m128d a2b2 =
    _mm_load_pd(d_origx +
                ((2 * init_G_offset + start) & n2_m_1));
  unsigned i2_mod_B = 0;
  for (unsigned i = start; i < end; i += 2)
    {
      __m128d ab = a2b2;
      a2b2 =
        _mm_load_pd(d_origx +
                    ((origx_offset + i) & n2_m_1));
      __m128d cd = _mm_load_pd(d_filter + i);

      __m128d cc = _mm_unpacklo_pd(cd, cd);
      __m128d dd = _mm_unpackhi_pd(cd, cd);

      __m128d a0a1 = _mm_unpacklo_pd(ab, a2b2);
      __m128d b0b1 = _mm_unpackhi_pd(ab, a2b2);

      __m128d ac = _mm_mul_pd(cc, a0a1);
      __m128d ad = _mm_mul_pd(dd, a0a1);
      __m128d bc = _mm_mul_pd(cc, b0b1);
      __m128d bd = _mm_mul_pd(dd, b0b1);

      __m128d ac_m_bd = _mm_sub_pd(ac, bd);
      __m128d ad_p_bc = _mm_add_pd(ad, bc);

      __m128d ab_times_cd = _mm_unpacklo_pd(ac_m_bd, ad_p_bc);
      __m128d a2b2_times_cd =
        _mm_unpackhi_pd(ac_m_bd, ad_p_bc);

      __m128d xy = _mm_load_pd(d_x_sampt + i2_mod_B);
      __m128d x2y2 = _mm_load_pd(d_x_sampt + i2_mod_B + 2);

      __m128d st = _mm_add_pd(xy, ab_times_cd);
      __m128d s2t2 = _mm_add_pd(x2y2, a2b2_times_cd);

      _mm_store_pd(d_x_sampt + i2_mod_B, st);
      _mm_store_pd(d_x_sampt + i2_mod_B + 2, s2t2);

      i2_mod_B += 4;
    }
}

【问题讨论】:

  • 我确信这是对术语的迂腐狡辩,但是…… C++代码!当然,它使用 SSE 内在函数,但它仍然是用 C++ 编写的,并且需要 C++ 编译器来编译它。最重要的是,它具有使用 SSE 指令以获得最佳性能的所有优点,没有典型的缺点。唯一的“限制”是它要求您的处理器支持 SSE,这不是很高的标准,只是限制了可移植性。
  • 当然它是一个 c++。我的错。我只是想删除 SSE 指令。

标签: c++ sse intel-ipp


【解决方案1】:

您可以在下面找到这两个函数的描述,我还将每个函数链接到其参考页面。完整的参考资料可以在这里找到:https://software.intel.com/sites/landingpage/IntrinsicsGuide/

_mm_unpackhi_p

__m128d _mm_unpackhi_pd (__m128d a, __m128d b)

解包和交错双精度(64 位)浮点 a 和 b 的高半部分的元素,并将结果存储在 dst 中。


_mm_unpacklo_pd

_m128d _mm_unpacklo_pd (__m128d a, __m128d b)

解包和交错双精度(64 位)浮点 a 和 b 的下半部分的元素,并将结果存储在 dst 中。

【讨论】:

  • 嗨,迈克,谢谢或提供参考链接,实际上我想知道是否有相同的 C/C++ 替代方案,而无需使用 SSE 指令。我希望编译器本身自动矢量化这些东西,而不是使用 SSE 指令。
  • 既然您知道这些函数的作用,您就可以在 C++ 中自己实现它们了。参考包含详细说明。
  • 非常感谢迈克,我真的很感激。最后一个问题。你能告诉我如何用 C++ 编写 src1[127:0]。谢谢。
  • 我假设它代表来自src1 的第 127 位到第 0 位。我不知道__m128d 是如何表示的,我也不知道如何解释字节序。您应该创建一个新问题。
【解决方案2】:

具体如何实现它取决于你的表示,但基本上你返回一个由a 的高(或低)一半与b 的高(或低)一半连接组成的新值。例如:

typedef double[2] __m128d;

__m128d _mm_unpackhi_pd(__m128d a, __m128d b) {
  __m128d res;
  res[0] = a[1];
  res[1] = b[1];
  return res;
}

__m128d _mm_unpacklo_pd(__m128d a, __m128d b) {
  __m128d res;
  res[0] = a[0];
  res[1] = b[0];
  return res;
}

这个问题的时间很奇怪……我在为SIMDe 实现这个功能时发现了这个问题,而且它只有 17 天。如果您想使用 SIMDe 作为参考,这些函数在 sse2.h 以及许多其他函数中。 SIMDe 中的代码比上面的要复杂一些,但这主要是为了匹配其他 _mm_unpack* 函数的实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-16
    • 1970-01-01
    • 2012-03-27
    相关资源
    最近更新 更多