ARM-NEON:基于参数的条件寄存器交换
Posted
技术标签:
【中文标题】ARM-NEON:基于参数的条件寄存器交换【英文标题】:ARM-NEON: Conditional register swapping based on parameters 【发布时间】:2014-03-07 19:45:56 【问题描述】:我正在 NEON 中编写一个用于进行颜色交换的图像处理子程序,即,我从一个数组中顺序加载 R、G、B 通道,并根据某些配置,置换其中的一些通道。
最多有 6 个排列
(RGB) -> (RGB),(RBG),(GRB),(GBR),(BRG),(BGR)
最有效的方法是为每种情况使用一个单独的子程序和相应的 VSWP 指令。由于子程序会做其他几件事,我宁愿把所有东西都放在一个子程序中,即使效率不高,
还阅读了条件执行和分支是不可取的。所以,如果我想把它放在一个带有无分支代码的块中,我唯一想到的是
New_R = a(0)*R+a(1)*G+a(2)*B
New_G = a(3)*R+a(4)*G+a(5)*B
New_B = a(6)*R+a(7)*G+a(8)*B
每行和每列中只有一个a(i)每次=1,其余为=0
问题:有什么更聪明的方法吗?考虑到它必须被编码为 NEON?
【问题讨论】:
【参考方案1】:VTBL.8
是 NEON 中最强大的字节交换工具。
将 3x8 字节加载到寄存器 d0,d1,d2 看起来像
R G B R G B R G | B R G B R G B R | G B R G B R G B |
0 1 2 3 4 5 6 7 8 9 a b c d e f .... 17
VTBL d3, d0,d1,d2 , d6 ;; select bytes to d3 from d0,d1,d2 based on d6
VTBL d4, d0,d1,d2 , d7
VTBL d5, d0,d1,d2 , d8
其中 d6,d7,d8 编码要在新字节中读取的位置。 例如'0 1 2 3 4 5 6 7' 用于原始排列,'0 2 1 3 5 4 6 8', '7 ...' 用于交换 G 和 B。常量向量 d6..d8 只需加载例程开始时一次。
另一种可能性是使用交错读取对以下序列进行编码;
VLD3.8 d0,d1,d2 , [r0] ; // Read R, G, B to separate registers
VLD3.8 d3,d4,d5 , [r0] ; // Make a second copy (or use some other instruction)
VBIT d3, d1, d6 ; // d3 is now either R or G
VBIT d4, d2, d7 ; // d4 is now either G or B
VBIT d5, d0, d8 ; // d5 is now either B or R
VBIT d0, d4, d9 ; // d0 is now R or (G or B)
VBIT d1, d5, d10 ; // d1 is now G or (B or R)
VBIT d2, d3, d11 ; // d2 is now B or (R or G)
虽然示例中使用了 6 个寄存器作为条件码,但 3 个独立的寄存器应该足够了——如果需要使用反向逻辑,也可以使用 VBIF。
【讨论】:
无话可说。我之前的问题只是关于 VTBL,但根本没想到它也可以用于排列。谢谢 我认为这不是最有效的方法,因为 VTBL 相当复杂并且不能在单个时钟中执行。不过这很容易。您可能想尝试使用 interleaved read VLD3.8 将 RGB 分离到不同的通道,d1=R、d2=G、d3=B,并使用 VBIT 或 VSEL 复制完整的寄存器。使用VLD3.8 d0, d2, d4, [r0]!; VLD3.8 d1, d3, d5, [r0]!
允许将完整的寄存器 q0 分配给红色通道。
是的,我已经进行了交错阅读并调整了您之前对这个案例的回答。但是我看不到如何使用 VBIT o VSEL 来处理一般情况,即在前面的答案中,我只需要加载一次 d6..d8。对不起,如果我问的很明显,我很新。
我喜欢 VBIT 选项,谢谢。此外,也许第二个负载可以替换为 2 vmov(如果寄存器选择正确,一个带有 q,另一个带有 d),从而提高循环计数。
@AkiSuihkonen:这取决于您所针对的特定内核,但对于高功率部件VTBL
确实非常快,并且执行此操作的最面向未来的方式(即@ 987654326@ 并没有因为 arm 内核变得越来越复杂而变得更慢——在越来越多的处理器上它将是单周期)。以上是关于ARM-NEON:基于参数的条件寄存器交换的主要内容,如果未能解决你的问题,请参考以下文章
如何在没有隐式锁定最新的64位Intel CPU的情况下用寄存器交换堆栈顶部?