Почему присвоение элементу массива AVX-Vector-wrapper-class-object-array вызывает ошибки нарушения доступа?

Я пытаюсь сделать кое-что векторное и написал оболочку для типа данных m256d из immintrin.h для использования перегруженных операторов. Следующий пример должен дать вам основную идею.

Определение класса

#include <immintrin.h>
using namespace std;
class vwrap {
public:
  __m256d d;
  vwrap(void) { 
    this->d = _mm256_set_pd(0.0,0.0,0.0,0.0); 
  }
  void init (const double &a, const double &b, const double &c) { 
    this->d = _mm256_set_pd(0.0,c,b,a);
  }
};

Массив объектов vwrap

Давайте представим массив vwrap, который выделяется динамически:

vwrap *a = (vwrap*) malloc(sizeof(vwrap)*2);

Ошибки нарушения доступа

Использование функции объекта vwrap, который содержит функцию-набор mm256... провоцирует ошибку нарушения доступа.

a[0].init(1.3,2.3,1.2);

То же самое происходит с назначением d с помощью функции набора mm256 (назначение другого объекта m256d также не работает):

a[0].d = _mm256_set_pd(1,2,3,4);

Копирование данных из другого объекта тоже не работает.

vwrap b;
a[0].d = b.d;

Материал, который работает

Объектом m256d можно манипулировать без проблем:

a[0].d.m256d_f64[0] = 1.0;
a[0].d.m256d_f64[1] = 2.0;
a[0].d.m256d_f64[2] = 3.0;
a[0].d.m256d_f64[3] = 4.0;

Назначения работают в случае обычного экземпляра класса:

vwrap b,c;
__mm256d t = _mm256_set_pd(1,2,3,5);
b.d = _mm256_set_pd(1,2,3,4); 
b.d = t;
b.d = c.d;

Я не понимаю проблемы. Почему я не могу использовать функции _mm256 (или назначить m256d-объект) в случае массива классов? Моя единственная идея - избегать использования функций mm256 и напрямую манипулировать двойными значениями. Но это не то, что я намеренно хотел сделать.

1 ответ

Решение

Это, скорее всего, проблема с выравниванием. __m256d необходимо выровнять по 32 байтовым границам. Вы не должны использовать malloc когда выравнивание является проблемой, используйте new или выровненный malloc,

Переменные, выделенные в стеке, работают правильно: компилятор правильно их выравнивает, потому что знает, что они должны быть выровнены. Принимая во внимание, когда вы звоните malloc, среда выполнения не знает, что вы планируете хранить в памяти, которую она вам дает. Поэтому вам нужно явно запросить выравнивание, используя выровненный malloc или используйте распределение с учетом типа, что new для.

изменения

vwrap *a = (vwrap*) malloc(sizeof(vwrap)*2);

в

vwrap *a = new vwrap[2];

vwrap *a = (vwrap*) _aligned_malloc(sizeof(vwrap)*2, 32);

должно сработать.

РЕДАКТИРОВАТЬ: после того, как попробовать это в Windows с GCC 4.6.1 (переключатель компилятора -march=corei7-avx) похоже на то new не соблюдает требования выравнивания. Изменение нового вызова на использование _aligned_malloc работает.

Другие вопросы по тегам