Выравнивание структуры для SSE

Модератор: Модераторы разделов

BratSinot
Сообщения: 812
ОС: Slackware64

Выравнивание структуры для SSE

Сообщение BratSinot »

Доброго времени суток!

В общем имею структуру:

Код: Выделить всё

typedef struct quaternion {
    double a;
    double i;
    double j;
    double k;
} quaternion;

Если выполнить код:

Код: Выделить всё

struct quaternion n1;
<...>
__m128d n_t0 = *(__m128d *)((void *)n1+8);

То вылетает segmentation fault (если собрать с оптимизацией выше -Og, то все норм). Если использовать инструкцию для невыровненных данных:

Код: Выделить всё

__m128d n_t0 = _mm_loadu_pd((void *)n1+8);

То все нормально работает. Пробовал выровнять структуру, возможно не правильно:

Код: Выделить всё

typedef struct quaternion {
    double a;
    double i;
    double j;
    double k;
} quaternion _Alignas(16);

Ничего не изменилось.
Спасибо сказали:
Аватара пользователя
Женя Подсыпальников
Сообщения: 482

Re: Выравнивание структуры для SSE

Сообщение Женя Подсыпальников »

У меня такое на не x86 (MIPS, SHx, ARM, ...) бывало.
Там N-ник требовал и N-ную границу адреса.
А буфер непрерывный шёл, не мой, так что - только memcpy и спасало... :)

// Пробовал выровнять структуру, возможно не правильно
Дак опосля и прибавлять, поди, 16 треба ?
А коли sizeof(double) < 16 , то окно пустоты после него считается, заодно :)

// Если использовать инструкцию для невыровненных данных
А то, наверное, и есть memcpy, с промежуточным результатом на стэке ? :)
Пойдём на рыбалку !
Спасибо сказали:
BratSinot
Сообщения: 812
ОС: Slackware64

Re: Выравнивание структуры для SSE

Сообщение BratSinot »

Женя Подсыпальников писал(а):
25.03.2013 19:53
Дак опосля и прибавлять, поди, 16 треба ?
А коли sizeof(double) < 16 , то окно пустоты после него считается, заодно :)

А ну логично... а как мне узнать об этом? Ну что-то вроде sizeof(double)*2?

Женя Подсыпальников писал(а):
25.03.2013 19:53
А то, наверное, и есть memcpy, с промежуточным результатом на стэке ? :)

Нет это movups заместо movaps.
Спасибо сказали:
Аватара пользователя
Женя Подсыпальников
Сообщения: 482

Re: Выравнивание структуры для SSE

Сообщение Женя Подсыпальников »

Ух... провозился, всё тестануть хотел,
а там, оказывается, баг alignas в С++11 до gcc 4.8 исправляется... :)

Вобщем, должно корениться что-то вроде:

Код: Выделить всё

typedef float[4] sse_quant _Alignas(16);

typedef struct {
  sse_quant first;
  sse_quant second;
  sse_quant third;
  sse_quant fourth;
} quatro_quant _Alignas(16); // возможно, необязательно, ввиду порядка первой переменной

Ну, и обращатйся строго по 16-байтовым границам, и без дыр на пути :) :

Код: Выделить всё

void test()
{
  quatro_quant qq;
  //..
  __m128d test = *((__m128d *) ((void *)&qq  + _Alignof(sse_quant)));
  //..
}
Пойдём на рыбалку !
Спасибо сказали:
BratSinot
Сообщения: 812
ОС: Slackware64

Re: Выравнивание структуры для SSE

Сообщение BratSinot »

Женя Подсыпальников писал(а):
26.03.2013 03:00
а там, оказывается, баг alignas в С++11 до gcc 4.8 исправляется... :)

Я на C11 пишу :)

Женя Подсыпальников писал(а):
26.03.2013 03:00

Код: Выделить всё

void test()
{
  quatro_quant qq;
  //..
  __m128d test = *((__m128d *) ((void *)&qq  + _Alignof(sse_quant)));
  //..
}

А точно! _Alignof же еще сделали.

Дык все равно ничего же не изменилось. Если прибавлять 16, а не 8 то программа не вылетает, но она и без _Alignas так перестает вылетать и работает не правильно.
P.S. Я теперь вообще стал &n.i делать.
Спасибо сказали:
Аватара пользователя
Женя Подсыпальников
Сообщения: 482

Re: Выравнивание структуры для SSE

Сообщение Женя Подсыпальников »

Причина вылета: разадресация __m128d-ого указателя не по __m128d-ой границе .
Причина дырок ("работает не правильно"): использование double, выравненных по __m128d-ой границе, а не, например, float[4] .
Работа movups и movaps: _короткие_ вещественные, без дырок, выравненные по __m128d-ой границе в случае movаps .

Где-то ошибаюсь ? :)

