最近在做飞腾上的FFT优化,记录一下以后用。
目前实现了基2FFT,使用arm提供的neon接口做了并行计算。算法原理网上很多,这里就不讲了,记录复数正向优化方法。
优化思路:
第一层蝶形计算:
第一层的蝶形因子都是1,蝶形下半部分就无需乘蝶形因子,直接与蝶形上半部分做加减运算即可。
由于第一层蝶形上下部分跨度为1(即连续),直接加载4个数据到向量寄存器无法实现并行计算,改用vld2q_f32()对输入信号进行加载,存入到float32x4x2类型的变量中。具体形式如下图:

第一行4个数据为蝶形的上半部分,第二行四个数据为蝶形的下半部分,可直接进行结果的计算。
复数部分与实数部分一样。
第二层蝶形计算
第二层蝶形有两种旋转因子分别为1和-i,蝶形上下部分间隔为2,可以使用vld4q_f32()将数据加载到float32x4x4_t的变量中,具体形式如下图:

第一行与第三行为同组蝶形的上下两部分(间隔为2),第二行与第四行为第二种蝶形的上下部分。对于旋转因子为1的部分,计算方式与第一层相同。对于第二种蝶形,旋转因子为-i,可以直接得到下半部分与蝶形因子的计算结果而无需乘法。
第三层及之后的
蝶形计算
第三层旋转因子有4个,蝶形上下部分间隔为4,可以选择使用vld1q_f32()加载数据到float32x4变量中,再加载之后的4个到第二个float32x4变量中。两个变量分别存储蝶形上下两部分的数据。然后进行常规的复数乘法运算与加减法。
后来发现这种方式的访存次数太多,考虑到armV8有32个向量寄存器,cache line大小为64B即16个float,利用vld1q_f32_x4()接口加载一个缓存行的数据,用4个向量寄存器存着,计算完再利用vst1q_f32_x4()存回去,将8次访存(4次取4次存)减少为2次访存(1次取1次存)。
实现了这个想法后,在飞腾CPU上利用g++编译发现不认识vld1q_f32_x4()与vst1q_f32_x4()接口!!
在我本机(macbook pro 2017)编码是可以看到<arm_neon.h>库中有这些接口的。