1

我正在使用带有 linux ubuntu 的 i.MX53 板进行试验。我正在我的主机系统上使用交叉编译器(arm-linux-gnueabihf)在 ssh 上工作。

对于在处理器 (ARM Cortex-A8) 上进行浮点运算的基准测试,我创建了以下两个不同的程序,它们都包含一个简单的循环。在第一个程序中,循环包含一个乘法,在第二个程序中,循环包含一个额外的加法。

我使用以下编译器调用编译了这两个程序:

arm-linux-gnueabihf-g++-4.8 -O3 -ffast-math -Ofast -Wall -fmessage-length=0 -Wno-multichar -Wno-unknown-pragmas -std=c++11 -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=hard -save-temps loopMul.cpp -o loopMul

现在我的问题是:为什么编译器会为循环部分输出如此不同的汇编代码? (见汇编代码)

我认识到,在第一个程序中,编译器为乘法生成 NEON 指令,而在第二个程序中,只有较慢的 VFP 指令。

第一个程序(loopMul.cpp):

#include <iostream>
#include <ctime>

using namespace std;

int main(int argc, char **argv)
{
    size_t length = 10E7;
    float test = 1;

    clock_t start = clock();    

    for(size_t i=1; i<length; i++)
    {
        test *= i;
    }

    clock_t elapsed = clock() - start;

    cout << test << endl;

    float elapsed_seconds = float(elapsed) / float(CLOCKS_PER_SEC);
    cout << "loop took " << elapsed_seconds <<  "seconds" << endl;

    return 0;
}

第二个程序(loopMulAdd):

#include <iostream>
#include <ctime>

using namespace std;

int main(int argc, char **argv)
{
    size_t length = 10E7;
    float test = 1;

    clock_t start = clock();    

    for(size_t i=1; i<length; i++)
    {
        test *= i;
        test += 1;
    }

    clock_t elapsed = clock() - start;

    cout << test << endl;

    float elapsed_seconds = float(elapsed) / float(CLOCKS_PER_SEC);
    cout << "loop took " << elapsed_seconds <<  "seconds" << endl;

    return 0;
}

第一个程序的汇编输出(loopMul.s):

    .syntax unified
    .cpu cortex-a8
    .eabi_attribute 27, 3
    .eabi_attribute 28, 1
    .fpu neon
    .eabi_attribute 23, 1
    .eabi_attribute 24, 1
    .eabi_attribute 25, 1
    .eabi_attribute 26, 2
    .eabi_attribute 30, 2
    .eabi_attribute 34, 1
    .eabi_attribute 18, 4
    .thumb
    .file   "loopMul.cpp"
    .section    .text.startup,"ax",%progbits
    .align  2
    .global main
    .thumb
    .thumb_func
    .type   main, %function
main:
    .fnstart
.LFB1265:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    push    {r4, lr}
    .save {r4, lr}
    fstmfdd sp!, {d8, d9, d10, d11}
    .vsave {d8, d9, d10, d11}
    bl  clock
    vmov.i32    q11, #4  @ v4si
    vmov.f32    q9, #1.0e+0  @ v4sf
    movw    r2, #30783
    movt    r2, 381
    movs    r3, #0
    vldr    d16, .L8
    vldr    d17, .L8+8
    mov r4, r0
.L3:
    vcvt.f32.s32    q10, q8
    adds    r3, r3, #1
    cmp r3, r2
    vadd.i32    q8, q8, q11
    vmul.f32    q9, q9, q10
    bne .L3
    vmov.i32    q8, #0  @ v16qi
    vext.8  q4, q9, q8, #8
    vmul.f32    q4, q4, q9
    vext.8  q5, q4, q8, #4
    bl  clock
    flds    s15, .L8+16
    vmul.f32    q4, q5, q4
    vmov.32 r3, d8[0]
    fmsr    s0, r3
    fmuls   s0, s0, s15
    fcvtds  d0, s0
    subs    r4, r0, r4
    movw    r0, #:lower16:_ZSt4cout
    movt    r0, #:upper16:_ZSt4cout
    bl  _ZNSo9_M_insertIdEERSoT_
    bl  _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
    movw    r0, #:lower16:_ZSt4cout
    movw    r1, #:lower16:.LC0
    movt    r0, #:upper16:_ZSt4cout
    movt    r1, #:upper16:.LC0
    bl  _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    fmsr    s15, r4 @ int
    fsitos  s0, s15
    flds    s15, .L8+20
    fmuls   s0, s0, s15
    fcvtds  d0, s0
    bl  _ZNSo9_M_insertIdEERSoT_
    movw    r1, #:lower16:.LC1
    movt    r1, #:upper16:.LC1
    bl  _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    bl  _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
    fldmfdd sp!, {d8-d11}
    movs    r0, #0
    pop {r4, pc}
.L9:
    .align  3
.L8:
    .word   1
    .word   2
    .word   3
    .word   4
    .word   1733542428
    .word   897988541
    .fnend
    .size   main, .-main
    .align  2
    .thumb
    .thumb_func
    .type   _GLOBAL__sub_I_main, %function
_GLOBAL__sub_I_main:
    .fnstart
