スタックを使わずに引数何個渡せるか

スタックを使わずに引数何個渡せるか調べた。

調査対象は以下の コンパイラ / コンパイラ・オプション。

|名前|コンパイラオプションなど|
|:--|:--|
|cortex-m4-hard|arm-none-eabi-gcc  -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 |
|cortex-m4-soft|arm-none-eabi-gcc  -mthumb -mcpu=cortex-m4 -mfloat-abi=soft -mfpu=fpv4-sp-d16 |
|cortex-a53-32hard|arm-none-eabi-gcc  -mcpu=cortex-a53 -mfloat-abi=hard |
|cortex-a53-32soft|arm-none-eabi-gcc  -mcpu=cortex-a53 -mfloat-abi=soft |
|cortex-a53-ilp32|aarch64-none-elf-gcc  -mabi=ilp32 -mcpu=cortex-a53 -march=armv8-a |
|cortex-a53-lp64|aarch64-none-elf-gcc  -mabi=lp64 -mcpu=cortex-a53 -march=armv8-a |
|x64ms|gcc-10 -mabi=ms  |
|x64sysv|gcc-10 -mabi=sysv  |

# まとめ

## ARM(32bit)

32bit までの整数型は整数レジスタ1個使う。4個まで使える。

Thumb でも ARM でも大差ない。

浮動小数点型は `-mfloat-abi=soft` か `-mfloat-abi=hard` かで全然ちがう。
`-mfloat-abi=hard` だと、浮動小数点数レジスタで引数渡せる。
なんと `float` なら16個、 `double` でも8個もレジスタで渡せる。

`-mfloat-abi=soft` だと、整数用の普通のレジスタで渡すので、 `float` だと 32bit レジスタ1個、 `double` だと 2個消費する。

中身にメンバが2個以上ある構造体があるとすぐにスタックに割り当てられる。
`struct { uint16_t a; };` だと1個なのでレジスタを使うけど
`struct { uint8_t a, b; };` だと2個なのでスタックを使う。

## ARM(64bit)

64bit までの整数型は整数レジスタ1個使う。8個まで使える。
浮動小数点数は `double` でも `float` でもレジスタ1個使う。8個まで使える。

ARM64 には `-mfloat-abi` みたいなものはない。

ARM(32bit) と異なり、構造体でもレジスタを使う。
`uint8_t` の限界は 8 個だけど、 `struct{ uint8_t a, b; };` でもスタックを使わずに8個渡せる。

ABI は `ilp32` と `lp64` があるんだけど、同じだった。

## amd64

amd64 の ABI は、 sysv と ms がある。
sysv は Linux などで使われている方式らしい。
ms は、 Windows で使われているらしい。

### amd64(ms)

組み込み型は4個まで渡せる。
浮動小数点数と整数は違うレジスタを使うけど、足して4個まで。

構造体は、1個のサイズが 64bit までならレジスタに乗せて、それ以上ならスタックに乗せるみたい。

### amd64(sysv)

整数型は 6個 まで渡せる。
それとは別に、浮動小数点型を8個まで渡せる。
構造体になってもこのレジスタを使える。

# 調査

https://github.com/nabetani/arm-x64-regarg のように調査した。

本当は ABI のドキュメントを読めばいいんだろうけど、アセンブラを吐かせて調べた。

## 一種類の型

表内の数字は、スタックを使わないで引数を渡せる個数。

### 組み込み型

|命令セット|条件|`char`|`short`|`int32_t`|`int64_t`|`void*`|`float`|`double`|
|:--|:--|--:|--:|--:|--:|--:|--:|--:|
|ARM(32bit)|cortex-a53-32hard|4|4|4|2|4|16|8|
|ARM(32bit)|cortex-a53-32soft|4|4|4|2|4|4|2|
|ARM(32bit, Thumb)|cortex-m4-hard|4|4|4|2|4|16|8|
|ARM(32bit, Thumb)|cortex-m4-soft|4|4|4|2|4|4|2|
|ARM(64bit)|cortex-a53-ilp32|8|8|8|8|8|8|8|
|ARM(64bit)|cortex-a53-lp64|8|8|8|8|8|8|8|
|amd64|x64ms|4|4|4|4|4|4|4|
|amd64|x64sysv|6|6|6|6|6|8|8|

### 構造体

|命令セット|条件|`char × 2`|`short × 1`|`int32_t × 2`|`int32_t × 4`|`int32_t + float`|`int32_t + double`|
|:--|:--|--:|--:|--:|--:|--:|--:|
|ARM(32bit)|cortex-a53-32hard|0|4|0|0|0|0|
|ARM(32bit)|cortex-a53-32soft|0|4|0|0|0|0|
|ARM(32bit, Thumb)|cortex-m4-hard|0|4|0|0|0|0|
|ARM(32bit, Thumb)|cortex-m4-soft|0|4|0|0|0|0|
|ARM(64bit)|cortex-a53-ilp32|8|8|8|4|8|4|
|ARM(64bit)|cortex-a53-lp64|8|8|8|4|8|4|
|amd64|x64ms|4|4|4|0|4|0|
|amd64|x64sysv|6|6|6|3|6|6|

