Previous ToC Next

150. A64fx におけるアセンブラルーチンの書き方の初歩以前 (2020/08/30)

例えば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 と Procedure call standard for the ARM 64-bit Architecture (AArch64) with SVE support には書いてある。なのでこれはセーブ/リストアする必要あり。

d0 と z0.d[0] は同じものである。

xレジスタには

    mov     x1, 1777
    add     x7, x0, :lo12:vars_
    add     x0, x7, 12288
という形で即値の代入と加算ができる。

あとはスタックポインタはそこから下のアドレスがスタック領域であるとかくらい?
Previous ToC Next