Потребовалось написать функцию сложения векторов на Ассемблере. Использую инлайн ассемблер, встроенный в MSVS: Код (Text): void addition(){ int n = 4; __declspec(align(16)) double* a = new double[n]; __declspec(align(16)) double* b = new double[n]; __declspec(align(16)) double* c = new double[n]; for (int i = 0;i<n;i++) { a[i] = i; b[i] = i*2; c[i] = 0.0; } // C = A + B __asm{ mov eax,a mov ebx,b mov edx,c xorps ecx,ecx } for (int i = 0;i<n;i+=2){ __asm{ movapd xmm0,[eax+ecx] // Ошибка при выполнении программы нет доступа при чтении movapd xmm1,[ebx+ecx] addpd xmm0,xmm1 movapd [edx+ecx],xmm0 add ecx,16 } } Что я не правильно делаю?
Всё Главное - наивно предполагаешь, что при смешивании асм и С-кода значения установленных тобою регистров сохраняются, хотя это ес-но не так
Можно просто заюзать sse intrinsics. Код (Text): for ( int i=0; i<n; i+=2) { __m128d x = _mm_load_pd (a+i); __m128d y = _mm_load_pd (b+i); __m128d z = _mm_add_pd(x, y); _mm_store_pd (c+i, z); } С оптимизацией получаем: Код (Text): mov eax, DWORD PTR _a$[ebp] mov edx, DWORD PTR _c$[ebp] mov esi, DWORD PTR _b$[ebp] dec ecx shr ecx, 1 sub edx, eax sub esi, eax inc ecx $LL3@add: ; 7 : { ; 8 : __m128d x = _mm_load_pd (a+i); ; 9 : __m128d y = _mm_load_pd (b+i); movapd xmm0, XMMWORD PTR [esi+eax] movapd xmm1, XMMWORD PTR [eax] ; 10 : __m128d z = _mm_add_pd(x, y); addpd xmm0, xmm1 ; 11 : _mm_store_pd (c+i, z); movapd XMMWORD PTR [edx+eax], xmm0 add eax, 16 ; 00000010H sub ecx, 1 jne SHORT $LL3@add По-моему, вполне неплохо.
Какая ошибка то ? Ты уверен, что объвление выравнивает на 16 именно указатель, возвращаемый new, а не просто адрес переменной b ?!
Да я вообще уже ни в чем не уверен... Теперь всё ясно. Значит __declspec(align(#)) только для переменных... а _aligned_malloc для структур и массивов. С последним всё работает. Только объясните мне последнее: когда я пишу так mov eax,a - то в регистр eax помещается адрес начала массива или значение, хранящееся в a[0]? тогда, почему не работает lea eax,a приминительно к моей задаче?
Нет declspec нужна для 1) задания выравнивания структур при их объявлении, 2) для выравнивания адреса любой статической или локальной переменной. А _aligned_malloc юзается вместо обычных malloc\new для обеспечения выравнивания адресов динамических переменных. В твоем случае double *a - это 4-х байтная переменная в которой хранится указатель на double, поэтому declspec может выравнять адрес только самой переменной a (но не указателя, который хранится в a). А вот если объявить статический массив double a[100], то сама переменная a является массивом и соотв-но declspec выравняет его начальный адрес на заданную величину В eax помещается значение переменной a. Т.к. она объявлена как указатель на double, то соотв-но помещается значение этого указателя, т.е. адрес начала массива. А значение a[0] никак не может поместиться в eax из-за несоответсвия размера double и dword Видимо потому, что принято писать lea eax,[a]