В продолжение моего
предыдущего сообщения. Под Win64 обычно SSE/AVX-ориентированные вычисления с плавающей точкой. Я провел простенькое тестирование трех вариантов под 64b Win 7. В случае доступного мне компилятора (Embarcadero RAD Studio XE7) стандартный логический тип имеет длину 8 бит; значение
True кодируется одной 1, а False – нулями.
Для сравнения написано три крошечные функции. Функции имеют один аргумент типа числа двойной точности с плавающей запятой, который при вызове заносится в
xmm0; не вызывают другие функции (листовые), результат логического типа возвращают в
al. Функции Lt1 и Lt2 выполняют сравнение аргумента "на меньше" числа в переменной
c, а функция Eq проверяет на равенство аргумента со значением в
c.
Тело Lt1:
Код:
comisd xmm0, [c]
setb al
Тело Lt2:
Код:
movsd xmm1, [c]
cmpsd xmm0, xmm1, 001b
movmskpd eax, xmm0
До X7 в компиляторе был «баг movq»: например, по инструкции
movq rax, xmm2 компилятор генерировал код, приводящий к перемещению данных из
xmm2 в xmm0. В X7 этот баг вроде бы починили, но я столкнулся с тем что
cmpsd xmm0, mem128, 001b в доступной мне версии компилятора не работает. Поэтому пришлось загружать значение из переменной
c в
xmm1.
Тело Eq:
Код:
movq rax, xmm0
xor rax, [c]
setz al
Для тестирования скоростей выполнения были созданы три процедуры: Lt1_tst, Lt2_tst, Eq_tst.
В теле этих процедур в цикле выполнялись соответствующие тела функций. Для имитации передачи параметра выполнялось копирование аргумента из переменной
d в
xmm0. Число повторений (
rep) 5000000000.
Тело Lt1_tst:
Код:
mov rcx, [rep]
@loop:
comisd xmm0, [c]
setb al
sub rcx, 1
jnz @loop
Тело Lt2_tst:
Код:
mov rcx, [rep]
@loop:
movsd xmm0, [d]
movsd xmm1, [c]
cmpsd xmm0, xmm1, 001b
movmskpd eax, xmm0
sub rcx, 1
jnz @loop
Тело Eq_tst:
Код:
mov rcx, [rep]
@loop:
movsd xmm0, [d]
movq rax, xmm0
xor rax, [c]
setz al
sub rcx, 1
jnz @loop
Т.е. тела функций вставлены в одно и то же "окружение".
На Sandy Bridge время выполнения Lt1_tst равно приблизительно
времени выполнения Eq_tst, а время выполнения Lt2_tst было приблизительно равно времени выполнения Eq_tst, как при значении аргумента или
порядка 1, так и при денормализованном значении.
В общем, ускорить сравнение на равенство для денормализованных при помощи
xor не получилось.