2010-07-28 3 views
2

Многие инструкции SSE позволяют исходному операнду быть адресом с 16-байтовым выровненным адресом. Например, различные инструкции (un) pack. PUNCKLBW имеет следующую подпись:SSE2 intrinsics: непосредственно доступ к памяти

PUNPCKLBW XMM1, xmm2/M128

Теперь это не представляется возможным вообще с встроенными функциями. Похоже, что необходимо использовать _mm_load * intrinsics, чтобы читать что-либо в памяти. Это внутренняя для PUNPCKLBW:

__m128i _mm_unpacklo_epi8 (__m128i а, __m128i б);

(Насколько я знаю, тип __m128i всегда относится к регистру XMM.)

Теперь, почему это? Это довольно печально, так как я вижу некоторый потенциал оптимизации, обращаясь к памяти напрямую ...

ответ

6

Внутренние требования соответствуют относительно непосредственно фактическим инструкциям, но компиляторы не обязаны выдавать соответствующие инструкции. Оптимизация нагрузки, сопровождаемая операцией (даже когда она написана в intrinsics) в форме памяти операции, является общей оптимизацией, выполняемой всеми респектабельными компиляторами, когда это выгодно.

TLDR: записать нагрузку и операцию во встроенном режиме, и пусть компилятор оптимизирует ее.

Edit: тривиальный пример:

#include <emmintrin.h> 
__m128i foo(__m128i *addr) { 
    __m128i a = _mm_load_si128(addr); 
    __m128i b = _mm_load_si128(addr + 1); 
    return _mm_unpacklo_epi8(a, b); 
} 

Компиляция с gcc -Os -fomit-frame-pointer дает:

_foo: 
movdqa  (%rdi), %xmm0 
punpcklbw 16(%rdi), %xmm0 
retq 

См? Оптимизатор разобратся.

+0

Я бы не стал жаловаться, если компилятор оптимизировал его, но, по крайней мере, clang и gcc этого не делают. Это легко проверить с помощью опции -S. Я нахожу вербальные внутренние операции -> сборные переводы практически для любых внутренних и могут привязывать регистры непосредственно к переменным. Похоже, что эти компиляторы вряд ли оптимизируют код встроенного кода SIMD ... – dietr

+1

@dietr: clang и gcc обе делают эту оптимизацию, как вы можете видеть в моем примере. Вы строите с отключенной оптимизацией? Попробуйте использовать '-O1' или выше. –

+0

Я использую -O2. Я думаю, что gcc/clang просто не видит никакого потенциала оптимизации в моем конкретном фрагменте кода ... – dietr

3

Вы можете просто использовать свои значения памяти напрямую. Например:

__m128i *p=static_cast<__m128i *>(_aligned_malloc(8*4,16)); 

for(int i=0;i<32;++i) 
    reinterpret_cast<unsigned char *>(p)[i]=static_cast<unsigned char>(i); 

__m128i xyz=_mm_unpackhi_epi8(p[0],p[1]); 

Интересная часть результата:

; __m128i xyz=_mm_unpackhi_epi8(p[0],p[1]); 
0040BC1B 66 0F 6F 00  movdqa  xmm0,xmmword ptr [eax] 
0040BC1F 66 0F 6F 48 10 movdqa  xmm1,xmmword ptr [eax+10h] 
0040BC24 66 0F 68 C1  punpckhbw xmm0,xmm1 
0040BC28 66 0F 7F 04 24 movdqa  xmmword ptr [esp],xmm0 

Так что компилятор делает немного плохой работы - или, возможно, этот путь быстрее и/или играть с параметрами это исправит, но он генерирует код, который работает, а код на C++ указывает на то, что он хочет достаточно прямо.

Смежные вопросы