2016-08-27 2 views
0

Я пишу код для умножения матриц на языке ассемблера. Я не могу использовать переменные и только хранилище в стеке, что мне нужно. Алгоритм кажется правильным, но у меня проблемы с IMUL и MOV с использованием регистров в последних двух блоках кода. Я отправляю мой код здесь:Матричное умножение в сборке

 unsigned int m = 3; // raws of mat1 
     unsigned int n = 2; // columns of mat1 
     unsigned int k = 4; // columns of mat2 
     short int mat1[] = { -1,-2, 4,5, 4,-2 }; // first matrix 
     short int mat2[] = { 2,0,4,6, 0,2,-1,3 }; // second matrix 
     int mat3[1024]; // output matrix 

     __asm { 

      XOR EAX, EAX //mat1 raws counter 
      XOR EBX, EBX //mat2 columns counter 
      XOR EDX, EDX //mat1 columns(equal to mat2 raws) counter 
      XOR EDI, EDI //will contain sum of multiplications to be copied into output matrix 

      Loop1 :   //determinates the raws of output matrix: mat3 
      XOR EBX, EBX //at the end of first raw, column counter is resetted 
       CMP m, EAX //if loopped mat1 m-raws times...  
       JZ Finale //...algortihm is over 
       INC EAX  //increase mat1 raws counter 
       JMP Loop2 

      Loop2 :    //determinates the columns of mat3 
      XOR EDX, EDX  //at the end of the n-sums, mat1 column counter is resetted 
       XOR EDI, EDI //after sum of n-multiplications edi is resetted 
       CMP k, EBX  //if multiplications/sums on this raw have been done... 
       JZ Loop1  //...go to next output matrix raw 
       INC EBX   //increase mat2 columns counter 
       JMP Loop3 

      Loop3 :   //determinates elements of mat3 
      CMP n, EDX  //if the n-multiplacations/sums on first n-elements have been done... 
       JZ Loop2 //...skip to next n-elements 
       INC EDX  //increase counter of the elements that will be multiplicate 
       JMP Stuffs //go to operations code block 

      Stuffs :          //here code generates mat3 elements 
    #58  MOV SI, mat1[2 * ((EAX - 1) * 2 + (EDX - 1)] //moves to SI the [m-raws/n-clomumn] element of mat1 
    #59   IMUL SI, mat2[2 * ((EBX - 1) * 2 + (EDX - 1)] //multiplicates(with sign) SI and [n-raws/k-column] element of mat2 
       ADD DI, SI         //sum the result in edi 
       CMP n, EDX         //check the sums 
       JZ CopyResult        //if n-sums have been done... 
       JMP Loop3         //...go to copy result into mat3 

      CopyResult : 
    #66  MOV mat3[4 * ((EAX - 1) * 4 + (EBX - 1))], EDI //copy value to output matrix mat3 
       JMP Loop3         //go to next n-elements 

      Finale : 
    } 

    { 
     unsigned int i, j, h; 

     printf("Output matrix:\n"); 
     for (i = h = 0; i < m; i++) { 
      for (j = 0; j < k; j++, h++) 
       printf("%6d ", mat3[h]); 
      printf("\n"); 
     } 

    } 

В этом коде, компилятор сообщает о двух типах ошибок, относящихся IMUL и MOV для MAT1, MAT2 и mat3. Вот они:

  • Линия 58 - Ошибка C2404 'EDX': запрещенный регистр в 'втором операнде'
  • Line 58 - Ошибка C2430 более чем один индексный регистр в 'втором операнде'

Те же ошибки для строк 59 и 66, с регистрами EDX и EBX.

Является ли это algortihm в основном хорошим? (я проверил установку вручную некоторых индексов , а затем последний, во время отладки, и это было хорошо, но я не смог полностью его протестировать).

Я думаю, что первая ошибка зависит от второй, но если i не может использовать этот способ регистров, что я могу сделать для вычисления вывода?

+3

'[2 * ((EAX - 1) * 2 + (EDX - 1)]', '[2 * ((EBX - 1) * 2 + (EDX - 1)]" и '[4 * ((EAX - 1) * 4 + (EBX - 1))] 'недействительный режим адресации: https://courses.engr.illinois.edu/ece390/books/artofasm/CH04/CH04-3.html –

+1

Ваш последняя версия вопроса имела C-декларации для ввода и вывода, поэтому мы могли видеть, что вы имеете дело с «коротким». Реальным вопросом здесь является только адресация режимов и синтаксических ошибок. Вы не указали, какая строка дает ошибку. –

+0

@Peter Cordes - Хорошо, я редактировал вопрос. Возможно, что если петли теперь работают правильно, самая большая проблема заключается в том, как обращаться с регистрами на блок вычисления. – Caramelleamare

ответ

1

Вместо того, чтобы пытаться масштабировать несколько регистров по два в режиме адресации (which is impossible), просто используйте add eax, 2 вместо inc eax.

Кроме того, поскольку ваша матрица вывода использует 32-разрядную int, вы должны выполнять 32-битную математику. Вы генерируете значение в DI, а затем сохраняете это, а всякий мусор находится в верхней половине EDI с линией # 66.

