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 bsrinstruksi (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 bsrinstruksi adalah OK.
Dalam input kasus terbaik, entri jumptable dapat memetakan bsrhasilnya langsung ke besarnya. mis. Untuk input dalam kisaran 32-63, bsrhasilnya 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, bsrhasilnya akan memetakan ke dua besaran yang mungkin, sehingga entri jumptable melakukan satu tambahan cmpuntuk memeriksa apakah inputnya> 10 n . Misalnya untuk input dalam kisaran 64-127, bsrhasilnya 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 bsrinstruksi (plus an xor).
Saya mempertimbangkan beberapa solusi sebelum sampai pada yang ini:
FYL2Xuntuk menghitung log natural, maka FMULdengan konstanta yang diperlukan. Ini mungkin akan memenangkan ini jika ini adalah kontes [tag: instructions: golf]. Tetapi FYL2Xmemiliki 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.