【发布时间】:2025-12-18 19:50:02
【问题描述】:
我在一个 32 位字中有两个带符号的 16 位值,我需要将它们右移(除)在常数值(它可以是从 1 到 6)并饱和到字节(0..0xFF) .
例如,
- 0x FFE1 00AA 与 shift=5 必须变为 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 个周期。 :( 可以更快吗?
p.s.:后来我找到了 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
但它并不漂亮。
【问题讨论】:
-
你有没有试过用 C 语言编写它,然后看看编译器产生了什么?
-
史蒂夫,我不知道如何在没有单独处理的情况下用 C 编写它。但是我的大脑产生了一些想法 :) 其中之一是“XOR 掩码”。如果数字没问题,它必须包含 0(分别在每一半中)。如果 number 为负数,它将包含自己。正溢出将包含数字^0xFFFF。所以结果将是源 ^ 掩码。但不知道如何同时进行
标签: optimization assembly arm bit-manipulation simd