Capital S
Capital S

Reputation: 63

Force arm64 gcc use instruction to construct double floating point number, no .rodata section

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

Answers (1)

Tom V
Tom V

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

Related Questions