optimization - 快速饱和并在ARM asm中移动两个半字

标签 optimization assembly arm bit-manipulation simd

我在32位字中有两个带符号的16位值,我需要将它们右移(除以常数)(可以从1到6),然后饱和到字节(0..0xFF)。

例如,


移位= 5的0x FFE1 00AA必须变为0x 0000 0005;
0x 2345 1234必须变为0x 00FF 0091


我正在尝试同时使值饱和,例如以下伪代码:

AND RT, R0, 0x80008000; - mask high bits to get negatives
ORR RT, RT, LSR #1
ORR RT, RT, LSR #2
ORR RT, RT, LSR #4
ORR RT, RT, LSR #8; - now its expanded signs in each halfword
MVN RT, RT
AND R0, RT; now negative values are zero
; here something to saturate high overflow and shift after


但是我得到的代码非常难看和缓慢。 :)
我现在拥有的最好(最快)的东西是每一半的饱和度,例如:

MOV RT, R0, LSL #16
MOVS RT, RT, ASR #16+5
MOVMI RT, #0
CMP RT, RT, #256
MOVCS RT, #255
MOVS R0, R0, ASR #16+5
MOVMI R0, #0
CMP R0, R0, #256
MOVCS R0, #255
ORR R0, RT, R0, LSL #16


但这是10个周期。 :(可以更快吗?

附注:后来我找到了USAT16指令,但这仅适用于ARMv6。而且我需要在ARMv5TE和ARMv4上运行的代码。



编辑:现在我重写我的第一个代码:

ANDS RT, 0x10000, R0 << 1;      // 0x10000 is in register. Sign (HI) moves to C flag, Sign (LO) is masked
SUBNE RT, RT, 1;            // Mask LO with 0xFFFF if it's negative
SUBCS RT, RT, 0x10000;      // Mask HI with 0xFFFF if it's negative
BIC R0, R0, RT;         // Negatives are 0 now. The mask can be used as XOR too
TST R0, 0xE0000000;         // check HI overflow             
ORRNE R0, R0, 0x1FE00000        // set HI to 0xFF (shifted) if so
TST R0, 0x0000E000          // check LO overflow             
ORRNE R0, R0, 0x00001FE0        // set LO to 0xFF if so          
AND R0, 0x00FF00FF, R0 >> 5;    // 0x00FF00FF is in register     


但这并不漂亮。

最佳答案

如上所述,您所拥有的与您将要解决的问题一样好。如果要在一个紧密的循环中处理大量数据,并且可以提供一些寄存器来保存掩码,则可以节省一个或两个周期,但这不会有太大的改善。在v6架构之前,ARM上对此类型的“小向量”饱和操作的支持不大。

基本上,除非这是程序中的唯一瓶颈,否则是时候解决这个问题并继续进行下一个热点了。

关于optimization - 快速饱和并在ARM asm中移动两个半字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1284689/

相关文章:

c++强制编译器选择退出某些代码

c++ - 低内存的内存管理 : finding and tracking duplicates of random function return values

c - 这个没有 libc 的 C 程序如何工作?

linux - 在 ARM (armv7l/arm64/aarch64) 上构建 mongo shell 3.2.x - 段错误

arm - ARMv8-A 上的系统寄存器是否按处理器存储?

最大化矩阵的最小对角线元素的算法

c++ - 优化子集和实现

C内联汇编内存拷贝

gcc - x86 asm - 从 esp 中减去 12 个字节。只需要8个

c - 这 ((LPC_PINCON_TypeDef *) LPC_PINCON_BASE ) 是什么意思?