Целое число, описывающее число аргументов с плавающей запятой в регистрах xmm, не переданных в rax - PullRequest
0 голосов
/ 13 января 2019

У меня есть функция, которая объявлена ​​следующим образом:

double foo(int ** buffer, int size, ...);

Функция является частью реализации программы cpp.

Я использую последний параметр для передачи нескольких двойных переменных в функцию.

Проблема в том, что на Mac я не получаю действительный номер в регистре rax, с другой стороны, на Ubuntu он работает как положено.

Простой пример:

CPP

#include <iostream>
extern "C" double foo(int ** buffer, int buffer_size, ...);

int main() {
    int* buffer [] = {new int(2), new int(3), new int(4)};
    std::cout<< foo(buffer, 2, 1.0, 2.0, 3.0) << '\n';
    std::cout<< foo(buffer, 3, 2.0, 3.0) << '\n';
    std::cout<< foo(buffer, 3) << '\n';
}

Сборка, NASM2

global foo

section .text

foo:
    cvtsi2sd xmm0, rax
    ret

Mac выход:

1.40468e+14
1.40736e+14
1.40736e+14

Вывод Ubuntu:

3
2
0

Программа 64-битная

1 Ответ

0 голосов
/ 13 января 2019

ABI System V x86-64 сообщает, что счетчик аргументов регистра FP передается в AL, и что старшие байты RAX могут содержать мусор . (То же, что и любое узкое целое число или аргумент FP. Но см. Также в этом вопросе и ответе о clang, предполагающем расширение нуля или знака для узких целочисленных аргументов до 32 бит. Это относится только к собственно аргументам функции, а не al .)

Используйте movzx eax, al для расширения нуля AL в RAX. (Запись EAX неявно расширяется в RAX, в отличие от записи 8- или 16-битного регистра.)

Если есть еще один целочисленный регистр, который вы можете замкнуть, используйте movzx ecx,al, чтобы сработало исключение mov на процессорах Intel, обеспечивающее нулевую задержку и не требующий порт выполнения. Сбой mov-elission от Intel, когда src и dst являются частями одного и того же регистра.

Также нет нужды использовать 64-битный источник для преобразования в FP. cvtsi2sd xmm0, eax на один байт (без префикса REX), и после расширения нуля в EAX вы знаете, что интерпретация дополнения EAX и RAX со знаком 2, используемая cvtsi2sd, идентична.


На вашем Mac clang / LLVM решил оставить мусор в старших байтах RAX . Оптимизатор LLVM менее осторожен во избежании ложных зависимостей, чем gcc, поэтому он иногда будет писать частичные регистры. (Иногда даже когда это не сохраняет размер кода, но в этом случае это делает).

Исходя из ваших результатов, мы можем заключить, что вы использовали clang на Mac и gcc или ICC на Ubuntu.

Проще посмотреть на asm, генерируемый компилятором, из упрощенного примера (new и std::cout::operator<< приводят к большому количеству кода).

extern "C" double foo(int, ...);
int main() {
    foo(123, 1.0, 2.0);
}

Компилируется в этот ассм в Исследователь компилятора Godbolt , с gcc и clang -O3:

### clang7.0 -O3
.section .rodata
.LCPI0_0:
    .quad   4607182418800017408     # double 1
.LCPI0_1:
    .quad   4611686018427387904     # double 2

.text
main:                                   # @main
    push    rax                  # align the stack by 16 before a call
    movsd   xmm0, qword ptr [rip + .LCPI0_0] # xmm0 = mem[0],zero
    movsd   xmm1, qword ptr [rip + .LCPI0_1] # xmm1 = mem[0],zero
    mov     edi, 123
    mov     al, 2                # leave the rest of RAX unmodified
    call    foo
    xor     eax, eax             # return 0
    pop     rcx
    ret

GCC выдает в основном то же самое, но с

 ## gcc8.2 -O3
    ...
    mov     eax, 2               # AL = RAX = 2   FP args in regs
    mov     edi, 123
    call    foo
    ...

mov eax,2 вместо mov al,2 позволяет избежать ложной зависимости от старого значения RAX для процессоров, которые не переименовывают AL отдельно от остальной части RAX . (Это делают только семейство Intel P6 и Sandybridge, а не IvyBridge и более поздние версии. И ни какие-либо процессоры AMD, Pentium 4 или Silvermont.)

См. Как именно работают частичные регистры на Haswell / Skylake? Написание AL, похоже, ложно зависит от RAX, и AH не согласуется , чтобы больше узнать о том, как IvB и более поздние версии отличаются от Core2 / Nehalem.

...