Kasus terbaik 8 siklus, Kasus terburuk 12 siklus
Karena tidak jelas dalam pertanyaan, saya mendasarkan latensi Ivy Bridge ini.
Pendekatan di sini adalah dengan menggunakan bsr
instruksi (bit scan reverse) sebagai log2 orang miskin (). Hasilnya digunakan sebagai indeks ke dalam tabel lompatan yang berisi entri untuk bit 0 hingga 42. Saya berasumsi bahwa mengingat operasi pada data 64bit secara implisit diperlukan, maka penggunaan bsr
instruksi adalah OK.
Dalam input kasus terbaik, entri jumptable dapat memetakan bsr
hasilnya langsung ke besarnya. mis. Untuk input dalam kisaran 32-63, bsr
hasilnya adalah 5, yang dipetakan dengan besaran 1. Dalam hal ini, jalur instruksi adalah:
Instruction Latency
bsrq 3
jmp 2
movl 1
jmp 2
total 8
Dalam input kasus terburuk, bsr
hasilnya akan memetakan ke dua besaran yang mungkin, sehingga entri jumptable melakukan satu tambahan cmp
untuk memeriksa apakah inputnya> 10 n . Misalnya untuk input dalam kisaran 64-127, bsr
hasilnya akan menjadi 6. Entri jumptable yang sesuai kemudian memeriksa apakah input> 100 dan mengatur besarnya output yang sesuai.
Selain untuk jalur kasus terburuk, kami memiliki instruksi mov tambahan untuk memuat nilai langsung 64bit untuk digunakan di cmp
, jadi jalur instruksi kasus terburuk adalah:
Instruction Latency
bsrq 3
jmp 2
movabsq 1
cmpq 1
ja 2
movl 1
jmp 2
total 12
Ini kodenya:
/* Input is loaded in %rdi */
bsrq %rdi, %rax
jmp *jumptable(,%rax,8)
.m0:
movl $0, %ecx
jmp .end
.m0_1:
cmpq $9, %rdi
ja .m1
movl $0, %ecx
jmp .end
.m1:
movl $1, %ecx
jmp .end
.m1_2:
cmpq $99, %rdi
ja .m2
movl $1, %ecx
jmp .end
.m2:
movl $2, %ecx
jmp .end
.m2_3:
cmpq $999, %rdi
ja .m3
movl $2, %ecx
jmp .end
.m3:
movl $3, %ecx
jmp .end
.m3_4:
cmpq $9999, %rdi
ja .m4
movl $3, %ecx
jmp .end
.m4:
movl $4, %ecx
jmp .end
.m4_5:
cmpq $99999, %rdi
ja .m5
movl $4, %ecx
jmp .end
.m5:
movl $5, %ecx
jmp .end
.m5_6:
cmpq $999999, %rdi
ja .m6
movl $5, %ecx
jmp .end
.m6:
movl $6, %ecx
jmp .end
.m6_7:
cmpq $9999999, %rdi
ja .m7
movl $6, %ecx
jmp .end
.m7:
movl $7, %ecx
jmp .end
.m7_8:
cmpq $99999999, %rdi
ja .m8
movl $7, %ecx
jmp .end
.m8:
movl $8, %ecx
jmp .end
.m8_9:
cmpq $999999999, %rdi
ja .m9
movl $8, %ecx
jmp .end
.m9:
movl $9, %ecx
jmp .end
.m9_10:
movabsq $9999999999, %rax
cmpq %rax, %rdi
ja .m10
movl $9, %ecx
jmp .end
.m10:
movl $10, %ecx
jmp .end
.m10_11:
movabsq $99999999999, %rax
cmpq %rax, %rdi
ja .m11
movl $10, %ecx
jmp .end
.m11:
movl $11, %ecx
jmp .end
.m11_12:
movabsq $999999999999, %rax
cmpq %rax, %rdi
ja .m12
movl $11, %ecx
jmp .end
.m12:
movl $12, %ecx
jmp .end
jumptable:
.quad .m0
.quad .m0
.quad .m0
.quad .m0_1
.quad .m1
.quad .m1
.quad .m1_2
.quad .m2
.quad .m2
.quad .m2_3
.quad .m3
.quad .m3
.quad .m3
.quad .m3_4
.quad .m4
.quad .m4
.quad .m4_5
.quad .m5
.quad .m5
.quad .m5_6
.quad .m6
.quad .m6
.quad .m6
.quad .m6_7
.quad .m7
.quad .m7
.quad .m7_8
.quad .m8
.quad .m8
.quad .m8_9
.quad .m9
.quad .m9
.quad .m9
.quad .m9_10
.quad .m10
.quad .m10
.quad .m10_11
.quad .m11
.quad .m11
.quad .m11_12
.quad .m12
.quad .m12
.quad .m12
.end:
/* output is given in %ecx */
Ini sebagian besar dihasilkan dari output assembler gcc untuk kode C proof-of-concept yang saya tulis . Perhatikan kode C menggunakan goto yang dapat dihitung untuk mengimplementasikan tabel lompatan. Ia juga menggunakan __builtin_clzll()
gcc builtin, yang mengkompilasi bsr
instruksi (plus an xor
).
Saya mempertimbangkan beberapa solusi sebelum sampai pada yang ini:
FYL2X
untuk menghitung log natural, maka FMUL
dengan konstanta yang diperlukan. Ini mungkin akan memenangkan ini jika ini adalah kontes [tag: instructions: golf]. Tetapi FYL2X
memiliki latency 90-106 untuk jembatan Ivy.
Pencarian biner dengan kode keras. Ini mungkin sebenarnya kompetitif - saya akan menyerahkannya kepada orang lain untuk diimplementasikan :).
Tabel hasil pencarian lengkap. Ini saya yakin secara teoritis tercepat, tetapi akan membutuhkan tabel pencarian 1TB - belum praktis - mungkin dalam beberapa tahun jika Hukum Moore terus berlaku.