ARM的速度更快? MUL或(SHIFT + SUB)?

时间:2013-08-22 18:28:07

标签: c performance optimization assembly arm

哪个在ARM上更快?

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

or

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

基本上我在这里做的是取一个8位字,如果&gt; = 128则设置为255,否则为0。

3 个答案:

答案 0 :(得分:4)

如果p低于char,则语句只是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

如果你不是最好的挑剔,总是检查生成的代码的组装超过这些细节。人们倾向于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>