如何在内在函数中使用条件

时间:2016-06-24 06:08:56

标签: c++ visual-c++ compiler-optimization intrinsics

我想使用内在函数比较两个浮点变量。如果比较是真的,做其他事做点什么。我想这样做是一个正常的if..else条件。有没有办法使用内在函数?

//normal code
vector<float> v1, v2;
for(int i = 0; i < v1.size(); ++i)
if(v1[i]<v2[i])
{
    //do something
}
else
{
    //do something
)

如何使用SSE2或AVX执行此操作?

3 个答案:

答案 0 :(得分:1)

使用无分支技术完成SIMD条件操作。您可以使用压缩比较指令来获取全零或全一的元素向量。

e.g。当相应的元素匹配具有以下代码的条件时,您可以有条件地将4添加到累加器中的元素:

__m128i match_counts = _mm_setzero_si128();

for (...) {
    __m128  fvec = something;
    __m128i  condition = _mm_castps_si128( _mm_cmplt_ps(fvec, _mm_setzero_ps()) );  // for elements less than zero
    __m128i masked_constant = _mm_and_si128(condition, _mm_set1_epi32(4));
    match_counts = _mm_add_epi32(match_counts, masked_constant);
}

显然,只有你能想出一个无分支的方式去做分支的两边,这才有效。混合指令通常可以提供帮助。

如果分支的每一侧都有太多的工作,你可能根本不会获得任何加速,特别是如果你的元素大小是4字节或更大。 (当您在16个独立字节上并行执行16次操作时,SIMD非常强大,在4个32位元素上执行4次操作时效率较低)。

答案 1 :(得分:1)

如果你期望v1[i] < v2[i]几乎永远不会真实,或者通常长期保持不变(即使整体上可能没有特别的偏见),那么另一种技术也适用于提供&#34;真正的条件&#34; (即不是&#34;两者都做,丢弃一个结果&#34;),当然是一个价格,但你也可以实际跳过工作而不是忽略一些结果。

该技术相当简单,进行比较(矢量化),将比较掩码与_mm_movemask_ps一起收集,然后你有3个案例:

  • 所有比较都采用相同的方式,它们都是false,执行适当的&#34;做某事&#34;现在的代码可能更容易向量化,因为条件消失了。
  • 所有比较都采用相同的方式,它们都是true,相同。
  • 混合,使用更复杂的逻辑。根据您的需要,您可以单独检查所有位(回退到标量代码,但现在只需1 FP比较整个批次),或者使用其中一个&#34;仅迭代(非)设置位&#34 ;技巧(与bitscan很好地结合以恢复实际索引),或者有时你可以像往常一样回到掩蔽和合并。

并非所有3个案例总是相关的,通常你会应用这个,因为谓词几乎总是以相同的方式,使得其中一个&#34;全部相同&#34;这种情况非常罕见,你可以把它与#34;混合&#34;。

混在一起

这种技术绝对不是很有用。 &#34;混合&#34;案件复杂而缓慢。快速路径必须通用且速度足以值得测试您是否可以接受它。

但是它可能很有用,也许其中一个方面非常缓慢和烦人,而分支的另一面是很好的简单的可矢量化代码,相比之下并没有那么长的时间。例如,对于快速近似的超越函数,慢速方可能需要进行参数约简,或者可能必须在获取点积之前对某些向量进行标准化,或者使矩阵正交化,甚至可能从磁盘获取数据。

或者,也许两方都不是很慢,但是他们从缓存中驱逐了彼此的数据(可能两边都是一个适合缓存的数组的循环,但数组并不适合它们)这样做他们无条件地放慢了他们两个。这可能是一个真实的东西,但我还没有在野外看到它(还)。

或者,也许一方无法无条件地执行,做一些通常具有破坏性的事情,甚至可能是一些IO。例如,如果您正在检查错误情况并记录它们。

答案 2 :(得分:0)

我找到了一个对条件SIMD指令非常有用的文档。 这是我的问题的完美解决方案。 If...else condition

文件:http://saluc.engr.uconn.edu/refs/processors/intel/sse_sse2.pdf