如何在很多条件下对循环进行矢量化?

时间:2015-11-28 12:31:25

标签: c++ vectorization sse simd

我有以下循环。目标是在数组tmp的所有元素之间执行操作,并将其存储在标量b中。该操作等同于添加,因此没有特定的执行顺序。例如,如果我们有+ b + c + d,我们可以按任何顺序计算它,这意味着(a + b)+(c + d)也是可能的。这同样适用于此操作。但是,有一些特殊条件会以不同的方式导致结果。

tmp.eb.elongs,而tmp.xb.xdoubles

是否有任何形式可以比较所有tmp.e,例如对SSE的2对,并相应地执行b.x的正确计算。在所有情况下,它都可以被视为addMul,在第一种情况下,它只是乘以1,在其他情况下乘以0或BOUND。有可能对此进行矢量化吗?如果是这样,怎么样?

感谢。

void op(vec& tmp, scalar& b)
{
    for (i = 1; i < n; ++i)
    {
        if (b.e == tmp.e[i])
        {
            b.x += tmp.x[i];
            b.normalize();
            continue;
        }
        else if (b.e > tmp.e[i])
        {
            if (b.e > tmp.e[i]+1)
            {
                continue;
            }
            b.x += tmp.x[i] * BOUND;
            b.normalize();
        }
        else
        {
            if (tmp.e[i] > b.e+1)
            {
                b.x = tmp.x[i]; 
                b.e = tmp.e[i];
                b.normalize();
                continue;
            }
            b.x = b.x * BOUND + tmp.x[i];
            b.e = tmp.e[i];
            b.normalize();
        }
    }
}

1 个答案:

答案 0 :(得分:3)

SIMD代码中的每个元素条件通常通过使用压缩比较指令来处理,以生成全零和全一元素的掩码。您可以将此用于AND或OR向量。所以例如您可以通过使用AND来仅增加通过测试的元素,以生成一个向量,其中元素应该递增1,而元素不应该递增0,因为0是加法的标识值。 (x + 0 = x)。

您还可以根据蒙版计算两个结果,然后将它们混合在一起。 (使用AND和OR,或使用向量混合指令。)

这种做SIMD条件的方法就像cmov:你必须计算分支的两边,即使你在向量中处理的所有元素都占据了分支的同一侧。

您的数据看起来已经是数组结构格式。因此,您可以根据e值的向量对操作生成掩码,以便与x值的向量一起使用。如果long为32位,则可以比较4个元素,并解压低和解包高,以获得具有64位元素的两个掩码以匹配您的双精度。如果数组很小(因此它们适合缓存甚至.e[]占用的空间与.x[]一样多),那么长度与双精度相同意味着更少的解包。

无论如何,它看起来并不乐观。条件太多,我不知道整个事情究竟要完成什么,以及输入数据可能存在哪些限制。如果我对这个问题有更多的了解,也许我可以想出一种矢量化的方法来做一些。

哦,我认为另一个致命缺陷是每次迭代都取决于之前的迭代,因为它可能会修改b 。因此,您无法进行向量化并行执行多次迭代,除非您可以根据最后一个向量元素计算出更新b的规则。