例えば2つポインタ渡す関数なら以下のように書けばよいらしい。
.arch armv8-a+fp16+sve
.file "testasm.c"
.text
.align 2
.p2align 3,,7
.global svefadd
.type svefadd, %function
svefadd:
.LFB0:
.cfi_startproc
ptrue p7.d, all
ld1d z0.d, p7/z, [x0]
ld1d z1.d, p7/z, [x1]
fadd z0.d, z1.d, z0.d
st1d z0.d, p7, [x0]
ret
.cfi_endproc
.LFE0:
.size svefadd, .-svefadd
.ident "GCC: (GNU) 8.2.1 20180905 (Red Hat 8.2.1-3)"
.section .note.GNU-stack,"",@progbits
引数8個までならこれで渡せる。呼ぶほうはこんなに感じ。
//
// svetest.c
//
#include <stdio.h>
void svefadd(double *, double*);
void dump_sveval(char* name, double* x)
{
int i;
printf("%s", name);
for(i=0;i<8;i++) printf(" %e",x[i] );
printf("\n");
}
int main() {
int i,n;
double x[8]={0,1,2,3,4,5,6,7};
double y[8]={0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8};
dump_sveval("x", x);
dump_sveval("y", y);
svefadd(x,y);
dump_sveval("x after call", x);
return 0;
}
アセンブラの側では単にポインタなので、ポインタ型であれば別に svefloat
とかでなくてもかまわない。
もっと沢山渡すなら、
単純な方針は引数を配列にいれておいて、その配列の先頭アドレスを
渡すことである。そうすると、そのアドレスが x0 レジスタで見える。
関数呼び出しのオーバーヘッドを測定した。上の関数を100M回呼び出すと2.2
秒なので、45M回/秒。あるいは 22ns/call = 44 cycles/call。とはいえ上の
は load + add だけで20サイクルかかるはずなので、実際のオーバーヘッドは
20サイクル程度と思われる。
Armv8-A Instruction Set Architecture
によれば Procedure Call Standard は
x0-x7: parameter and result
x8: xr (indirect result register)
x9-15: corruptable
x16-18: used
x19-29: callee-saved 使うならセーブ/リストアをこちらでする。
floating-point registers:
d0-d7: parameters and results
d8-d31: callee-saved
d8-d15 だけが callee-saved と