// P.S. Я теперь вообще стал &n.i делать.
Коли i не на __m128d-ой границе - вылет.
Коли i - double - считается дырка после него, коли i - float[4] - считается float[4].
Пойдём на рыбалку !
Спасибо сказали:
BratSinot
Сообщения: 812
ОС: Slackware64

Re: Выравнивание структуры для SSE

Сообщение BratSinot »

Женя Подсыпальников писал(а):
26.03.2013 10:52
Причина вылета: разадресация __m128d-ого указателя не по __m128d-ой границе .
Причина дырок ("работает не правильно"): использование double, выравненных по __m128d-ой границе, а не, например, float[4] .
Работа movups и movaps: _короткие_ вещественные, без дырок, выравненные по __m128d-ой границе в случае movаps .

Где-то ошибаюсь ? :)

// P.S. Я теперь вообще стал &n.i делать.
Коли i не на __m128d-ой границе - вылет.
Коли i - double - считается дырка после него, коли i - float[4] - считается float[4].

Вы меня извините, я честно пытался, но я не понимаю что вы говорите.

Дык один черт, __m128d -- 16 байт и замена _Alignas(16) на __Alignas(__m128d) погоды не меняет.
А если включить что-то выше -O0, то он все нормально делает. Да и вообще, тут нечего же выравнивать? Тут 4 по 8 байт, всего 32 байт, нечего же выравнивать?
Спасибо сказали:
Аватара пользователя
Женя Подсыпальников
Сообщения: 482

Re: Выравнивание структуры для SSE

Сообщение Женя Подсыпальников »

ОК, я попробую поподробнее :)

- чтобы не было вылета при разадресации (__m128d*) , необходим адрес, кратный 16 байтам.
Не у структуры или чего-то ещё адрес, а у того, что мы разадресовываем. Например, &i в нашем случае.

- предположим, что выравнивание выполнено для i и следующим за ним j . Обе стоят на 16-байтовых границах.
Длина double=8 байтов. Значит, если разадресовываем 16 байтов для __m128d, начиная с i - считается 8 байтов неконтролируемого пространства, промеж i и j .

- если в целях лишь разадресация - т.е. термины SSE не интересны, хотя и употреблены в заголовке темы -
то да, нечего выравнивать. Главное, чтоб разадресация проходила по 16-кратным адресам. Либо использовать дополнительный код ассемблера в помощь (читай: "что-то выше -O0")

- если термины SSE интересны, например, планируется использовать movaps прямо и эффективно (а не дополнительный код ассемблера в помощь),
то надо принять, что оно (movaps) ожидает 16 байтов непрерывной (без дырок) памяти по адресу, кратному 16 байтов - для правильной работы.

Вот почему мне были выжны не только правильный адрес но и непрерывность памяти для операции,
т.е. использование, например, float[4] или char[16] , но не double[1] .

Но выбор пути - за Вами, конечно ! :)
Пойдём на рыбалку !
Спасибо сказали:
BratSinot
Сообщения: 812
ОС: Slackware64

Re: Выравнивание структуры для SSE

Сообщение BratSinot »

Женя Подсыпальников писал(а):
27.03.2013 11:02
Вот почему мне были выжны не только правильный адрес но и непрерывность памяти для операции,
т.е. использование, например, float[4] или char[16] , но не double[1] .

Все равно вылетает:

Код:

#include <emmintrin.h> int main(int argc, char *argv[]) { double a[4]; a[0] = 1.0; a[1] = 2.0; a[2] = 3.0; a[3] = 4.0; __m128d tmp; __asm__ ( "movapd 8%[a], %[tmp]" : : [tmp]"x"(tmp), [a]"m"(a) : "%xmm0" ); printf("%lf %lf\n", ((double *)&tmp)[0], ((double *)&tmp)[1]); return 0; }

Код:

#include <emmintrin.h> int main(int argc, char *argv[]) { float a[8]; ((double *)a)[0] = 1.0; ((double *)a)[1] = 2.0; ((double *)a)[2] = 3.0; ((double *)a)[3] = 4.0; __m128d tmp; __asm__ ( "movapd 8%[a], %[tmp]" : : [tmp]"x"(tmp), [a]"m"(a) : "%xmm0" ); printf("%lf %lf\n", ((double *)&tmp)[0], ((double *)&tmp)[1]); return 0; }

И да, как я уже сказал, дырок в структуре нет. Она четко занимает 32 байта.
Спасибо сказали:
Аватара пользователя
Женя Подсыпальников
Сообщения: 482

Re: Выравнивание структуры для SSE

Сообщение Женя Подсыпальников »

// Все равно вылетает
Не вижу замысла и адресов, к сожалению :)

// И да, как я уже сказал, дырок в структуре нет. Она четко занимает 32 байта.
Да, но тогда i не на 16-кратности адреса :)

И да, работа по выравниванию стоит того, по моему мнению:
операция movaps много быстрее movups :)
Пойдём на рыбалку !
Спасибо сказали: