【问题标题】:How to compare the upper double-precision floating-point element with SSE如何将高位双精度浮点元素与 SSE 进行比较
【发布时间】:2015-03-22 00:26:51
【问题描述】:

我正在寻找一种方法来比较两个 __m128d 变量的上部。 因此,我查找 https://software.intel.com/sites/landingpage/IntrinsicsGuide/ 的相关内在函数。

但我只能找到一些内在函数比较两个变量之间的下部,例如_mm_comieq_sd

我想知道为什么没有关于比较上部的内在函数,更重要的是,如何比较两个 __m128d 变量之间的上部?


更新:

代码是这样的

    j0     =  jprev0;
    j1     =  jprev1;

    t_0    =  p_i_x - pj_x_0;
    t_1    =  p_i_x - pj_x_1;
    r2_0   =  t_0 * t_0;
    r2_1   =  t_1 * t_1;

    t_0    =  p_i_y - pj_y_0;
    t_1    =  p_i_y - pj_y_1;
    r2_0  +=  t_0 * t_0;
    r2_1  +=  t_1 * t_1;

    t_0    =  p_i_z - pj_z_0;
    t_1    =  p_i_z - pj_z_1;
    r2_0  +=  t_0 * t_0;
    r2_1  +=  t_1 * t_1;

    #if NAMD_ComputeNonbonded_SortAtoms != 0 && ( 0 PAIR ( + 1 ) )
    sortEntry0 = sortValues + g; 
    sortEntry1 = sortValues + g + 1; 
    jprev0 = sortEntry0->index;
    jprev1 = sortEntry1->index;
    #else
    jprev0     =  glist[g  ];
    jprev1     =  glist[g+1];
    #endif

    pj_x_0     =  p_1[jprev0].position.x;
    pj_x_1     =  p_1[jprev1].position.x;
    pj_y_0     =  p_1[jprev0].position.y; 
    pj_y_1     =  p_1[jprev1].position.y;
    pj_z_0     =  p_1[jprev0].position.z; 
    pj_z_1     =  p_1[jprev1].position.z;

    // want to use sse to compare those
    bool test0 = ( r2_0 < groupplcutoff2 );
    bool test1 = ( r2_1 < groupplcutoff2 );

    //removing ifs benefits on many architectures
    //as the extra stores will only warm the cache up
    goodglist [ hu         ] = j0;
    goodglist [ hu + test0 ] = j1;

    hu += test0 + test1;

我正在尝试用 SSE 重写它。

【问题讨论】:

  • 为什么不进行打包比较,只使用顶部比较的结果?
  • @Mysticial 这是我的 B 计划 :)
  • 有几种方法可以做到这一点(例如_mm_comieq_sd(_mm_shuffle_ps(x,x,0xee))),但如果你展示你正在尝试做的事情,你的问题可能会更有趣。可能有比你现在做的更有效的方法。
  • @Mysticial,我刚刚注意到原始标签是 SSE,然后您将其更改为 SSE2,现在我已将其更改回 SSE。我将 SSE 标签视为涵盖 SSE-SSE4.2 的通用标签。 SSE2 标签只有 10% 的问题是 SSE。但我也比我更相信你的判断。我应该将其保留为 SSE2 吗?
  • @Zboson 哦,我将其更改为 SSE2,因为 SSE 没有 OP 所要求的双精度。不过,我对此并没有特别强烈的感觉。无论如何,SSE 标签都是一团糟。

标签: c intel sse simd intrinsics


【解决方案1】:

你问的是在比较了下半部分之后如何比较上半部分。

进行比较的 SIMD 方法是使用打包比较指令,例如 __m128d _mm_cmplt_pd (__m128d a, __m128d b),它会生成掩码作为输出而不是设置标志。 AVX 有一个改进的vcmppd / vcmpps,它有更广泛的比较运算符选择,您可以将其作为第三个参数传递。 _mm_cmp_pd (__m128d a, __m128d b, const int imm8).

const __m128d groupplcutoff2_vec = _mm_broadcastsd_pd(groupplcutoff2);
// should emit SSE3 movddup like _mm_movedup_pd() would.

__m128d r2 = ...;

// bool test0 = ( r2_0 < groupplcutoff2 );
// bool test1 = ( r2_1 < groupplcutoff2 );
__m128d ltvec = _mm_cmplt_pd(r2, groupplcutoff2_vec);
int ltmask = _mm_movemask_pd(ltvec);

bool test0 = ltmask & 1;
// bool test1 = ltmask & 2;

// assuming j is double.  I'm not sure from your code, it might be int.
// and you're right, doing both stores unconditionally is prob. fastest, if your code isn't heavy on stores.
// goodglist [ hu         ] = j0;
_mm_store_sd (goodglist [ hu         ], j);
// goodglist [ hu + test0 ] = j1;
_mm_storeh_pd(goodglist [ hu + test0 ], j);
// don't try to use non-AVX _mm_maskmoveu_si128, it's like movnt.  And doesn't do exactly what this needs, anyway, without shuffling j and ltvec.

// hu += test0 + test1;
hu += _popcnt32(ltmask);  // Nehalem or later.  Check the popcnt CPUID flag

popcnt 技巧与 AVX 一样有效(在 ymm 寄存器中包含 4 个双精度数)。 Packed-compare -> movemask 和使用位操作是一个需要牢记的有用技巧。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-25
    • 2012-11-21
    • 1970-01-01
    相关资源
    最近更新 更多