哪个在 ARM 上更快?
*p++ = (*p >> 7) * 255;
or
*p++ = ((*p >> 7) << 8) - 1
本质上,我在这里所做的是取一个 8 位字,如果 >= 128 则将其设置为 255,否则设置为 0。
哪个在 ARM 上更快?
*p++ = (*p >> 7) * 255;
or
*p++ = ((*p >> 7) << 8) - 1
本质上,我在这里所做的是取一个 8 位字,如果 >= 128 则将其设置为 255,否则设置为 0。
If p
is char
below 语句只是对255
.
*p++ = ((*p >> 7) << 8) - 1
如果p
是int
,那当然是另一回事了。
您可以使用GCC Explorer查看程序集输出的样子。下面显然是你从标志中得到Linaro's arm-linux-gnueabi-g++ 4.6.3
的;-O2 -march=armv7-a
void test(char *p) {
*p++ = (*p >> 7) * 255;
}
void test2(char *p) {
*p++ = ((*p >> 7) << 8) - 1 ;
}
void test2_i(int *p) {
*p++ = ((*p >> 7) << 8) - 1 ;
}
void test3(char *p) {
*p++ = *p >= 128 ? ~0 : 0;
}
void test4(char *p) {
*p++ = *p & 0x80 ? ~0 : 0;
}
创建
test(char*):
ldrb r3, [r0, #0] @ zero_extendqisi2
sbfx r3, r3, #7, #1
strb r3, [r0, #0]
bx lr
test2(char*):
movs r3, #255
strb r3, [r0, #0]
bx lr
test2_i(int*):
ldr r3, [r0, #0]
asrs r3, r3, #7
lsls r3, r3, #8
subs r3, r3, #1
str r3, [r0, #0]
bx lr
test3(char*):
ldrsb r3, [r0, #0]
cmp r3, #0
ite lt
movlt r3, #255
movge r3, #0
strb r3, [r0, #0]
bx lr
test4(char*):
ldrsb r3, [r0, #0]
cmp r3, #0
ite lt
movlt r3, #255
movge r3, #0
strb r3, [r0, #0]
bx lr
如果您不挑剔,最好始终检查生成的代码的汇编是否超过这些细节。人们倾向于高估编译器,我同意大多数时候他们做得很好,但我想任何人都有权利质疑生成的代码。
您还应该小心解释指令,因为由于核心的体系结构特征(如无序、超标量深度管道),它们并不总是与周期准确列表相匹配。所以它可能并不总是最短的指令序列获胜。
好吧,要回答您标题中的问题,在 ARM 上,SHIFT+SUB 可以在具有 1 个周期延迟的单个指令中完成,而 MUL 通常具有多个周期延迟。所以这种转变通常会更快。
要回答为此编写什么 C 代码的隐含问题,通常最好使用表达您意图的最简单的代码:
*p++ = *p >= 128 ? ~0 : 0; // set byte to all ones iff >= 128
或者
*p++ = *p & 0x80 ? ~0 : 0; // set byte to all ones based on the MSB
这通常会被编译器转换为最快的方式,无论是转变还是其他,还是有条件的移动。
尽管您的编译器可以很好地优化该行(并且阅读程序集会告诉您真正完成了什么),但您可以参考此页面以准确了解 MUL 可以花费多少周期。