## 複数の型の混在

✅ は、レジスタのみで渡せる。
❌ は、スタックを使う。

### double＼int32_t


#### cortex-a53-32hard

|double＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|2|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|3|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|4|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|5|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|6|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|7|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|8|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|9|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-a53-32soft

|double＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|2|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-a53-ilp32

|double＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|2|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|3|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|4|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|5|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|6|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|7|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|8|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|9|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-a53-lp64

|double＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|2|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|3|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|4|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|5|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|6|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|7|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|8|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|9|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-m4-hard

|double＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|2|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|3|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|4|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|5|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|6|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|7|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|8|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|9|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-m4-soft

|double＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|2|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### x64ms

|double＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|❌|❌|❌|❌|❌|❌|
|2|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|3|✅|❌|❌|❌|❌|❌|❌|❌|❌|
|4|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### x64sysv

|double＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|2|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|3|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|4|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|5|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|6|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|7|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|8|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|9|❌|❌|❌|❌|❌|❌|❌|❌|❌|

### float＼int32_t


#### cortex-a53-32hard

|float＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|2|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|3|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|4|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|5|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|6|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|7|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|8|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|9|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|10|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|11|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|12|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|13|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|14|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|15|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|16|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|17|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-a53-32soft

|float＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|❌|❌|❌|❌|❌|❌|
|2|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|3|✅|❌|❌|❌|❌|❌|❌|❌|❌|
|4|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-a53-ilp32

|float＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|2|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|3|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|4|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|5|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|6|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|7|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|8|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|9|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-a53-lp64

|float＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|2|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|3|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|4|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|5|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|6|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|7|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|8|✅|✅|✅|✅|✅|✅|✅|✅|❌|
|9|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-m4-hard

|float＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|2|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|3|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|4|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|5|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|6|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|7|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|8|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|9|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|10|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|11|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|12|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|13|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|14|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|15|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|16|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|17|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-m4-soft

|float＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|❌|❌|❌|❌|❌|❌|
|2|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|3|✅|❌|❌|❌|❌|❌|❌|❌|❌|
|4|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### x64ms

|float＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|❌|❌|❌|❌|❌|❌|
|2|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|3|✅|❌|❌|❌|❌|❌|❌|❌|❌|
|4|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### x64sysv

|float＼int32_t|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|2|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|3|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|4|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|5|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|6|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|7|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|8|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|9|❌|❌|❌|❌|❌|❌|❌|❌|❌|

### int32_t＼short


#### cortex-a53-32hard

|int32_t＼short|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|❌|❌|❌|❌|❌|❌|
|2|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|3|✅|❌|❌|❌|❌|❌|❌|❌|❌|
|4|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-a53-32soft

|int32_t＼short|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|❌|❌|❌|❌|❌|❌|
|2|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|3|✅|❌|❌|❌|❌|❌|❌|❌|❌|
|4|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-a53-ilp32

|int32_t＼short|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|✅|✅|✅|❌|❌|
|2|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|3|✅|✅|✅|✅|✅|❌|❌|❌|❌|
|4|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|5|✅|✅|✅|❌|❌|❌|❌|❌|❌|
|6|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|7|✅|❌|❌|❌|❌|❌|❌|❌|❌|
|8|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-a53-lp64

|int32_t＼short|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|✅|✅|✅|❌|❌|
|2|✅|✅|✅|✅|✅|✅|❌|❌|❌|
|3|✅|✅|✅|✅|✅|❌|❌|❌|❌|
|4|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|5|✅|✅|✅|❌|❌|❌|❌|❌|❌|
|6|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|7|✅|❌|❌|❌|❌|❌|❌|❌|❌|
|8|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-m4-hard

|int32_t＼short|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|❌|❌|❌|❌|❌|❌|
|2|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|3|✅|❌|❌|❌|❌|❌|❌|❌|❌|
|4|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### cortex-m4-soft

|int32_t＼short|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|❌|❌|❌|❌|❌|❌|
|2|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|3|✅|❌|❌|❌|❌|❌|❌|❌|❌|
|4|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### x64ms

|int32_t＼short|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|❌|❌|❌|❌|❌|❌|
|2|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|3|✅|❌|❌|❌|❌|❌|❌|❌|❌|
|4|❌|❌|❌|❌|❌|❌|❌|❌|❌|

#### x64sysv

|int32_t＼short|1|2|3|4|5|6|7|8|9|
|:--|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|✅|✅|✅|✅|✅|❌|❌|❌|❌|
|2|✅|✅|✅|✅|❌|❌|❌|❌|❌|
|3|✅|✅|✅|❌|❌|❌|❌|❌|❌|
|4|✅|✅|❌|❌|❌|❌|❌|❌|❌|
|5|✅|❌|❌|❌|❌|❌|❌|❌|❌|
|6|❌|❌|❌|❌|❌|❌|❌|❌|❌|

# 感想

8bit 整数をレジスタに4個つめたりするんだろうと思ってたんだけど、そういうことはないみたいで、意外だった。

ARM32 で構造体がすぐにスタックに行くのは、昔は構造体を引数に渡す習慣がなくて軽視されていたからかなと思う。