首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SSE/NEON表查找优化

SSE/NEON表查找优化
EN

Stack Overflow用户
提问于 2013-07-18 21:21:42
回答 3查看 2.1K关注 0票数 2

我有以下查找和插值代码进行优化。(128大小的浮动表)它将在windows上与英特尔编译器一起使用,在OSX上使用GCC,在neon OSX上使用GCC。

代码语言:javascript
复制
for(unsigned int i = 0 ; i < 4 ; i++)
{
    const int iIdx = (int)m_fIndex[i];
    const float frac = m_fIndex - iIdx;
    m_fResult[i] = sftable[iIdx].val + sftable[iIdx].val2 * frac;
}

我使用sse/neon对所有内容进行了矢量化。(宏转换为sse/neon指令)

代码语言:javascript
复制
VEC_INT iIdx = VEC_FLOAT2INT(m_fIndex);
VEC_FLOAT frac = VEC_SUB(m_fIndex ,VEC_INT2FLOAT(iIdx);
m_fResult[0] = sftable[iIdx[0]].val2;
m_fResult[1] = sftable[iIdx[1]].val2;
m_fResult[2] = sftable[iIdx[2]].val2;
m_fResult[3] = sftable[iIdx[3]].val2;
m_fResult=VEC_MUL( m_fResult,frac);
frac[0] = sftable[iIdx[0]].val1;
frac[1] = sftable[iIdx[1]].val1;
frac[2] = sftable[iIdx[2]].val1;
frac[3] = sftable[iIdx[3]].val1;
m_fResult=VEC_ADD( m_fResult,frac);

我认为表访问和移动到对齐内存才是真正的瓶颈。我不擅长汇编,但有很多unpcklp和mov:

代码语言:javascript
复制
10026751  mov         eax,dword ptr [esp+4270h] 
10026758  movaps      xmm3,xmmword ptr [eax+16640h] 
1002675F  cvttps2dq   xmm5,xmm3 
10026763  cvtdq2ps    xmm4,xmm5 
10026766  movd        edx,xmm5 
1002676A  movdqa      xmm6,xmm5 
1002676E  movdqa      xmm1,xmm5 
10026772  psrldq      xmm6,4 
10026777  movdqa      xmm2,xmm5 
1002677B  movd        ebx,xmm6 
1002677F  subps       xmm3,xmm4 
10026782  psrldq      xmm1,8 
10026787  movd        edi,xmm1 
1002678B  psrldq      xmm2,0Ch 
10026790  movdqa      xmmword ptr [esp+4F40h],xmm5 
10026799  mov         ecx,dword ptr [eax+edx*8+10CF4h] 
100267A0  movss       xmm0,dword ptr [eax+edx*8+10CF4h] 
100267A9  mov         dword ptr [eax+166B0h],ecx 
100267AF  movd        ecx,xmm2 
100267B3  mov         esi,dword ptr [eax+ebx*8+10CF4h] 
100267BA  movss       xmm4,dword ptr [eax+ebx*8+10CF4h] 
100267C3  mov         dword ptr [eax+166B4h],esi 
100267C9  mov         edx,dword ptr [eax+edi*8+10CF4h] 
100267D0  movss       xmm7,dword ptr [eax+edi*8+10CF4h] 
100267D9  mov         dword ptr [eax+166B8h],edx 
100267DF  movss       xmm1,dword ptr [eax+ecx*8+10CF4h] 
100267E8  unpcklps    xmm0,xmm7 
100267EB  unpcklps    xmm4,xmm1 
100267EE  unpcklps    xmm0,xmm4 
100267F1  mulps       xmm0,xmm3 
100267F4  movaps      xmmword ptr [eax+166B0h],xmm0 
100267FB  mov         ebx,dword ptr [esp+4F40h] 
10026802  mov         edi,dword ptr [esp+4F44h] 
10026809  mov         ecx,dword ptr [esp+4F48h] 
10026810  mov         esi,dword ptr [esp+4F4Ch] 
10026817  movss       xmm2,dword ptr [eax+ebx*8+10CF0h] 
10026820  movss       xmm5,dword ptr [eax+edi*8+10CF0h] 
10026829  movss       xmm3,dword ptr [eax+ecx*8+10CF0h] 
10026832  movss       xmm6,dword ptr [eax+esi*8+10CF0h] 
1002683B  unpcklps    xmm2,xmm3 
1002683E  unpcklps    xmm5,xmm6 
10026841  unpcklps    xmm2,xmm5 
10026844  mulps       xmm2,xmm0 
10026847  movaps      xmmword ptr [eax+166B0h],xmm2

在评测时,sse版本在win上没有太多好处。

你有什么建议可以改进吗?霓虹灯/gcc有什么副作用吗?

目前,我只考虑将第一部分矢量化,并在循环中进行表读出和插值,希望它将从编译器优化中受益。

EN

回答 3

Stack Overflow用户

发布于 2013-07-18 22:28:57

OSX?那它就和霓虹灯没有关系了。

顺便说一句,霓虹灯无论如何也无法处理这么大的LUT。(关于这件事,我不知道上交所)

首先验证SSE是否可以处理这种大小的out,如果可以,我建议使用不同的编译器,因为GCC倾向于对内部函数进行内吸。

票数 2
EN

Stack Overflow用户

发布于 2013-07-18 23:39:28

这是我见过的最糟糕的编译器代码生成(假设启用了优化器)。值得一提的是对GCC的攻击。

主要问题:

  • 将每次查找valval2valval2的索引加载到GPR中,并将索引的向量加载到堆栈,然后将它们加载到gpr.

在霓虹灯和SSE上,这应该只需要四个加载和三四个解包(比目前的八个加载+六个解包要好得多)。

消除多余的堆栈流量可能会更难。确保优化器已打开。

票数 1
EN

Stack Overflow用户

发布于 2013-07-19 00:08:48

编译器之所以在这里创建“时髦的”代码(需要大量重载)的原因之一是,为了正确起见,它必须假设sftable[]数组中的数据可能会发生变化。要使生成的代码更好,请将其重新构造为如下所示:

代码语言:javascript
复制
VEC_INT iIdx = VEC_FLOAT2INT(m_fIndex);
VEC_FLOAT frac = VEC_SUB(m_fIndex ,VEC_INT2FLOAT(iIdx);
VEC_FLOAT fracnew;

// make it explicit that all you want is _four loads_
typeof(*sftable) tbl[4] = {
    sftable[iIdx[0]], sftable[iIdx[1]], sftable[iIdx[2]], sftable[iIdx[3]]
};

m_fResult[0] = tbl[0].val2
m_fResult[1] = tbl[1].val2;
m_fResult[2] = tbl[2].val2;
m_fResult[3] = tbl[3].val2;
fracnew[0] = tbl[0].val1;
fracnew[1] = tbl[1].val1;
fracnew[2] = tbl[2].val1;
fracnew[3] = tbl[3].val1;

m_fResult=VEC_MUL( m_fResult,frac);
m_fResult=VEC_ADD( m_fResult,fracnew);
frac = fracnew;

使用内部函数可能是有意义的(因为你在sftable[]中的布局是交错的),因为向量浮点数组fResultfrac很可能都可以通过一条指令从tbl[]加载(在SSE中解压hi/lo,在Neon中解压)。如果没有类似AVX2的VGATHER指令的帮助,“主”表查找是不能向量化的,但它不需要超过四次加载。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17724678

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档