AVX2 dan register ymm

Register ymm 256-bit, operasi delapan lane, dan instruksi gather untuk pengumpulan data tak berurutan.

Daftar isi

Topik ini membahas register ymm 256-bit beserta keluarga AVX2-nya. Register ymm memperpanjang lebar SIMD dari empat lane menjadi delapan lane 32-bit. AVX pertama hanya membawa float ke lebar 256 bit, sedangkan AVX2 melengkapinya dengan integer 256-bit dan instruksi gather yang mengumpulkan elemen dari alamat tak berurutan. Struktur register dan syarat penyelarasannya dibahas lebih dahulu, dilanjutkan dengan mekanisme gather, kemudian satu program menjalankan keduanya dan diperiksa lewat keluaran gdb yang asli.

Register ymm 256-bit#

Setiap prosesor dengan AVX menyediakan enam belas register ymm bernama ymm0 sampai ymm15, masing-masing menyimpan 256 bit atau delapan lane 32-bit. Register ymm bukan tambahan yang berdiri sendiri, melainkan perluasan dari register xmm yang sudah dikenal, karena 128 bit bawah ymm0 berbagi tempat yang sama dengan xmm0. Menulis ke ymm0 mengubah isi xmm0 juga, sedangkan menulis ke xmm0 dengan instruksi ber-VEX mengosongkan bagian atas ymm0, sehingga keduanya harus diperlakukan sebagai satu tempat penyimpanan.

Instruksi 256-bit mengenali lebarnya dari bit L pada prefiks VEX, sehingga pasangan vaddps untuk xmm dan untuk ymm berbagi mnemonic yang sama. Syarat penyelarasan juga naik seiring lebar, karena vmovaps dengan operan memori 256-bit menuntut alamat kelipatan 32 byte, dan itulah alasan arahan align 32 pada program di bagian akhir. AVX pertama hanya menyediakan float pada lebar ini, sedangkan AVX2 menambahkan instruksi integer 256-bit seperti vmovdqa dan vpaddd, sehingga pengolahan integer delapan lane menjadi mungkin tanpa memecah datanya menjadi dua register xmm. Lebar ganda ini berdampak langsung pada jumlah iterasi, karena blok data yang sama hanya membutuhkan separuh muat dan separuh operasi dibandingkan dengan versi xmm.

Instruksi gather#

Muat biasa seperti vmovaps mengambil data berurutan dari memori, sedangkan sebagian data nyata tersusun dalam urutan yang berbeda dari urutan pemrosesannya. Kebutuhan itu muncul pada tabel yang dibaca per baris padahal tersusun per kolom, atau pada pemilihan elemen tertentu dari data besar. Instruksi gather menyelesaikan kebutuhan itu dengan mengumpulkan elemen dari banyak alamat sekaligus. Bentuknya adalah vpgatherdd ymm1, [rax + ymm2*4], ymm3, yang untuk setiap lane membaca memori pada alamat rax + indeks*4 menggunakan isi lane ymm2 sebagai indeksnya, lalu menuliskan hasilnya ke lane ymm1 yang sejajar.

Operan ketiga berupa register mask, yaitu penyeleksi lane yang menentukan pengumpulan mana yang dijalankan. Lane dengan bit mask bernilai satu ikut dibaca dan diperbarui, sedangkan lane dengan bit nol dibiarkan tanpa mengakses memori sama sekali, sehingga indeks yang tidak sah pada lane nonaktif tidak memicu fault. Penyeleksian per lane juga membuat gather dapat dibatasi pada sebagian lane saja, misalnya ketika jumlah elemen yang sah tidak mengisi register penuh. Perbedaan penting dengan muat biasa adalah register mask ikut dikosongkan setelah instruksi selesai, sehingga mask tidak dapat digunakan kembali tanpa diisi kembali. Kebalikan gather, yaitu scatter yang menyebarkan isi register ke banyak alamat, tidak tersedia pada AVX2 dan baru muncul pada generasi setelahnya.

Delapan lane dan pengumpulan tak berurutan#

