2013-10-15 2 views
0

Я пытаюсь ускорить мой код, используя sse, и следующий код работает хорошо. В основном переменная __m128 должна указывать на 4 поплавка в строке, чтобы выполнить 4 операции одновременно.Адресация нецелого адреса и sse

Этот код эквивалентен вычислениям c[i]=a[i]+b[i] с i от 0 до 3.

float *data1,*data2,*data3 
// ... code ... allocating data1-2-3 which are very long. 
__m128* a = (__m128*) (data1); 
__m128* b = (__m128*) (data2); 
__m128* c = (__m128*) (data3); 
*c = _mm_add_ps(*a, *b); 

Однако, когда я хочу, чтобы сдвинуть чуток данные, которые я использую (см ниже), чтобы вычислить c[i]=a[i+1]+b[i] с i от 0 до 3, он craches во время выполнения.

__m128* a = (__m128*) (data1+1); // <-- +1 
__m128* b = (__m128*) (data2); 
__m128* c = (__m128*) (data3); 
*c = _mm_add_ps(*a, *b); 

Я думаю, что это связано с тем, что __m128 128 бит и поплавком данных 32 бита. Таким образом, может быть невозможно, если 128-битный указатель указывает на адрес, который не делится на 128.

В любом случае, вы знаете, в чем проблема и как я могу обойти его?

+2

У вас есть неопределенное поведение. Указатель на 'float' * не * совпадает с указателем на' __m128'. Кроме того, когда вы делаете 'data1 + 1', это то же самое, что и' & data1 [1] ', действительно ли вы выделили более одного' float' и сохранили указатель в 'data1'? –

+0

Да, в data1, data2, data3 есть много данных. Они хорошо распределены. – Oli

+0

@JoachimPileborg, Что такое undedined поведение? Я знаю, что указатели на float и __m128 различны. Вот почему я бросил. __mm128 должен указывать на 4 поплавков подряд, чтобы выполнить все 4 операции одновременно на процессоре. – Oli

ответ

5

Вместо того, чтобы использовать неявные выровненные нагрузки/магазины, как это:

__m128* a = (__m128*) (data1+1); // <-- +1 
__m128* b = (__m128*) (data2); 
__m128* c = (__m128*) (data3); 
*c = _mm_add_ps(*a, *b); 

использования явных выровненные/невыровненные нагрузки/магазины в зависимости от обстоятельств, например:

__m128 va = _mm_loadu_ps(data1+1); // <-- +1 (NB: use unaligned load) 
__m128 vb = _mm_load_ps(data2); 
__m128 vc = _mm_add_ps(va, vb); 
_mm_store_ps(data3, vc); 

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

Обратите внимание, что последние процессоры имеют относительно небольшие штрафы за невыровненные нагрузки, но на старых процессорах может быть 2x или более сильный удар.

+1

Спасибо. Это работает в моем случае, и у него мало накладных расходов. – Oli

+1

иногда перетасовывается, а затем выровненный доступ может быть быстрее, чем невысокая загрузка/хранение –

0

Я не очень хорошо знаком с sse, но я думаю, что вы можете сделать локальную (или другую копию) данных, которые должным образом назначены на 128 и содержат 4 поплавки из data1 + 1.

Надеюсь, что это поможет, Разван.

+0

Спасибо. Это определенно сработает. Но смысл sse слишком сильно делает все очень быстрым.Если мне нужно сначала скопировать, это будет медленнее, чем вообще не использовать sse. – Oli

+0

@Oli Возможно, вы захотите сначала оценить его. Копирование 16 байтов происходит очень быстро. –

1

Ваша проблема в том, что a заканчивается тем, что не является __m128; он указывает на то, что содержит последние 96 бит __m128 и 32 бит снаружи, что может быть чем угодно. Это могут быть первые 32 бита следующего __m128, но в конце концов, когда вы придете к последнему __m128 в том же блоке памяти, это будет что-то другое. Возможно, зарезервированная память, к которой вы не можете получить доступ, следовательно, к сбою.

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