SSE2 (базовый уровень для x86-64) содержит инструкции по перемещению данных непосредственно между XMM и целыми регистрами (без перескакивания через память). Это легко для элемента с низким значением вектора: MOVD or MOVQ. Чтобы извлечь более высокие элементы, вы можете просто перетасовать элемент, который вы хотите, до нижнего элемента вектора.
SSE4.1 также добавил вставку/извлечение для размеров, отличных от 16-разрядных (например, PEXTRQ). Помимо кода-размера, это not actually faster than a separate shuffle and movq on any existing CPUs, но это означает, что вам не нужны дополнительные регистры tmp.
#SSE4.1
movq rax, xmm0 # low qword
pextrq rdx, xmm0, 1 # high qword
# 128b result in rdx:rax, ready for use with div r64 for example.
# (But watch out for #DE on overflow)
# also ready for returning as a __int128_t in the SystemV x86-64 ABI
#SSE2
movq r10, xmm0
punpckhqdq xmm0, xmm0 # broadcast the high half of xmm0 to both halves
movq r9, xmm0
PUNPCKHQDQ - самый эффективный способ сделать это. Он работает даже на старых процессорах с медленными тасованиями для размеров элементов размером менее 64 бит, например, 65 нм Core2 (Merom/Conroe). См. my horizontal sum answer для получения более подробной информации. PUNPCKHQDQ не имеет непосредственного операнда и является только SSE2, поэтому это всего лишь 4 байта кода.
Чтобы сохранить исходное значение xmm0, используйте pshufd
с другим адресом. Или обменять верхние и нижние половинки на месте или что-то еще.
movlpd или movhpd ...
Там нет смысла никогда не использовать их. Вместо этого используйте movlps/movhps, потому что они короче, и никакие CPU не заботятся о float и double.
Вы можете использовать movhlps xmm1, xmm0
, чтобы извлечь большую половину xmm0 в другой регистр, но смешивание FP-тасов с целыми векторами приведет к задержкам перехвата на некоторых процессорах (в частности, Intel Nehalem). Также будьте осторожны с зависимостью от xmm1, вызывающей узкое место задержки.
Определенно предпочитаю pshufd
для этого в целом. Но вы можете использовать movhlps
, если вы настроитесь на определенный процессор, такой как Core2, где movhlps
работает быстро и работает в целочисленном домене, а pshufd
работает медленно.
Компиляция 'long long f (long long __attribute __ ((vector_size (16))) x) {return x [1];}' с gcc (и версией с '0'), чтобы получить некоторые предложения ... –