如何对两个矩阵进行逐元素求和?

时间:2019-05-11 08:23:24

标签: assembly matrix x86 addressing-mode

我是汇编语言的新手,如果您能用一段代码介绍如何添加两个矩阵并将结果移动到另一个矩阵中(汇编语言x86-32bit),我将不胜感激。矩阵被声明为一维数组。

n dd 9
A dd 1,2,3,4,5,6,7,8,9
B dd 2,0,4,5,6,7,0,1,3
sum dd dup 9(0)

我尝试了下面的代码,但是它仅适用于这样声明的矩阵,而对于声明为1s数组的矩阵,我将需要一个代码。

A db 1,2,3
   db 4,5,6
B db 7,8,9
   db 10,11,12
.code
start:
mov eax , 0 
mov esi, 0 
mov ebx, 0 

add al, A[ebx][esi]
add al, B[ebx][esi]
mov A[ebx][esi], al
mov al, 0
inc esi
add al, A[ebx][esi]
add al, B[ebx][esi]
mov A[ebx][esi], al
mov al, 0
inc esi
add al, A[ebx][esi]
add al, B[ebx][esi]
mov A[ebx][esi], al

mov al, 0
mov esi, 0
add ebx, 3 
add al, A[ebx][esi]
add al, B[ebx][esi]
mov A[ebx][esi], al
mov al, 0
inc esi
add al, A[ebx][esi]
add al, B[ebx][esi]
mov A[ebx][esi], al
mov al, 0
inc esi
add al, A[ebx][esi]
add al, B[ebx][esi]
mov A[ebx][esi], al
 push 0
call exit
end start

2 个答案:

答案 0 :(得分:2)

在内存中连续的矩阵(例如C 2D数组)等效于1D数组,只是内存中一行中的rows * cols个元素,无论您使用哪种asm语法将它们放在那里。使它们成为2D矩阵的唯一方法是如何为它们建立索引,例如
flat_index row * width + col

(要进行遍历,您当然可以执行row_offset += width;这就是2x3字节矩阵代码中的add ebx, 3。)

矩阵的每个元素加法根本不必在意它们的维数,这与矩阵的每个元素加法完全相同。因此,只需在每个数组上循环索引或指针并添加即可。

然后,行和列不需要两个单独的索引,这只会使您的代码更复杂,或者(对于如此小的尺寸)几乎值得像您第二次一样完全展开。

(或者,如果您的CPU支持SSE2,则可以使用paddd一次执行4个双字。)


这并不特殊:

A db 1,2,3
   db 4,5,6

这样声明,对于单独的行有2条单独的db行,等效于一个长数组。对于MASM,它可能会更改SIZEOF A(您可能只获得与A标签实际上在同一行的第一行),但没有其他改变。

与之配套的代码不适用于您的情况的原因是它使用字节元素,并且具有不同的矩阵大小(9个元素而不是6个元素)。与之无关怎么声明的。

可以完全展开一个循环,并根据需要进行一堆复杂的移动和整数寄存器的添加,但这没有意义。


A[ebx][esi]在大多数(?)汇编程序中不是有效的语法。如果组装的话,我认为这意味着
A[ebx + esi] 。那是写出来的正常方法。

这不是为您做矩阵索引,这就是为什么您仍然必须使用字节偏移量转到下一行的原因。

如果列数是2的汇编时间常数,则可以使用A[ebx*4 + esi]之类的东西(特别是1、2、4或8; x86寻址模式对于2位移位计数索引)。

通常使用asm语法编写[base + index*scale],但是Intel语法汇编程序实际上并不关心寻址模式的组件出现的顺序。因此,如果您想在C中思考,则左索引会大步前进在整个行上选择一列,然后将其写为[A + ebx*4 + esi]是有意义的(如果您有一个uint8_t [2][4]矩阵,那么从元素到下一行的步长为4。

对于dword元素(如您的第一个示例),而不是字节元素(如您的第二个元素),您需要将索引缩放或已经缩放4(例如A[ebx*4]或使用{ {1}},而不是add esi, 4

答案 1 :(得分:0)

如果要通过将输出写入数组C来对任意两个数组A和B求和,则可以提供 函数的输入参数等于矩阵A的大小,等于矩阵B的大小,并且 矩阵C的整数:MAT_SIZE。 要计算MAT_SIZE,您只需将行数乘以数字 列(一维和二维矩阵)。如果索引数大于2,则 MAT_SIZE将是所有(最大索引+ 1)的乘积(假设0指向 第一个元素,n-1指向最后一个元素)。 我想矩阵包含1个字节的单元格。

;Indexes Max-Index+1 MAT_Size 
;      3           8    8*8*8

;ROUTINE @@MAT

;INPUT: EAX: First matrix pointer. Unaltered
;       EDX: Second matrix pointer. Unaltered.
;       EBX: Target matrix pointer. Unaltered.
;       ECX: MAT_Size. Unaltered.

@@MAt:PUSH  EBP           ; Save EBP.
      MOV   EBP,EBX       ; Copy EBX into EBP.

      JECXZ @@00          ; If matrix is empty, terminate sub-routine.

      PUSH  ECX           ; Save ECX.

 @@01:Mov   BL,[EAX]      ; Load in BL first byte.
      Add   BL,[EDX]      ; Add to BL second byte.
      MOV   [EBP],BL      ; Save result in [EBP].

      INC   EAX           ; Increase First matrix pointer.
      INC   EDX           ; Increase Second matrix pointer.
      INC   EBP           ; Increase Target matrix pointer.

      LOOP  @@01          ; If target matrix is full, end.

      POP   ECX           ; Resume MAT_SIZE

      SUB   EAX,ECX       ; Adjust First matrix pointer.
      SUB   EDX,ECX       ; Adjust Second matrix pointer.

      MOV   EBX,EBP
      SUB   EBX,ECX       ; Adjust Target matrix pointer.

 @@00:POP   EBP           ; Resume EBP.

      RET                 ; Return from sub-routine.

在真实的x86模式下,假设矩阵位于数据段中,您可以类似地写道:

;Indexes Max-Index+1 MAT_Size 
;      3           8    8*8*8

;ROUTINE @@MT2

;INPUT: SI: First matrix offset. Unaltered
;       DI: Second matrix offset. Unaltered.
;       BX: Target matrix offset. Unaltered.
;       CX: MAT_Size. Unaltered.

@@MT2:PUSH  BP            ; Save BP.
      MOV   BP,BX         ; Copy BX into BP.

      JCXZ  @@00          ; If matrix is empty, terminate sub-routine.

      PUSH  CX            ; Save ECX.

 @@01:Mov   BL,DS:[SI]    ; Load in BL first byte.
      Add   BL,DS:[DI]    ; Add to BL second byte.
      MOV   DS:[BP],BL    ; Save result in [BP].

      INC   SI            ; Increase First matrix offset.
      INC   DI            ; Increase Second matrix offset.
      INC   BP            ; Increase Target matrix offset.

      LOOP  @@01          ; If target matrix is full, end.

      POP   CX            ; Resume MAT_SIZE

      SUB   SI,CX         ; Adjust First matrix offset.
      SUB   DI,CX         ; Adjust Second matrix offset.

      MOV   BX,BP
      SUB   BX,CX         ; Adjust Target matrix pointer.

 @@00:POP   BP            ; Resume BP.

      RET                 ; Return from sub-routine.