ARM アセンブラ 簡単命令でソート処理
アセンブラのプログラミング経験が皆無なので、とにかく簡単なプログラムを組んでみました。4つの整数についてソート、合計、平均、範囲を求めるプログラムです。
#include <stdio.h>
int main(int argc, char *argv[])
{
register int v0;
register int v1;
register int v2;
register int v3;
register int sum;
register int avg;
register int rng;
register int tmp;
v0 = atoi(argv[1]); v1 = atoi(argv[2]);
v2 = atoi(argv[3]); v3 = atoi(argv[4]);
printf("%d\t%d\t%d\t%d\n", v0, v1, v2, v3);
// Sort
asm volatile(" \
srt00: CMP %0, %1; \
BLE srt01; \
MOV %4, %0; \
MOV %0, %1; \
MOV %1, %4; \
srt01: CMP %1, %2; \
BLE srt02; \
MOV %4, %1; \
MOV %1, %2; \
MOV %2, %4; \
srt02: CMP %2, %3; \
BLE srt10; \
MOV %4, %2; \
MOV %2, %3; \
MOV %3, %4; \
srt10: CMP %0, %1; \
BLE srt11; \
MOV %4, %0; \
MOV %0, %1; \
MOV %1, %4; \
srt11: CMP %1, %2; \
BLE srt20; \
MOV %4, %1; \
MOV %1, %2; \
MOV %2, %4; \
srt20: CMP %0, %1; \
BLE srt30; \
MOV %4, %0; \
MOV %0, %1; \
MOV %1, %4; \
srt30: NOP; \
" : "=r"(v0), "=r"(v1), "=r"(v2), "=r"(v3), "=r"(sum));
// Sum
asm volatile(" \
ADD %4, %0, %1; \
ADD %4, %4, %2; \
ADD %4, %4, %3; \
" : "=r"(v0), "=r"(v1), "=r"(v2), "=r"(v3), "=r"(sum));
// Average
asm volatile(" \
MOV %6, #0; \
AND %7, %4, #3; \
CMP %7, #1; \
MOVGT %6, #1; \
MOV %5, %4, ASR #2; \
ADD %5, %5, %6; \
" : "=r"(v0), "=r"(v1), "=r"(v2), "=r"(v3),
"=r"(sum), "=r"(avg), "=r"(rng), "=r"(tmp));
// Range
asm volatile(" \
SUB %6, %3, %0; \
" : "=r"(v0), "=r"(v1), "=r"(v2), "=r"(v3),
"=r"(sum), "=r"(avg), "=r"(rng), "=r"(tmp));
printf("%d\t%d\t%d\t%d\n", v0, v1, v2, v3);
printf("sum\t= %d\naverage\t= %d\nrange\t= %d\n", sum, avg, rng);
//printf("tmp\t= %d\n", tmp);
return 0;
}
本当はサブルーチンとか使ってエレガントに書きたかったのですが、それだけで試験当日になりそうだったので、べたに書いてみました。とりあえず、期待通りの動作を確認できて一安心です。
root@zynq:~# ./a.out 5 1 2 7
5 1 2 7
1 2 5 7
sum = 15
average = 4
range = 6
root@zynq:~# ./a.out 5 1 2 6
5 1 2 6
1 2 5 6
sum = 14
average = 4
range = 5
root@zynq:~# ./a.out 5 1 2 5
5 1 2 5
1 2 5 5
sum = 13
average = 3
range = 4
root@zynq:~# ./a.out 5 1 2 -15
5 1 2 -15
-15 1 2 5
sum = -7
average = -2
range = 20
インラインで register 変数をたくさん使うのは限界がありますね
#include <stdio.h>
int main(int argc, char *argv[])
{
register int v0;
register int v1;
register int v2;
register int v3;
register int sum;
register int avg;
register int rng;
register int tmp;
v0 = atoi(argv[1]); v1 = atoi(argv[2]);
v2 = atoi(argv[3]); v3 = atoi(argv[4]);
printf("%d\t%d\t%d\t%d\n", v0, v1, v2, v3);
// Sort
asm volatile(" \
srt00: CMP %0, %1; \
BLE srt01; \
MOV %4, %0; \
MOV %0, %1; \
MOV %1, %4; \
srt01: CMP %1, %2; \
BLE srt02; \
MOV %4, %1; \
MOV %1, %2; \
MOV %2, %4; \
srt02: CMP %2, %3; \
BLE srt10; \
MOV %4, %2; \
MOV %2, %3; \
MOV %3, %4; \
srt10: CMP %0, %1; \
BLE srt11; \
MOV %4, %0; \
MOV %0, %1; \
MOV %1, %4; \
srt11: CMP %1, %2; \
BLE srt20; \
MOV %4, %1; \
MOV %1, %2; \
MOV %2, %4; \
srt20: CMP %0, %1; \
BLE srt30; \
MOV %4, %0; \
MOV %0, %1; \
MOV %1, %4; \
srt30: NOP; \
" : "=r"(v0), "=r"(v1), "=r"(v2), "=r"(v3), "=r"(sum));
// Sum
asm volatile(" \
ADD %4, %0, %1; \
ADD %4, %4, %2; \
ADD %4, %4, %3; \
" : "=r"(v0), "=r"(v1), "=r"(v2), "=r"(v3), "=r"(sum));
// Average
asm volatile(" \
MOV %6, #0; \
AND %7, %4, #3; \
CMP %7, #1; \
MOVGT %6, #1; \
MOV %5, %4, ASR #2; \
ADD %5, %5, %6; \
" : "=r"(v0), "=r"(v1), "=r"(v2), "=r"(v3),
"=r"(sum), "=r"(avg), "=r"(rng), "=r"(tmp));
// Range
asm volatile(" \
SUB %6, %3, %0; \
" : "=r"(v0), "=r"(v1), "=r"(v2), "=r"(v3),
"=r"(sum), "=r"(avg), "=r"(rng), "=r"(tmp));
printf("%d\t%d\t%d\t%d\n", v0, v1, v2, v3);
printf("sum\t= %d\naverage\t= %d\nrange\t= %d\n", sum, avg, rng);
//printf("tmp\t= %d\n", tmp);
return 0;
}
本当はサブルーチンとか使ってエレガントに書きたかったのですが、それだけで試験当日になりそうだったので、べたに書いてみました。とりあえず、期待通りの動作を確認できて一安心です。
root@zynq:~# ./a.out 5 1 2 7
5 1 2 7
1 2 5 7
sum = 15
average = 4
range = 6
root@zynq:~# ./a.out 5 1 2 6
5 1 2 6
1 2 5 6
sum = 14
average = 4
range = 5
root@zynq:~# ./a.out 5 1 2 5
5 1 2 5
1 2 5 5
sum = 13
average = 3
range = 4
root@zynq:~# ./a.out 5 1 2 -15
5 1 2 -15
-15 1 2 5
sum = -7
average = -2
range = 20
インラインで register 変数をたくさん使うのは限界がありますね