Da skupim o aarch64 asembler programiranju

Lep primer za ucenje ARM64(aarch64) asemblera.
Asembler koji se koristi je takodje moj omiljeni flat assembler, u sledecoj generaciji koja se ne vezuje za arhitekturu
nego se instrukcije za odrejenu arhitekturu inkluduju.

Introduction​

Welcome to the project of translating Stockfish into assembly language. This project now uses the new assembler engine fasmg from Tomasz Grysztar. The includes in arm/includes/ or x86/include/ contain instruction and formatting macros for the four popular targets in the Building section. The hello world examples in these directories should provide enough to grasp the syntax.

1 Like

Zbog ovoga sam kupio macbook,da se pripremim za budućnost :)
Evo ga hello world na aarch64 mac OS-u, asembler je GNU gas, jedini koliko znam izbor za ARM:

Kod:

msg:
    .ascii        "Hello, ARM64!\n"
len = . - msg

.globl _main ; osx linker traži ovaj simbol za ulaz
.align 4        ; f-je moraju na 4 bajta da se alajnuju

_main:

    mov     x0,#1 ; standardni izlaz, stdout
    adr     x1,msg ; adresa poruke
    mov     x2,len    ; duzina
    mov     x16, #4    ; syscall broj 4 je write
    svc     #0        ; poziv sistemskog servisa

   mov     x0, #0      ; povratni kod
   mov     x16, #1     ; 1 je izlaz
   svc     #0   ; jasno
; kraj

i idemo:

Kod:

[email protected] assembler % as hello.s -o hello.o                                                                     
[email protected] assembler % ld -o hello hello.o -lSystem -L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
[email protected] assembler % ./hello
Hello, ARM64!

I to bi bilo to za početak :)

bmaxa

bmaxa

Veoma poznat

Moderator

Poruka

11.727

A sada to isto ali sa kooperacijom sa C bibliotekom:

Kod:

        .text
msg:
        .ascii "Zdravo Svete!\0"
        .globl _main
        .align 4
_main:
        stp     x29, x30, [sp, -16]!
        adr     x0, msg
        mov     x29, sp
        bl      _puts
        ldp     x29, x30, [sp], 16
        mov     x0, 0
        ret

x29 je frejm, a x30 link pointer, tj onaj koji cuva return adresu. Ova dva se moraju
sacuvati i to se radi na pocetku sa stp instrukcijom koja ih smesta na stek.
potom se frejm podesi da pokauzuje na vrh steka da ih puts ne pregazi.
x0 drzi pointer na string za puts. I poziv f-je sledi. Nakon povratka vraca
se vrednost x29 i x30 registara. potom sledi izlaz sa ret. (ret koristi adresu
u x30 a x29 je frejm koji je nasetovala pozivna f-ja. I to je to.

Kod:

[email protected] assembler % as helloc.s -o hello.o                                                                    
[email protected] assembler % ld -o hello hello.o -lSystem -L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
[email protected] assembler % ./hello

Toliko za danas :)

Sad sam krenuo da pretabam, merge i radix sort listi u asm_u koji su trenutno za x86.
Zahvaljujuci rozeti tj jit-u koji prevodi x86 kod u ARM kod mogu ovo da vozim na Mac-u.
Evo recimo 2700x isti program i na Mac-u.

Kod:

list radix elapsed 1.071881 seconds
list merge elapsed 0.308731 seconds
size of node 12, length 1000000

a gle na Macu:

Kod:

list radix elapsed 0.090691 seconds
list merge elapsed 0.048341 seconds
size of node 16, length 1000000

I jednom i drugom milion noda staje u cache, ali je M1 drasticno brzi :P
Kad pretabam objavim.

Evo ga full blown asm program za M1, sto je retkost naci:P
Zezao sam se najvise sa stekom, zato sto ARM ne da nonaligned pristup steku, za razliku
od x86, pa sam tu imao pretumbacija. Osim toga nasao sam lep nacin da se meri vreme
izvrsavanja a to je mrs instrukcija koja cita sistemske registre od kojih su dva interesantna:
cntfrq_el0 koji daje frekvenciju sa kojom se deli takt tako da se dobiju sekunde i drugi
je CNTPCT_EL0 koji daje sam brojac.
Progi je ovde kao sto sam obecao: GitHub - bmaxa/asmsort: List sorting in asm for macOS

A sada primer koriscenja SIMD instrukcija.

Kod:

    .text
    .globl _main
    .align 4
    .arch armv8a
_main:
    stp    x29, x30, [sp, -16]!
    adrp x1,[email protected]
    ldr q0,[x1,[email protected]]
    adrp x2,[email protected]
    ldr q1,[x2,[email protected]]
    add.4s v0,v1,v0
    sub sp,sp,32
    mov.s w8,v0[0]
    str x8,[sp]
    mov.s w8,v0[1]
    str x8,[sp,8]
    mov.s w8,v0[2]
    str x8,[sp,16]
    mov.s w8,v0[3]
    str x8,[sp,24]
    adrp x0,[email protected]
    add  x0,x0,[email protected]
    bl _printf
    add sp,sp,32
    ldp    x29, x30, [sp], 16
    eor     x0,x0,x0
    ret
    .data
msgsimd:
    .asciz "%d %d %d %d!\n"
.align 16
simd1:
.long 1
.long 2
.long 3
.long 4
simd2:
.long 10
.long 20
.long 30
.long 40

E sad na ARM postoji SIMD koji se zove Neon i najblizi je SSE2 na x86. Dakle koriscenje je prilicno slicno
sa time da su naravno instrukcije drugacije.

  1. ucitavanje iz memorije. Kada se ovo radi koristi se oznaka q0-31 za registar, dakle
    ldr q0,[x1,[email protected]] ucitava u registar q0 4 32 bitna inta.
  2. operacija
    add.4s v0,v1,v0 oznacava celobrojno sabiranje 4 worda (word je 32 bitni na ARM za razliku od x86 gde je to dword).
    v0 i v1 su oznake da se radi o vektorskoj operaciji. Ovo isto moze da se napise i kao add v0.4s,v1.4s,v0.4s sto je verboznije.
    Potom zelimo da isprintamo rezultat.
    mov.s w8,v0[0] znaci extraktuj prvi element iz vektora, velicine word i smesti u 32-bitni int registar w8.
    printf na macOS u x0 uzima format string, a parametri idu na stek sa leva na desno, tj odozdo na gore.
    i to bi bilo to.

Evo ga jos jedan primer za ARMV8 ovoga puta moj nbody bench, koji se ovde nije proslavio :P
Izgleda da M1 vise voli razmotane petlje od Neona, pa se moj program izvrsava dosta sporije.
Ali je odlican primer ARMV8 asemblera pa koga zanima, moze da pita.
Proggy je ovde: shootout/nbody2.gas at main · bmaxa/shootout · GitHub
I kao sto se dalo pretpostaviti:

Kod:

.L1main:
    cmp x20,20
    blt lo
    advance A
    advance B
    advance C
    advance D
    advance E
    advance F
    advance G
    advance H
    advance I
    advance J
    advance 01
    advance 02
    advance 03
    advance 04
    advance 05
    advance 06
    advance 07
    advance 08
    advance 09
    advance 10
    subs x20,x20,20
    bgt .L1main
    b Lskip
lo:
    advance K
    subs x20,x20,1
    bgt lo
Lskip:

Ovo mi je dalo 10% na performansama :P