2016-12-19 5 views
4

Как разбить 128-битный регистр xmm на два 64-битных квадратика?Как разбить 128-битный регистр XMM на два 64-битных целочисленных регистра?

У меня есть очень большое количество в xmm1 и хочет получить высшее четверное слово в r9 и нижней четверное слово к r10 или RAX и RDX.

movlpd или movhpd работает только с регистром памяти или наоборот.

+1

Компиляция 'long long f (long long __attribute __ ((vector_size (16))) x) {return x [1];}' с gcc (и версией с '0'), чтобы получить некоторые предложения ... –

ответ

4

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 работает медленно.