Skip to content

Instantly share code, notes, and snippets.

@petehamilton
Last active December 16, 2015 22:19
Show Gist options
  • Save petehamilton/5505799 to your computer and use it in GitHub Desktop.
Save petehamilton/5505799 to your computer and use it in GitHub Desktop.
Matrix Multiply Feedback

Matrix Multiply Aggregated Feedback

Indentation

Many of you (understandably) applied a sort of nesting indentation to your assembly code something like this:

for_row: mov r9, 0
next_row:
    COMPARISON
    jge end_for_row
    for_col: mov r10, 0
    next_col:
        COMPARISON
        jge end_for_col
        LOGIC
        jmp for_col
    end_for_col
jmp next_row
end_for_row

Whilst this is perfectly valid, generally this form of indentation is frowned upon.

In general I find the best format is to have labels aligned to the left and have code on separate lines, indented 4-8 spaces (be consistent!).

This makes it much quicker to scan and visually traverse the code.

Compare the readability of the above to:

for_row:
        mov r9, 0
next_row:
        COMPARISON
        jge end_for_row
for_col:
        mov r10, 0
next_col:
        COMPARISON
        jge end_for_col
        LOGIC
        jmp for_col
end_for_col:
        jmp next_row
end_for_row:

Much easier to find the control labels right?

Rest assured EVERYONE does this. I've attached my personal matrix print code from first year in this gist so you can laugh at my code style. Note the handy diagram of the stack though. I love them as I have the conceptual memory of a goldfish sometimes.

Also - Camelcase in assembly? -10,000 marks…

Label Names

Prefixing

When choosing labels, there are no scopes like you would have seen in haskell and java. As such, you need to pick unique names.

A few of you opted to suffix your labels:

; My First Function
for_row1:
        CODE
next_row1:
        CODE
for_col1:
        CODE
next_col1:
        CODE
end_for_col1:
        CODE
end_for_row1:

; My Other Function
for_row_other:
        CODE
next_row_other:
        CODE
for_col_other:
        CODE
next_col_other:
        CODE
end_for_col_other:
        CODE
end_for_row_other:

While this is perfectly fine, it's not the most readable format. Imagine scanning the lines of code, reading Left->right. It can also be quite hard to spot which jumps go to which labels if there are many which start with the same name.

Personally, I find prefixing is the best way to manage this. For example:

; Multiply Matrix
M_for_row:
        CODE
M_next_row:
        CODE
M_for_col:
        CODE
M_next_col:
        CODE
M_end_for_col:
        CODE
M_end_for_row:

; Print Matrix
P_for_row:
        CODE
P_next_row:
        CODE
P_for_col:
        CODE
P_next_col:
        CODE
P_end_for_col:
        CODE
P_end_for_row:

Comments

In a piece of assembly code, comments can rapidly make code unreadable. On the flipside, if used well, they can be fantastic for documenting what your code does.

For example:

P_for_col: ;start loop
    mov  rdi, 0
P_next_col:
    ;exits the for loop
    cmp rdi, [rbx+8]
    jge P_end_col
    call output_tab
    ;get element
    mov rax, rsi
    imul rax, [rbx+8]
    add rax, rdi
    mov rax, [rbx+8*rax+16]
    ; push ready for output
    push rax
    call output_int
    add rsp, 8
    ;increment column
    inc rdi
    jmp P_next_col
P_end_col:

Isn't partcularly clear or useful. Let's neaten it up.

P_for_col:
        mov  rdi, 0               ; col = 0
P_next_col:                       ; start for loop
        cmp  rdi, [rbx+8]         ; exit for loop if col >= this.COLS
        jge  P_end_col
    
        call output_tab
                                  ; element_addr = (this + 16) + 8 * (row * this.COLS + col)                                  
        mov  rax, rsi             ; rax = row
        imul rax, [rbx+8]         ;     = row * this.COLS
        add  rax, rdi             ;     = row * this.COLS + col
        mov  rax, [rbx+8*rax+16]  ;     = this.elem[row, col]
        push rax                  ; push this.elem[row, col]
        call output_int           ; output this.elem[row, col]
        add  rsp, 8               ; pop parameter
    
        inc rdi                   ; col ++
        jmp P_next_col
P_end_col:
        call output_newline

Boom.

Notice several things:

  • Comments are all aligned
  • Comments explain what each step does (this much detail not always needed!)
  • Additional comments to explain info like state pre-operation
  • 3 and 4 letter operator params are aligned. A small change, but it makes a difference I think
  • Newlines are injected between logical blocks of code
  • Nice indentation makes control labels easy to spot

RAX Register

DO NOT STORE THINGS IN THIS

rax is volatile which means that for calculations it's fine, but you shouldn't expect anything you put in there to be safe.

This also means that storing it isn't strictly necessary. A few of you added it to your register saving with push rax and later pop rax but you could have left these out.

push rbp ; setup base pointer
mov rbp, rsp
; Diagram of stack
;-------------------; TOP
; address of Matrix ;
;-------------------;
; pushed rbp ;
;-------------------;
; return addr. ; <-- rbp
;-------------------; BOTTOM
push rax ;Rows iterator
push rbx ;Cols iterator
push rcx ;ROWS
push rdx ;COLS
push rsi ;Will be used to hold the start pointers for data etc
mov rsi, [rbp + 16] ;set rsi as address of address of data
mov rcx, [rsi] ;Set rows as first element at rsi
mov rdx, [rsi + 8] ;Set cols as second element at rsi
add rsi, 16 ;Move rsi pointer to start of matrix elements
forRow:
mov rax, 0 ;Double for loop implementation
nextRow:
cmp rax, rcx
jge endforRow
forCol:
mov rbx, 0
nextCol:
cmp rbx, rdx
jge endforCol
call output_tab
push rax
;element is at [rsi + rax * rdx * 8 + 8 * rbx]
imul rax, rdx
add rax, rbx
imul rax, 8
add rax, rsi
push qword [rax]
call output_int
add rsp, 8 ;skips top value in stack
pop rax
inc rbx
jmp nextCol
endforCol:
call output_newline
inc rax
jmp nextRow
endforRow:
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
pop rbp ;Restore base pointer & return
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment