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
コンパイル結果です。冒頭・末尾のアセンブラ・ディレクティブ部分は省略しています。
次に、-O3最適化でコンパイルした結果です。
$ arm-xilinx-linux-gnueabi-gcc -O3 -mfpu=neon -S int_averate.c
ざっと見た感じ、京都マイクロコンピュータさんのブログ記事とほぼ同じ結果です。レジスタの使い方が微妙に違う程度でしょうか。
「浮動小数点演算のベクタライズ」はまた明日
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
ざっと見た感じ、京都マイクロコンピュータさんのブログ記事とほぼ同じ結果です。レジスタの使い方が微妙に違う程度でしょうか。
「浮動小数点演算のベクタライズ」はまた明日