Я пытаюсь изучить веревки SSE-intrinsics в C. У меня есть часть кода, где я загружаю двухкомпонентный вектор двойных данных, добавляю что-то к нему, а затем пытаюсь его сохранить вернуться в память. Все работает: я могу загружать свои данные в регистры SEE, я могу работать с моими данными в этих регистрах SSE, но в тот момент, когда я пытаюсь записать обработанные данные обратно в исходный массив (где я читаю свои данные из первое место!) Я получаю ошибку сегментации.SSE _mm_load_pd работает в то время как _mm_store_pd segfaults
Может кто угодно посоветуйте мне по этому вопросу - это сводит меня с ума.
double res[2] __attribute__((aligned(16)));
for(int k=0; k<n; k++){
int i=0;
for(; i+1<n; i+=2)
{
__m128d cik = _mm_load_pd(&C[i+k*n]);
int j = 0;
for(; j+1<n; j+=2)
{
__m128d aTij = _mm_load_pd(&A_T[j+i*n]);
__m128d bjk = _mm_load_pd(&B[j+k*n]);
__m128d dotpr = _mm_dp_pd(aTij, bjk,2);
cik = _mm_add_pd(cik, dotpr);
}
_mm_store_pd(res, cik);
//C[i+k*n] = res[0];
}
}
Как я уже говорил выше, все работает в этом коде для где я храню свои результаты обратно в этот одномерный массив «C», где я читал мои данные в первую очередь, за исключением. То есть, когда я раскомментировать знаки перед
//C[i+k*n] = res[0];
Я получаю ошибку сегментации.
Как возможно, что я могу читать с C с выровненной версией памяти _mm_load_pd (так что C должен быть выровнен в память!), В то время как запись на него не работает? «C» должен быть выровнен, и, как вы видите, «res» также должен быть выровнен.
Отказ от ответственности: Мой исходный код чтения
_mm_store_pd(&C[i+k*n], cik);
который также произвел ошибку сегментации, и я начал внедрять «Рес» с явным выравниванием в моей попытки решить эту проблему.
Добавление
A, B, C объявляются следующим образом:
buf = (double*) malloc (3 * nmax * nmax * sizeof(double));
double* A = buf + 0;
double* B = A + nmax*nmax;
double* C = B + nmax*nmax;
Попытка решения с posix_memalign
В попытке решить проблему ошибки сегментации при записи на оригинальный одномерный массив, теперь я использую буферы для соответствующих матриц. Тем не менее, это все еще segfauls при попытке написать обратно C_buff!
double res[2] __attribute__((aligned(16)));
double * A_T;
posix_memalign((void**)&A_T, 16, n*n*sizeof(double));
double * B_buff;
posix_memalign((void**)&B_buff, 16, n*n*sizeof(double));
double * C_buff;
posix_memalign((void**)&C_buff, 16, n*n*sizeof(double));
for(int y=0; y<n; y++)
for(int x=0; x<n; x++)
A_T[x+y*n] = A[y+x*n];
for(int x=0; x<n; x++)
for(int y=0; y<n; y++)
B_buff[y+x*n] = B[y+x*n];
for(int x=0; x<n; x++)
for(int y=0; y<n; y++)
C_buff[y+x*n] = C[y+x*n];
for(int k=0; k<n; k++){
int i=0;
for(; i+1<n; i+=2)
{
__m128d cik = _mm_load_pd(&C_buff[i+k*n]);
int j = 0;
for(; j+1<n; j+=2)
{
__m128d aTij = _mm_load_pd(&A_T[j+i*n]);
__m128d bjk = _mm_load_pd(&B_buff[j+k*n]);
__m128d dotpr = _mm_dp_pd(aTij, bjk,2);
cik = _mm_add_pd(cik, dotpr);
}
_mm_store_pd(&C_buff[i+k*n], cik);
//_mm_store_pd(res, cik);
//C_buff[i+k*n] = res[0];
//C_buff[i+1+k*n] = res[1];
}
}
Как объявляется 'C'? –
@TonyTheLion см. Добавление в вопросе. Насколько я понимаю, malloc пытается выровнять кусок памяти, который он выделяет, но не всегда преуспевает для всех целей. Мое основное недоумение в связи с вышеизложенным заключается в том, что я могу читать из этого конкретного места в «С», но не могу писать на него. Таким образом, «С» отображается с выравниванием с целью чтения, но не для записи? – 2013-03-18 12:15:22
Я думаю, что, исходя из предположения, что 'malloc' будет выровнять что-либо, есть iffy, вы можете использовать [' aligned_alloc'] (http://man7.org/linux/man-pages/man3/posix_memalign.3.html), если вы используете GCC или ['_aligned_malloc'] (http://msdn.microsoft.com/en-us/library/8z34s9c6%28VS.80%29.aspx), если вы используете MSVC. –