目的
昨日x86 CPU上で浮動小数がどう扱われるか調べました。
小数→浮動小数点形式の変換方法は以下の記事をご参照下さい。
浮動小数点形式そのものはx86でもARMでも変わりません。
x86 CPUにおける浮動小数点の処理とアセンブリ命令の対応
今日は32bit/64bitのARM上での扱いを調べてみます。
Cソース
gcc -O0 -S test.c -o test.s
#include <stdio.h>
int main() {
float f1 = 1.5f, f2 = 2.25f;
double d1 = 3.125, d2 = 4.875;
float fsum = f1 + f2;
double dsum = d1 + d2;
return 0;
}
生成されたアセンブリ
Armbian 32bit
.arch armv7-a
.fpu vfpv3-d16
.eabi_attribute 28, 1
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 34, 1
.eabi_attribute 18, 4
.file "test.c"
.text
.align 1
.global main
.syntax unified
.thumb
.thumb_func
.type main, %function
main:
@ args = 0, pretend = 0, frame = 40
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
push {r7}
sub sp, sp, #44
add r7, sp, #0
mov r3, #1069547520
str r3, [r7, #36] @ float
mov r3, #0
movt r3, 16400
str r3, [r7, #32] @ float
mov r2, #0
mov r3, #0
movt r3, 16393
strd r2, [r7, #24]
mov r2, #0
mov r3, #32768
movt r3, 16403
strd r2, [r7, #16]
vldr.32 s14, [r7, #36]
vldr.32 s15, [r7, #32]
vadd.f32 s15, s14, s15
vstr.32 s15, [r7, #12]
vldr.64 d6, [r7, #24]
vldr.64 d7, [r7, #16]
vadd.f64 d7, d6, d7
vstr.64 d7, [r7]
movs r3, #0
mov r0, r3
adds r7, r7, #44
mov sp, r7
@ sp needed
ldr r7, [sp], #4
bx lr
.size main, .-main
.ident "GCC: (Debian 12.2.0-14+deb12u1) 12.2.0"
.section .note.GNU-stack,"",%progbits
Termux 64bit
.file "test.c"
.text
.globl main // -- Begin function main
.p2align 2
.type main,@function
main: // @main
.cfi_startproc
// %bb.0:
sub sp, sp, #48
.cfi_def_cfa_offset 48
mov w0, wzr
str wzr, [sp, #44]
fmov s0, #1.50000000
str s0, [sp, #40]
fmov s0, #2.25000000
str s0, [sp, #36]
fmov d0, #3.12500000
str d0, [sp, #24]
mov x8, #140737488355328 // =0x800000000000
movk x8, #16403, lsl #48
fmov d0, x8
str d0, [sp, #16]
ldr s0, [sp, #40]
ldr s1, [sp, #36]
fadd s0, s0, s1
str s0, [sp, #12]
ldr d0, [sp, #24]
ldr d1, [sp, #16]
fadd d0, d0, d1
str d0, [sp]
add sp, sp, #48
.cfi_def_cfa_offset 0
ret
.Lfunc_end0:
.size main, .Lfunc_end0-main
.cfi_endproc
// -- End function
.ident "clang version 20.1.8"
.section ".note.GNU-stack","",@progbits
アセンブリの解説
32ビット
mov rX, #0
は全ビットを0で初期化している。
movt
は上位16ビットのみに書き込む命令。
全ビットを0で初期化した後にmovt
命令にて上位16ビットを書き換えることで、下位16ビットは0のままとなる。(=下位16ビットに余計なデータが入らないことを保障できる)
strd
は指定したレジスタrX
tとrX+1
2つのレジスタに保存された値を64ビットの値としてメモリへ保存する。
具体的にはstrd rX, [rY] ; rX:rX+1 の64bitを [rY] に書き込む
float 1.5
1.5
の浮動小数点形式は1069547520
mov r3, #1069547520
str r3, [r7, #36] @ float
float 2.25
2.25
の浮動小数点形式は1074790400
r3
の上位16ビットに16400
を書き込むと、r3 = 0x40100000 (1074790400)
mov r3, #0
movt r3, 16400
str r3, [r7, #32] @ float
double 3.125
3.125
の浮動小数点形式は1074331648
r3
の上位16ビットに16393
を書き込むと、r3 = 0x40090000 (1074331648)
[r7+24] = 0x00000000 ; 下位32bit
[r7+28] = 0x40090000 ; 上位32bit
mov r2, #0 @ 下位32bit
mov r3, #0 @ 上位32bit
movt r3, 16393
strd r2, [r7, #24]
double 4.875
4.875
の浮動小数点形式は1075019776
[r7+16] = r2 = 0x00000000 ; 下位32bit
[r7+20] = r3 = 0x400B8000 ; 上位32bit
mov r2, #0
mov r3, #32768
movt r3, 16403
strd r2, [r7, #16]
floatの加算
sレジスタ:単精度(32bit float)用
s14 = 1.5
s15 = 2.25
s15 = s14 + s15
vldr.32 s14, [r7, #36]
vldr.32 s15, [r7, #32]
vadd.f32 s15, s14, s15
vstr.32 s15, [r7, #12]
doubleの加算
dレジスタ:倍精度(64bit double)用
使用するレジスタと命令が違うだけで処理の方法は同じ。
vldr.64 d6, [r7, #24]
vldr.64 d7, [r7, #16]
vadd.f64 d7, d6, d7
vstr.64 d7, [r7]
64ビット
即値は10進数で書けるようになっている。
float 1.5
fmov s0, #1.50000000
str s0, [sp, #40]
float 2.25
fmov s0, #2.25000000
str s0, [sp, #36]
double 3.125
fmov d0, #3.12500000
str d0, [sp, #24]
double 4.875
mov x8, #140737488355328 // =0x800000000000
movk x8, #16403, lsl #48
fmov d0, x8
str d0, [sp, #16]
floatの加算
ldr s0, [sp, #40]
ldr s1, [sp, #36]
fadd s0, s0, s1
doubleの加算
str s0, [sp, #12]
ldr d0, [sp, #24]
ldr d1, [sp, #16]
fadd d0, d0, d1
動作環境
32bit
動作環境(Linux / ARM 版)
- OS: Armbian 23.08.0-trunk (Debian 12 Bookworm)
- Kernel: Linux 6.1.38-meson (armv7l)
- CPU: ARM Cortex-A5, 4 cores, Little Endian
- GCC: 12.2.0
- Architecture: armv7l
- 備考: Windows10からSSH接続して使用
動作環境確認コマンドは以下の通り
uname -a
cat /etc/os-release
gcc --version
lscpu
64bit
OPPO-A5-2020
Termux
Termuxの使い方は以前以下の記事にて纏めています。
不要になったアンドロイドをLinuxサーバにする Termuxを試す