Нечто подобное movsx esi, word ptr [rowstart + column]/
movsx eax, word ptr [offset_in_column + row]/ imul eax, esi может работать (части) тела внутреннего цикла. Я позволю вам сортировать по столбцам в первом режиме адресации и увеличивать их по строкам во втором режиме адресации.


Я думаю, что ваш алгоритм, вероятно, разумен, основываясь на том, что, как я думаю, вы пытаетесь сделать. Для каждого элемента выходной матрицы перебираем столбец в одной матрице и строку в другой матрице. Таким образом, вы только сохраняете один раз каждый элемент выходной матрицы. Независимо от того, делают ли вы ваши петли или нет, IDK: у меня больно, как уродливое разветвление. (посмотрите на оптимизацию вывода компилятора для цикла когда-нибудь, затем для двойного или тройного вложенного цикла, например, на http://gcc.godbolt.org/).


Другие способы гнезда петля может быть лучше или хуже для исполнения с большими матрицами, но только действительно хороший способ сделать это (для больших матриц) связанно с перестановкой один из входных матриц, так что вы можете цикл над смежными элементами памяти одновременно в обеих матрицах (поскольку перенос затрат O (n^2) раз, но ускоряет шаг O (n^3), который многократно пересекает транспонированный массив, поскольку он дает больше хитов кэша).

(Учитывая то, как общую точку matmul плавающего в научных вычислениях, это тема, которая была широко изучена, с большим усилием в опытные настройки коды см. Различные реализации функции DGEMM в BLAS.)

0

Всем спасибо.Это мой последний код для тройных вложенных циклов и матричного продукта. За то, что я тестировал, он работает с любой матрицей и положительных/отрицательных значений:

void main() 
{ 
    unsigned int m = 3; // numero di righe della prima matrice 
    unsigned int n = 2; // numero di colonne della prima matrice 
    unsigned int k = 4; // numero di colonne della seconda matrice 
    short int mat1[] = { -1,-2, 4,5, 4,-2 }; // prima matrice 
    short int mat2[] = { 2,0,0,0, 0,2,0,0 }; // seconda matrice 
    int mat3[1024]; // matrice risultato 

    __asm { 

     lea eax, mat1  //load mat1 
     lea edi, mat3  //load mat result 
     push m 

     Loop3 :    //extern loop 
     lea ebx, mat2  //load here mat2 to start from the beginning when new result raw starts 
      xor edx, edx //sets to zero column counter set to zero when new result row starts 

     Loop2 :    //middle loop, as long as k, mat2 columns 
     xor ecx, ecx  //sets to zero mat1 column counter every n multiplications 

     Loop1 :    //inner loop 
     call Compute  //calls sub program that calulates raw/column products 
      inc ecx   //increase column counter 
      cmp ecx, n  //check column counter 
      jb Loop1  //if below loop1 again 
      add ebx, 2  //if equal to n, inner loop is over, move mat2 position of one position 
      inc edx   //increase mat2 column counter 
      cmp edx, k  //chek mat2 column counter 
      jb Loop2  //if below loop2 again 
      imul esi, n, 2  //else calculate offset to skip to new raw in mat1 
      add eax, esi  //...skip to new mat1 raw 
      imul esi, k, 4  //calculate offset to skip to new raw in result matrix(mat3) 
      add edi, esi  //...skip to new raw in mat3 
      dec m    //a raw in mat1 has been done, decrease its counter 
      cmp m, 0   //check how many raws has been done 
      ja Loop3   //if more than zero, do extern loop again 
      jmp Finale   //else algorithm is over 

     Compute :    //calulates raw/column products 
     movsx esi, WORD PTR[eax][ecx * 2]  
      push edi   //stores mat3 address to free edi counter 
      push ecx   //stores the actual value of column counter to free ecx register 
      mov edi, k   //calculates the offset in mat2... 
      imul edi, ecx  //... 
      movsx ecx, WORD PTR[ebx][edi * 2] //mov the value of mat2 to ecx 
      imul esi, ecx  //multiplicates values of mat1 ad mat2 
      pop ecx    //set back column counter 
      pop edi    //set back mat3 address 
      cmp ecx, 0   //if ecx is zero... 
      je First   //...is the first multiplication for this result value... 
      add[edi][edx * 4], esi //if not the first, add the value to current position 

     Back : 
     ret      //in any case, comes back to loops... 

     First :     //...so move here the first value to which add the others 
     mov[edi][edx * 4], esi //moving value 
      jmp Back 

     Finale :  //the end 
     pop m   //restore the original mat1 raw value to print the result matrix below 

    } 

    //Output on video 

    { 
     unsigned int i, j, h; 

     printf("Product Matrix:\n"); 
     for (i = h = 0; i < m; i++) { 
      for (j = 0; j < k; j++, h++) 
       printf("%6d ", mat3[h]); 
      printf("\n"); 
     } 

    } 
} 

И это только алгоритм тройного вложенных циклов я писал, начиная с двойным вложенных циклов, найденных здесь в stackoverflaw:

m = raws of first matrix 
k = columns of second matrix 
n = column of first matrix and raws of second matrix 

x=0 
Loop3: 
y=0 
Loop2: 
z=0 
Loop1: 
compute... 
z++ 
if(z<n) 
    go to Loop1 
y++ 
if(y < k) 
    go to Loop2 
x++ 
if(x < m) 
    go to Loop3 
Else go to the End 
Смежные вопросы