哪个在ARM上更快?
*p++ = (*p >> 7) * 255;
or
*p++ = ((*p >> 7) << 8) - 1
基本上我在这里做的是取一个8位字,如果&gt; = 128则设置为255,否则为0。
答案 0 :(得分:4)
如果p
低于char
,则语句只是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
如果你不是最好的挑剔,总是检查生成的代码的组装超过这些细节。人们倾向于overestimate compilers,我同意他们大部分时间做得很好,但我想任何人都有权质问生成的代码。
您还应该仔细解释说明,因为它们并不总是与周期精确列表相匹配,因为核心的架构特征就像有无序的超标量深度管道。所以它可能不总是最短的指令序列获胜。
答案 1 :(得分:2)
嗯,为了回答你的标题中的问题,在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
这通常会被编译器转换为最快的方式,无论是转移等等,还是有条件的移动。
答案 2 :(得分:2)
尽管您的编译器可以很好地优化线路(并且阅读程序集会告诉您实际做了什么),但您可以从this page引用以确切了解MUL可以采用的周期数。 / p>