.LFB1422:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    push    {r4, lr}
    movw    r4, #:lower16:.LANCHOR0
    movt    r4, #:upper16:.LANCHOR0
    mov r0, r4
    bl  _ZNSt8ios_base4InitC1Ev
    mov r0, r4
    movw    r1, #:lower16:_ZNSt8ios_base4InitD1Ev
    movw    r2, #:lower16:__dso_handle
    movt    r1, #:upper16:_ZNSt8ios_base4InitD1Ev
    movt    r2, #:upper16:__dso_handle
    pop {r4, lr}
    b   __aeabi_atexit
    .cantunwind
    .fnend
    .size   _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
    .section    .init_array,"aw",%init_array
    .align  2
    .word   _GLOBAL__sub_I_main(target1)
    .section    .rodata.str1.4,"aMS",%progbits,1
    .align  2
.LC0:
    .ascii  "loop took \000"
    .space  1
.LC1:
    .ascii  "seconds\000"
    .bss
    .align  2
.LANCHOR0 = . + 0
    .type   _ZStL8__ioinit, %object
    .size   _ZStL8__ioinit, 1
_ZStL8__ioinit:
    .space  1
    .hidden __dso_handle
    .ident  "GCC: (Ubuntu/Linaro 4.8.1-10ubuntu7) 4.8.1"
    .section    .note.GNU-stack,"",%progbits

第二个程序的汇编输出(loopMulAdd.s):

    .syntax unified
    .cpu cortex-a8
    .eabi_attribute 27, 3
    .eabi_attribute 28, 1
    .fpu neon
    .eabi_attribute 23, 1
    .eabi_attribute 24, 1
    .eabi_attribute 25, 1
    .eabi_attribute 26, 2
    .eabi_attribute 30, 2
    .eabi_attribute 34, 1
    .eabi_attribute 18, 4
    .thumb
    .file   "loopMulAdd.cpp"
    .section    .text.startup,"ax",%progbits
    .align  2
    .global main
    .thumb
    .thumb_func
    .type   main, %function
main:
    .fnstart
.LFB1265:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    push    {r4, lr}
    .save {r4, lr}
    fstmfdd sp!, {d8}
    .vsave {d8}
    bl  clock
    fconsts s16, #112
    mov r2, #57600
    movt    r2, 1525
    movs    r3, #1
    fcpys   s14, s16
    mov r4, r0
.L3:
    fmsr    s13, r3 @ int
    adds    r3, r3, #1
    cmp r3, r2
    fsitos  s15, s13
    fcpys   s13, s14
    fmacs   s13, s16, s15
    fcpys   s16, s13
    bne .L3
    bl  clock
    fcvtds  d0, s16
    subs    r4, r0, r4
    movw    r0, #:lower16:_ZSt4cout
    movt    r0, #:upper16:_ZSt4cout
    bl  _ZNSo9_M_insertIdEERSoT_
    bl  _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
    movw    r0, #:lower16:_ZSt4cout
    movw    r1, #:lower16:.LC0
    movt    r0, #:upper16:_ZSt4cout
    movt    r1, #:upper16:.LC0
    bl  _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    fmsr    s15, r4 @ int
    fsitos  s0, s15
    flds    s15, .L7
    fmuls   s0, s0, s15
    fcvtds  d0, s0
    bl  _ZNSo9_M_insertIdEERSoT_
    movw    r1, #:lower16:.LC1
    movt    r1, #:upper16:.LC1
    bl  _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    bl  _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
    fldmfdd sp!, {d8}
    movs    r0, #0
    pop {r4, pc}
.L8:
    .align  2
.L7:
    .word   897988541
    .fnend
    .size   main, .-main
    .align  2
    .thumb
    .thumb_func
    .type   _GLOBAL__sub_I_main, %function
_GLOBAL__sub_I_main:
    .fnstart
.LFB1422:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    push    {r4, lr}
    movw    r4, #:lower16:.LANCHOR0
    movt    r4, #:upper16:.LANCHOR0
    mov r0, r4
    bl  _ZNSt8ios_base4InitC1Ev
    mov r0, r4
    movw    r1, #:lower16:_ZNSt8ios_base4InitD1Ev
    movw    r2, #:lower16:__dso_handle
    movt    r1, #:upper16:_ZNSt8ios_base4InitD1Ev
    movt    r2, #:upper16:__dso_handle
    pop {r4, lr}
    b   __aeabi_atexit
    .cantunwind
    .fnend
    .size   _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
    .section    .init_array,"aw",%init_array
    .align  2
    .word   _GLOBAL__sub_I_main(target1)
    .section    .rodata.str1.4,"aMS",%progbits,1
    .align  2
.LC0:
    .ascii  "loop took \000"
    .space  1
.LC1:
    .ascii  "seconds\000"
    .bss
    .align  2
.LANCHOR0 = . + 0
    .type   _ZStL8__ioinit, %object
    .size   _ZStL8__ioinit, 1
_ZStL8__ioinit:
    .space  1
    .hidden __dso_handle
    .ident  "GCC: (Ubuntu/Linaro 4.8.1-10ubuntu7) 4.8.1"
    .section    .note.GNU-stack,"",%progbits
4

1 回答 1

1

问:为什么编译器会为循环部分输出如此不同的汇编代码?

原因很简单。

在第一种情况下(乘法循环),编译器能够自动矢量化循环并使用 NEON 单元的 SIMD 功能。

在第二种情况下,编译器并不那么聪明。它没有找到向量化循环的方法,因此没有使用 NEON,而是使用了 vfp 指令集。

据我所知,您可以使用选项强制编译器使用 NEON 而不是 FPU。但是,这是否会提高性能或不很大程度上取决于浮点代码的性质。

于 2014-01-10T13:17:10.330 回答