Сложение массивов

Тема в разделе "WASM.BEGINNERS", создана пользователем fluck, 5 окт 2009.

  1. fluck

    fluck New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2009
    Сообщения:
    19
    Потребовалось написать функцию сложения векторов на Ассемблере. Использую инлайн ассемблер, встроенный в MSVS:
    Код (Text):
    1. void addition(){
    2.  
    3.        int n = 4;
    4.      __declspec(align(16)) double* a = new double[n];
    5.      __declspec(align(16)) double* b = new double[n];
    6.      __declspec(align(16)) double* c = new double[n];
    7.    
    8.     for (int i = 0;i<n;i++) {
    9.        a[i] = i;
    10.        b[i] = i*2;
    11.        c[i] = 0.0;
    12.     }
    13.     // C = A + B
    14.    
    15.     __asm{
    16.         mov eax,a
    17.         mov ebx,b
    18.         mov edx,c
    19.         xorps ecx,ecx
    20.     }
    21.    
    22.     for (int i = 0;i<n;i+=2){        
    23.        __asm{        
    24.           movapd xmm0,[eax+ecx] // Ошибка при выполнении программы нет доступа при чтении
    25.           movapd xmm1,[ebx+ecx]        
    26.           addpd xmm0,xmm1
    27.           movapd [edx+ecx],xmm0
    28.           add ecx,16
    29.      }
    30.    
    31.    
    32.     }
    Что я не правильно делаю?
     
  2. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Всё :)
    Главное - наивно предполагаешь, что при смешивании асм и С-кода значения установленных тобою регистров сохраняются, хотя это ес-но не так
     
  3. fluck

    fluck New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2009
    Сообщения:
    19
    угу..понял. тогда получается, что цикл тоже нужно на асме писать:
     
  4. reverser

    reverser New Member

    Публикаций:
    0
    Регистрация:
    27 янв 2004
    Сообщения:
    615
    Можно просто заюзать sse intrinsics.
    Код (Text):
    1.   for ( int i=0; i<n; i+=2)
    2.   {
    3.     __m128d x = _mm_load_pd (a+i);
    4.     __m128d y = _mm_load_pd (b+i);
    5.     __m128d z = _mm_add_pd(x, y);
    6.     _mm_store_pd (c+i, z);
    7.   }
    С оптимизацией получаем:
    Код (Text):
    1.     mov eax, DWORD PTR _a$[ebp]
    2.     mov edx, DWORD PTR _c$[ebp]
    3.     mov esi, DWORD PTR _b$[ebp]
    4.     dec ecx
    5.     shr ecx, 1
    6.     sub edx, eax
    7.     sub esi, eax
    8.     inc ecx
    9. $LL3@add:
    10.  
    11. ; 7    :   {
    12. ; 8    :     __m128d x = _mm_load_pd (a+i);
    13. ; 9    :     __m128d y = _mm_load_pd (b+i);
    14.  
    15.     movapd  xmm0, XMMWORD PTR [esi+eax]
    16.     movapd  xmm1, XMMWORD PTR [eax]
    17.  
    18. ; 10   :     __m128d z = _mm_add_pd(x, y);
    19.  
    20.     addpd   xmm0, xmm1
    21.  
    22. ; 11   :     _mm_store_pd (c+i, z);
    23.  
    24.     movapd  XMMWORD PTR [edx+eax], xmm0
    25.     add eax, 16                 ; 00000010H
    26.     sub ecx, 1
    27.     jne SHORT $LL3@add
    По-моему, вполне неплохо.
     
  5. fluck

    fluck New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2009
    Сообщения:
    19
    reverser, да не плохо, но хотелось бы самому разобратся без интринсик
     
  6. Clear__Energy

    Clear__Energy New Member

    Публикаций:
    0
    Регистрация:
    30 янв 2009
    Сообщения:
    432
    fluck
    тогда доки и отладчик в руки: читаешь, пишешь, смотришь в отладчике, во что код превратился.
     
  7. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Какая ошибка то ?
    Ты уверен, что объвление
    выравнивает на 16 именно указатель, возвращаемый new, а не просто адрес переменной b ?!
     
  8. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    msdn:
    .
     
  9. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    прикольно, не знал что у ms тоже есть _aligned_malloc
     
  10. fluck

    fluck New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2009
    Сообщения:
    19
    Да я вообще уже ни в чем не уверен...

    Теперь всё ясно. Значит __declspec(align(#)) только для переменных... а _aligned_malloc для структур и массивов.
    С последним всё работает.
    Только объясните мне последнее:
    когда я пишу так
    mov eax,a - то в регистр eax помещается адрес начала массива или значение, хранящееся в a[0]?
    тогда, почему не работает
    lea eax,a приминительно к моей задаче?
     
  11. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Нет 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] ;)
     
  12. fluck

    fluck New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2009
    Сообщения:
    19
    leo,Теперь я всё понял. Спасибо вам за подсказки и разъяснения.