Program berikut menjalankan dua hal sekaligus. Pertama, delapan float dimuat ke ymm0 dan digandakan dengan satu vaddps tiga operan. Kedua, elemen integer dari array data dikumpulkan dengan vpgatherdd mengikuti urutan pada array indeks, yang memotong data menjadi dua bagian berselang-seling. Alamat dasar array ditaruh di rax terlebih dahulu karena pengalamatan gather menggabungkan register umum, register vektor indeks, dan faktor skala dalam satu operan.

nasm avx2-ymm.asm
default rel

section .data
    align 32
suhu:   dd 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0
    align 32
data:   dd 10, 20, 30, 40, 50, 60, 70, 80
    align 32
indeks: dd 0, 2, 4, 6, 1, 3, 5, 7

section .text
global _start

_start:
    vmovaps ymm0, [suhu]      ; muat delapan float sekaligus
    vaddps  ymm0, ymm0, ymm0  ; gandakan setiap lane

    lea     rax, [data]
    vmovdqa ymm2, [indeks]    ; vektor indeks pengumpulan
    vpcmpeqd ymm3, ymm3, ymm3 ; mask: semua lane aktif
    vpgatherdd ymm1, [rax + ymm2*4], ymm3 ; kumpulkan data tak berurutan

    mov  eax, 60
    xor  edi, edi
    syscall
bash
# rakit dan tautkan program
nasm -f elf64 avx2-ymm.asm -o avx2-ymm.o
ld avx2-ymm.o -o avx2-ymm

# hasil delapan lane, hasil gather, dan kondisi register mask
gdb -batch -ex 'break _start' -ex 'run' -ex 'stepi 6' -ex 'p $ymm0.v8_float' -ex 'p $ymm1.v8_int32' -ex 'p $ymm3.v8_int32' ./avx2-ymm
text Keluaran
Breakpoint 1 at 0x401000

Breakpoint 1, 0x0000000000401000 in _start ()
0x0000000000401025 in _start ()
$1 = {42, 44, 46, 48, 50, 52, 54, 56}
$2 = {10, 30, 50, 70, 20, 40, 60, 80}
$3 = {0, 0, 0, 0, 0, 0, 0, 0}

Register ymm0 terbaca {42, 44, 46, 48, 50, 52, 54, 56}, yaitu delapan suhu yang masing-masing digandakan dalam satu instruksi, dua kali lebar empat lane pada topik register xmm. Delapan float dimuat dan digandakan tanpa satu pun struktur perulangan, sesuatu yang pada lebar 128-bit membutuhkan dua register serta dua kali pekerjaan. Register ymm1 terbaca {10, 30, 50, 70, 20, 40, 60, 80}, yaitu elemen array data yang dikumpulkan mengikuti indeks 0, 2, 4, 6, 1, 3, 5, 7, sehingga urutannya berubah menjadi dua kelompok berselang-seling tanpa satu pun perulangan per elemen. Register mask ymm3 terbaca sebagai delapan nol, bukti keluaran bahwa gather mengosongkan mask yang selesai digunakan, sesuai perilaku yang didokumentasikan. Arahan align 32 menjaga kedua array yang dimuat vmovaps dan vmovdqa pada alamat kelipatan 32 byte, sesuai syarat kedua instruksi tersebut untuk operan memorinya.

Ringkasan#

  • Register ymm0 sampai ymm15 menyimpan 256 bit atau delapan lane 32-bit, dan 128 bit bawahnya berbagi tempat dengan register xmm yang bernomor sama.
  • AVX1 membawa float ke 256 bit, sedangkan AVX2 melengkapinya dengan integer 256-bit seperti vmovdqa dan vpaddd.
  • vpgatherdd mengumpulkan elemen dari alamat dasar + indeks*4 per lane, diseleksi oleh register mask yang ikut dikosongkan setelah instruksi selesai.
  • Gather jauh lebih lambat daripada muat berurutan dan scatter tidak tersedia pada AVX2.

Referensi#