我想知道你是否可以帮助我使用NEON内在函数来优化这个掩码功能。我已经尝试使用O3 gcc编译器标志来使用自动矢量化,但是该函数的性能比使用O2运行它要小,这会关闭自动矢量化。由于某种原因,使用O3生成的汇编代码比使用O2的汇编代码长1.5。
void mask(unsigned int x, unsigned int y, uint32_t *s, uint32_t *m)
{
unsigned int ixy;
ixy = xsize * ysize;
while (ixy--)
*(s++) &= *(m++);
}
可能我必须使用以下命令:
vld1q_u32 //从s和m
加载4个整数vandq_u32 //执行s和m的4个整数之间的逻辑和
vst1q_u32 //将它们存储回s
然而,我不知道如何以最佳方式做到这一点。例如,我应该在加载,存储和存储后将s,m增加4?我对NEON很新,所以我真的需要一些帮助。
我正在使用gcc 4.8.1,我使用以下cmd进行编译:
arm-linux-gnueabihf-gcc -mthumb -march = armv7-a -mtune = cortex-a9 -mcpu = cortex-a9 -mfloat-abi = hard -mfpu = neon -O3 -fprefetch-loop-数组name.c -o name
提前致谢
答案 0 :(得分:2)
我可能会这样做。我已经包含了4x循环展开。预加载缓存总是一个好主意,可以将速度提高25%。由于没有太多的处理(它主要花费时间加载和存储),最好加载大量寄存器,然后处理它们,因为它给了数据实际加载的时间。它假设数据是16个元素的偶数倍。
void fmask(unsigned int x, unsigned int y, uint32_t *s, uint32_t *m)
{
unsigned int ixy;
uint32x4_t srcA,srcB,srcC,srcD;
uint32x4_t maskA,maskB,maskC,maskD;
ixy = xsize * ysize;
ixy /= 16; // process 16 at a time
while (ixy--)
{
__builtin_prefetch(&s[64]); // preload the cache
__builtin_prefetch(&m[64]);
srcA = vld1q_u32(&s[0]);
maskA = vld1q_u32(&m[0]);
srcB = vld1q_u32(&s[4]);
maskB = vld1q_u32(&m[4]);
srcC = vld1q_u32(&s[8]);
maskC = vld1q_u32(&m[8]);
srcD = vld1q_u32(&s[12]);
maskD = vld1q_u32(&m[12]);
srcA = vandq_u32(srcA, maskA);
srcB = vandq_u32(srcB, maskB);
srcC = vandq_u32(srcC, maskC);
srcD = vandq_u32(srcD, maskD);
vst1q_u32(&s[0], srcA);
vst1q_u32(&s[4], srcB);
vst1q_u32(&s[8], srcC);
vst1q_u32(&s[12], srcD);
s += 16;
m += 16;
}
}
答案 1 :(得分:0)
我将从最简单的一个开始,并将其作为与未来例程进行比较的参考。
一个好的经验法则是尽快计算所需的东西,而不是在需要时。 这意味着指令可以执行X个循环,但结果并不总是立即就绪,因此调度很重要
例如,您案例的简单调度架构将是(伪代码)
nn=n/4 // Assuming n is a multiple of 4
LOADI_S(0) // Load and immediately after increment pointer
LOADI_M(0) // Load and immediately after increment pointer
for( k=1; k<nn;k++){
AND_SM(k-1) // Inner op
LOADI_S(k) // Load and increment after
LOADI_M(k) // Load and increment after
STORE_S(k-1) // Store and increment after
}
AND_SM(nn-1)
STORE_S(nn-1) // Store. Not needed to increment
从内循环中省略这些指令,我们实现内部的操作不依赖于前一个操作的结果。 可以进一步扩展此模式,以便从等待前一个操作结果的时间中获利。
此外,由于内在函数仍然依赖于优化器,请参阅编译器在不同优化选项下执行的操作。我更喜欢使用内联汇编,这对于小程序来说并不困难,并且可以为您提供更多控制。