Беззнаковое 64-битное в двойное преобразование: почему этот алгоритм из g ++
Использование g ++ 4.9.2, если я скомпилирую
bool int_dbl_com(const unsigned long long x, const double y)
{
return x <= y;
}
тогда вывод ассемблера (для соглашения о вызовах Windows x64):
testq %rcx, %rcx # x in RCX
js .L2
pxor %xmm0, %xmm0
cvtsi2sdq %rcx, %xmm0
ucomisd %xmm0, %xmm1 # y in XMM1
setae %al
ret
Командаcvtsi2sdq
являетсяподписанный преобразование, и первая комбинация теста и прыжка должна проверить,%rcx < 0
, Если так, мы идем к L2, и это я не понимаю:
.L2:
movq %rcx, %rax
andl $1, %ecx
pxor %xmm0, %xmm0
shrq %rax
orq %rcx, %rax
cvtsi2sdq %rax, %xmm0
addsd %xmm0, %xmm0
ucomisd %xmm0, %xmm1
setae %al
ret
Наивно, вы могли бы вдвое%rcx
, конвертировать в двойной в%xmm0
, а затем добавить%xmm0
вернуть себе исходное значение (принимая, конечно, что вы потеряли некоторую низкую точность, переходя от 64-разрядного целого числа к 64-разрядному с плавающей точкой).
Но это не то, что делает код: похоже, он сохраняет младший бит%rcx
и затем возвращает это к результату. Зачем?? И зачем беспокоиться, если эти младшие биты все равно будут потеряны (или я здесь ошибаюсь)?
(Кажется, один и тот же алгоритм используется независимо от оптимизации; здесь я использовал -O3, чтобы его было легче увидеть.)