Untuk melakukan x = x*10 + 1
secara efisien, mungkin optimal untuk digunakan
lea eax, [rax + rax*4] ; x*=5
lea eax, [1 + rax*2] ; x = x*2 + 1
LEA 3 komponen memiliki latensi lebih tinggi pada CPU Intel modern, misalnya. 3 siklus vs. 1 pada keluarga Sandybridge, jadi disp32 + index*2
lebih cepat daripada disp8 + base + index*1
pada keluarga SnB, yaitu sebagian besar CPU x86 mainstream yang ingin kami optimalkan. (Ini sebagian besar hanya berlaku untuk LEA, bukan memuat/menyimpan, karena LEA berjalan pada unit eksekusi ALU, bukan AGU di sebagian besar CPU x86 modern.) CPU AMD memiliki LEA yang lebih lambat dengan 3 komponen atau scale > 1
(http://agner.org/optimize/)
Namun NASM dan YASM akan mengoptimalkan ukuran kode dengan menggunakan [1 + rax + rax*1]
untuk LEA ke-2, yang hanya memerlukan disp8 dan bukan disp32. (Mode pengalamatan selalu memiliki register dasar atau disp32).
yaitu mereka selalu membagi reg*2
menjadi base+index
, karena itu tidak lebih buruk untuk ukuran kode.
Saya dapat memaksa menggunakan disp32 dengan lea eax, [dword 1 + rax*2]
, tetapi itu tidak menghentikan NASM atau YASM untuk memisahkan mode pengalamatan. Manual NASM sepertinya tidak mendokumentasikan cara menggunakan kata kunci strict
pada faktor skala, dan [1 + strict rax*2]
tidak berkumpul. Apakah ada cara untuk menggunakan strict
atau sintaksis lain untuk memaksakan pengkodean mode pengalamatan yang diinginkan?
nasm -O0
untuk menonaktifkan optimasi tidak berfungsi. Rupanya itu hanya mengontrol optimasi perpindahan cabang multi-pass, bukan semua optimasi yang dilakukan NASM. Tentu saja Anda tidak ingin melakukan hal itu untuk seluruh file sumber, meskipun itu berhasil. saya masih mengerti
8d 84 00 01 00 00 00 lea eax,[rax+rax*1+0x1]
Satu-satunya solusi yang dapat saya pikirkan adalah menyandikannya secara manual dengan db
. Hal ini cukup merepotkan. Sebagai catatan, pengkodean manualnya adalah:
db 0x8d, 0x04, 0x45 ; opcode, modrm, SIB for lea eax, [disp32 + rax*2]
dd 1 ; disp32
Faktor skala dikodekan dalam 2 bit tinggi byte SIB. Saya merakit lea eax, [dword 1 + rax*4]
untuk mendapatkan kode mesin untuk register yang benar, karena optimasi NASM hanya berfungsi untuk *2
. SIB-nya adalah 0x85
, dan pengurangan bidang 2-bit di bagian atas byte akan mengurangi faktor skala dari 4 menjadi 2.
Namun pertanyaannya adalah: bagaimana menulisnya dengan cara yang mudah dibaca sehingga memudahkan untuk mengubah register, dan membuat NASM menyandikan mode pengalamatan untuk Anda? (Saya kira makro raksasa dapat melakukan ini dengan pemrosesan teks dan pengkodean db
manual, tapi itu bukan jawaban yang saya cari. Saya sebenarnya tidak memerlukan ini untuk apa pun saat ini, saya paling ingin tahu apakah NASM atau YASM memiliki sintaks untuk memaksakan ini.)
Pengoptimalan lain yang saya ketahui, seperti mov rax, 1
merakit menjadi 5-byte mov eax,1
adalah kemenangan murni pada semua CPU kecuali Anda menginginkan instruksi yang lebih panjang untuk mendapatkan padding tanpa NOP, dan dapat dinonaktifkan dengan mov rax, strict dword 1
untuk mendapatkan pengkodean perluasan tanda 7-byte, atau strict qword
untuk imm64 10-byte.
gas tidak melakukan ini atau sebagian besar pengoptimalan lainnya (hanya ukuran perpindahan langsung dan cabang): lea 1(,%rax,2), %eax
dirakit menjadi8d 04 45 01 00 00 00 lea eax,[rax*2+0x1]
, dan sama untuk versi .intel_syntax noprefix
.
Jawaban untuk MASM atau assembler lain juga menarik.