Reputation: 63
ARM64 instructions are 32-bit long, so normally a data section is used to store literals if one wants to use a 64-bit floating point constant number.
However, I found in some cases where AArch64 gcc compiler uses several instructions to construct a double floating point number from immediates instead of storing the constant in data section. Is there a way to force this feature?
I do not want to introduce data section in my embedded code.
000000000044fda0 <foo>: 1.1, 2.2
44fda0: d2800000 mov x0, #0x0 // #0
44fda4: b0000002 adrp x2, 450000 <pmalloc+0x78> // cal data address
44fda8: b0000001 adrp x1, 450000 <pmalloc+0x78>
44fdac: fd472c41 ldr d1, [x2, #3672] // load the double
44fdb0: fd473020 ldr d0, [x1, #3680]
44fdb4: 6d000001 stp d1, d0, [x0]
...
44fdbc: d65f03c0 ret
000000000044fda0 <foo>: 5.5, 6.6
44fda0: d2800000 mov x0, #0x0 // #0
44fda4: b203e7e1 mov x1, #0x6666666666666666 // #7378697629483820646
44fda8: 1e62d001 fmov d1, #5.500000000000000000e+00
44fdac: f2e80341 movk x1, #0x401a, lsl #48
44fdb0: 9e670020 fmov d0, x1
44fdb4: 6d000001 stp d1, d0, [x0]
...
44fdbc: d65f03c0 ret
I want gcc to not use any data section for constructing the double floating literal or integral literal like the second foo
function I showed.
I am with the following gcc compiler
$ aarch64-linux-gnu-gcc --version
aarch64-linux-gnu-gcc (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
My C code is float.c
void foo(void* base_ptr)
{
double buffer[2]= {5.5, 6.6};
double* q = (double*)base_ptr;
*q++ = buffer[0];
*q = buffer[1];
return ;
}
int main() {
double f[2];
foo(f);
}
For {5.5, 6.6}
, the compiler will construct the literal by shift and bit or instructions. However, when you change {5.5, 6.6}
to {1.1, 2.2}
, the compiler will store the constant literals in a data section and use adrp
instruction to load the address and fetch them.
for {5.5, 6.6}
$ aarch64-linux-gnu-gcc float.c
$ aarch64-linux-gnu-objdump -d a.out | grep -A15 '<foo>:'
00000000000007b4 <foo>:
7b4: a9bc7bfd stp x29, x30, [sp, #-64]!
7b8: 910003fd mov x29, sp
7bc: f9000fa0 str x0, [x29, #24]
7c0: 90000080 adrp x0, 10000 <__FRAME_END__+0xf6d8>
7c4: f947f000 ldr x0, [x0, #4064]
7c8: f9400001 ldr x1, [x0]
7cc: f9001fa1 str x1, [x29, #56]
7d0: d2800001 mov x1, #0x0 // #0
7d4: 1e62d000 fmov d0, #5.500000000000000000e+00
7d8: fd0017a0 str d0, [x29, #40]
7dc: b203e7e0 mov x0, #0x6666666666666666 // #7378697629483820646
7e0: f2e80340 movk x0, #0x401a, lsl #48
7e4: 9e670000 fmov d0, x0
7e8: fd001ba0 str d0, [x29, #48]
7ec: f9400fa0 ldr x0, [x29, #24]
for {1.1, 2.2}
$ aarch64-linux-gnu-objdump -d a.out | grep -A15 '<foo>:'
00000000000007b4 <foo>:
7b4: a9bc7bfd stp x29, x30, [sp, #-64]!
7b8: 910003fd mov x29, sp
7bc: f9000fa0 str x0, [x29, #24]
7c0: 90000080 adrp x0, 10000 <__FRAME_END__+0xf6b8>
7c4: f947f000 ldr x0, [x0, #4064]
7c8: f9400001 ldr x1, [x0]
7cc: f9001fa1 str x1, [x29, #56]
7d0: d2800001 mov x1, #0x0 // #0
7d4: 90000000 adrp x0, 0 <_init-0x620>
7d8: 9124e000 add x0, x0, #0x938
7dc: fd400000 ldr d0, [x0]
7e0: fd0017a0 str d0, [x29, #40]
7e4: 90000000 adrp x0, 0 <_init-0x620>
7e8: 91250000 add x0, x0, #0x940
7ec: fd400000 ldr d0, [x0]
It's a really strange feature. I want a compiler option to switch this on and off.
Upvotes: 3
Views: 556
Reputation: 5510
The option you want is called -mslow-flash-data
but the manual for my gcc version at least says this is only supported for ARMv7M architecture.
Upvotes: 1