C++ 向量化嵌套循环-SIMD

C++ 向量化嵌套循环-SIMD,c++,parallel-processing,x86,vectorization,simd,C++,Parallel Processing,X86,Vectorization,Simd,是否有人知道使用SIMD对类似的内容进行矢量化: for(size_t i = 0; i < refSeq.length() / 4; i++){ for(size_t j = 0; j<otherSeq.length(); j++){ if(refSeq[i] == otherSeq[j]){ if(i == 0 || j == 0) L[i][j] = 1; else L[i][j] = L[

是否有人知道使用SIMD对类似的内容进行矢量化:

for(size_t i = 0; i < refSeq.length() / 4; i++){

    for(size_t j = 0; j<otherSeq.length(); j++){
    if(refSeq[i] == otherSeq[j]){
        if(i == 0 || j == 0)
            L[i][j] = 1;
       else
        L[i][j] = L[i-1][j-1] + 1;
    }
       else
        L[i][j] = 0;
    }
}
(大小i=0;i{
对于(size_t j=0;j让我尝试提出一个解决方案。首先计算L[i][0]和L[0][j]的值。现在开始从i=1和j=1进行迭代。现在可以删除循环每次迭代中对i==0或j==0的检查。这样做的另一个优点是,对于行上每次迭代中的每个L[i][j],L[i-1][j-1]的值是可用的。现在,假设向量寄存器可以容纳数组的4个元素。现在我们可以加载refSeq、otherSeq、L(前一行)和L(当前行)的4个元素。理论上我们现在可以进行向量化。我假设自动向量器无法识别这一点。因此我们必须手动执行。如果我错了,请纠正我

for(size_t i=0;i<refSeq.length()/4;i++)
{
    if(refSeq[i]==otherSeq[0])
        L[i][0]=1;
    else
        L[i][0]=0;
}
for(size_t j=0; j<otherSeq.length();j++)
{
    if(refSeq[0]==otherSeq[j])
        L[0][j]=1;
    else
        L[0][j]=0;
}

for(size_t i=1;i<refSeq.length()/4;i++)
{
    for(size_t j=1; j<otherSeq.length();j++)
    {
        if(refSeq[i]==otherSeq[j])
            L[i][j] = L[i-1][j-1] + 1;
        else
            L[i][j]=0;
    }
}

for(size_t i=0;i这是一个动态规划问题,Streat forward实现有太多的数据依赖性,不适合SIMD计算

但是,如果将算法从按行迭代改为按对角线迭代,则可以并行计算整个对角线。请参见下图

下面的“伪”代码使用了一个额外行/列的矩阵,以简化“内部”计算。该额外行/列在每次对角迭代之前初始化

int i, j, k;
for (k = 1; ; k++) {
    int minI = k > refLen ? k - refLen : 1;
    int maxI = k > otherLen ? otherLen : k - 1;

    for (i = maxI; i >= minI; ) {
        j = k - i;

        // vectorized calculation 256 bit (AVX2)
        if (i >= 32 && otherLen - j >= 32) {
            // calculate 32 values of the diagonal with SIMD
            i -= 32;
            continue;
        }

        // vectorized calculation 128 bit (SSE)
        if (i >= 16 && otherLen - j >= 16) {
            // calculate 16 values of the diagonal with SIMD
            i -= 16;
            continue;
        }

        // scalar calculation
        if (refSeq[i - 1] == otherSeq[j - 1]) {
            L[i][j] = L[i - 1][j - 1] + 1;
        } else {
            L[i][j] = 0;
        }
        i--;
    }

    if (k == otherLen + refLen) {
        break;
    }

    // initialize next j-endpoint in diagonal
    if (k <= refLen) {
        L[0][k] = 0;
    }
    // initialize next i-endpoint in diagonal
    if (k <= otherLen) {
        L[k][0] = 0;
    }
}
inti,j,k;
对于(k=1;;k++){
int minI=k>refLen?k-refLen:1;
int maxI=k>otherLen?otherLen:k-1;
对于(i=maxI;i>=minI;){
j=k-i;
//矢量化计算256位(AVX2)
如果(i>=32&&otherLen-j>=32){
//使用SIMD计算对角线的32个值
i-=32;
继续;
}
//矢量化计算128位(SSE)
如果(i>=16&&otherLen-j>=16){
//使用SIMD计算对角线的16个值
i-=16;
继续;
}
//标量计算
if(refSeq[i-1]==otherSeq[j-1]){
L[i][j]=L[i-1][j-1]+1;
}否则{
L[i][j]=0;
}
我--;
}
if(k==otherLen+refLen){
打破
}
//初始化对角线中的下一个j端点

如果(k)当你说“SIMD”时,你需要指定你正在谈论的CPU系列,例如x86(在这种情况下,你需要指定可以假定的SSE/AVX级别)、PowerPC(AltiVec)、POWER(VMX/VSX)、ARM(Neon)、Cell等。另外,
refSeq[]
otherSeq[]
L[]
?您确实非常坚持让这个最长的子字符串算法再次并行:)数据依赖性。SIMD工作在独立的数据块上。这里您有
if
(坏)和
if
(更糟)。您需要重新设计算法以使用掩蔽而不是分支,我不确定它是否会运行得更快。它适用于x86,所有这些都是字符串。SSE intel的指令。@Hristo是的,我尝试了所有方法,但我能找到的只是一些有趣的示例,没有更复杂的示例。:)是的,掩蔽…尽管有一个:)谢谢:)