やまものブログ

メモ書きブログです (^_^;A

ARMのNEONのSIMD命令をgccのオートベクタライズの最適化で使う方法 【再実行(整数演算のみ)】

京都マイクロコンピュータさんのブログ記事
ARMのNEONのSIMD命令をgccのオートベクタライズの最適化で使う方法
に掲載されていることを再実行してみました。


違うのはクロスコンパイラのバージョンだけ。
私のはいつものこれ↓です。
$ arm-xilinx-linux-gnueabi-gcc --version
arm-xilinx-linux-gnueabi-gcc (Sourcery CodeBench Lite 2013.05-40) 4.7.3


とりあえず、「整数演算のベクタライズ」のみ試しました。
Cソースコードは全く同じものを使わさせてもらいました。

int int_average(int* array, int size)
{
        int i;
        long long total = 0;

        if (size <= 0) {
                return 0;
        }
        for (i = 0; i < size; i++) {
                total += array[i];
        }
        return total / size;
}



まずは、これを下記の -O2最適化でコンパイルしました。
$ arm-xilinx-linux-gnueabi-gcc -O2 -mfpu=neon -S int_averate.c

本題からそれますが、-mfpu=neon の有無で変わるのは下記の1行だけで、コンパイル結果は実質同じでした。きっと、デフォルトが neon なのですね。
3c3
<       .fpu neon-fp16
---
>       .fpu neon



コンパイル結果です。冒頭・末尾のアセンブラ・ディレクティブ部分は省略しています。

int_average:
    .fnstart
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    stmfd    sp!, {r4, lr}
    .save {r4, lr}
    subs    r4, r1, #0
    ble    .L4
    mov    r3, r0
    add    lr, r3, r4, asl #2
    mov    r0, #0
    mov    r1, #0
.L3:
    ldr    ip, [r3], #4
    adds    r0, r0, ip
    adc    r1, r1, ip, asr #31
    cmp    r3, lr
    bne    .L3
    mov    r2, r4
    mov    r3, r4, asr #31
    bl    __aeabi_ldivmod
    ldmfd    sp!, {r4, pc}
.L4:
    mov    r0, #0
    ldmfd    sp!, {r4, pc}


次に、-O3最適化でコンパイルした結果です。
$ arm-xilinx-linux-gnueabi-gcc -O3 -mfpu=neon -S int_averate.c

int_average:
    .fnstart
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    cmp    r1, #0
    stmfd    sp!, {r3, r4, r5, r6, r7, r8, sl, lr}
    .save {r3, r4, r5, r6, r7, r8, sl, lr}
    ble    .L11
    sbfx    lr, r0, #2, #1
    and    lr, lr, #3
    cmp    lr, r1
    movcs    lr, r1
    cmp    r1, #3
    movls    lr, r1
    cmp    lr, #0
    beq    .L12
    sub    ip, r0, #4
    mov    r4, #0
    mov    r5, #0
    mov    r3, #0
.L5:
    ldr    r2, [ip, #4]!
    add    r3, r3, #1
    adds    r4, r4, r2
    adc    r5, r5, r2, asr #31
    cmp    r3, lr
    bcc    .L5
    cmp    r1, lr
    beq    .L6
.L4:
    rsb    sl, lr, r1
    mov    r2, sl, lsr #2
    movs    r8, r2, asl #2
    beq    .L7
    vmov.i32    q9, #0  @ v2di
    add    lr, r0, lr, asl #2
    mov    ip, #0
.L8:
    vldmia    lr!, {d16-d17}
    vmovl.s32 q10, d16
    add    ip, ip, #1
    vmovl.s32 q8, d17
    vadd.i64    q9, q10, q9
    cmp    ip, r2
    vadd.i64    q9, q8, q9
    bcc    .L8
    vadd.i64    d18, d18, d19
    add    r3, r3, r8
    vmov    r6, r7, d18  @ v2di
    adds    r4, r4, r6
    adc    r5, r5, r7
    cmp    sl, r8
    beq    .L6
.L7:
    sub    r2, r3, #1
    add    r0, r0, r2, asl #2
.L10:
    ldr    r2, [r0, #4]!
    add    r3, r3, #1
    adds    r4, r4, r2
    adc    r5, r5, r2, asr #31
    cmp    r1, r3
    bgt    .L10
.L6:
    mov    r2, r1
    mov    r0, r4
    mov    r1, r5
    mov    r3, r2, asr #31
    bl    __aeabi_ldivmod
    ldmfd    sp!, {r3, r4, r5, r6, r7, r8, sl, pc}
.L11:
    mov    r0, #0
    ldmfd    sp!, {r3, r4, r5, r6, r7, r8, sl, pc}
.L12:
    mov    r4, #0
    mov    r5, #0
    mov    r3, lr
    b    .L4

ざっと見た感じ、京都マイクロコンピュータさんのブログ記事とほぼ同じ結果です。レジスタの使い方が微妙に違う程度でしょうか。
浮動小数点演算のベクタライズ」はまた明日