Оптимизация инициализации массива - PullRequest
33 голосов
/ 19 июня 2019

При компиляции следующего фрагмента кода (clang x86-64 -O3)

std::array<int, 5> test()
{
    std::array<int, 5> values {{0, 1, 2, 3, 4}};
    return values;
}

Было получено типичная сборка, которую я ожидал

test():                               # @test()
        mov     rax, rdi
        mov     ecx, dword ptr [rip + .L__const.test().values+16]
        mov     dword ptr [rdi + 16], ecx
        movups  xmm0, xmmword ptr [rip + .L__const.test().values]
        movups  xmmword ptr [rdi], xmm0
        ret
.L__const.test().values:
        .long   0                       # 0x0
        .long   1                       # 0x1
        .long   2                       # 0x2
        .long   3                       # 0x3
        .long   4                       # 0x4

Однако для небольших массивов, кажется, удалось выяснить трюк?

std::array<int, 3> test()
{
    std::array<int, 3> values {{0, 1, 2}};
    return values;
}

Этот был соответствующей сборкой

test():                               # @test()
        movabs  rax, 4294967296
        mov     edx, 2
        ret

Откуда этот магический номер (4294967296) откуда?По сути, это значение, которое может быть reinterpret_cast обратно в массив int каким-либо образом?

1 Ответ

41 голосов
/ 19 июня 2019

A std::array<int, 3> имеет ширину 96 бит в вашей реализации. Таким образом, ABI заявляет, что он должен быть возвращен в RAX + младшие 32 бита RDX (он же EDX).

4294967296 - 2 32 , в шестнадцатеричном - $1'0000'0000. Таким образом, movabs хранит 0 в младших 32 битах RAX и 1 в старших битах RAX. mov хранит 2 в EDX (это именно то, что вы хотели).

...