2

哪个在 ARM 上更快?

*p++ = (*p >> 7) * 255;

or

*p++ = ((*p >> 7) << 8) - 1

本质上,我在这里所做的是取一个 8 位字,如果 >= 128 则将其设置为 255,否则设置为 0。

4

3 回答 3

5

If pis charbelow 语句只是对255.

*p++ = ((*p >> 7) << 8) - 1

如果pint,那当然是另一回事了。

您可以使用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

如果您不挑剔,最好始终检查生成的代码的汇编是否超过这些细节。人们倾向于高估编译器,我同意大多数时候他们做得很好,但我想任何人都有权利质疑生成的代码。

您还应该小心解释指令,因为由于核心的体系结构特征(如无序、超标量深度管道),它们并不总是与周期准确列表相匹配。所以它可能并不总是最短的指令序列获胜。

于 2013-08-23T06:27:39.183 回答
3

好吧,要回答您标题中的问题,在 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

这通常会被编译器转换为最快的方式,无论是转变还是其他,还是有条件的移动。

于 2013-08-22T18:53:52.743 回答
2

尽管您的编译器可以很好地优化该行(并且阅读程序集会告诉您真正完成了什么),但您可以参考此页面以准确了解 MUL 可以花费多少周期。

于 2013-08-22T19:33:36.740 回答