सबसे अच्छा मामला 8 चक्र, सबसे खराब मामला 12 चक्र
चूंकि यह प्रश्न में स्पष्ट नहीं है, इसलिए मैं इसे आइवी ब्रिज की विलंबता से दूर कर रहा हूं।
यहाँ दृष्टिकोण bsr
एक गरीब आदमी के log2 () के रूप में (बिट स्कैन रिवर्स) अनुदेश का उपयोग करना है । परिणाम को एक जम्प टेबल में एक इंडेक्स के रूप में उपयोग किया जाता है जिसमें बिट्स 0 से 42 के लिए प्रविष्टियां होती हैं। मैं मान रहा हूं कि 64 बिट डेटा पर उस ऑपरेशन को दिए जाने की आवश्यकता है, फिर bsr
निर्देश का उपयोग ठीक है।
सबसे अच्छा मामला इनपुट में, जुमटेबल प्रविष्टि bsr
परिणाम को सीधे परिमाण में मैप कर सकती है । उदाहरण के लिए सीमा 32-63 में इनपुट के लिए, bsr
परिणाम 5 होगा, जिसे 1. के परिमाण में मैप किया जाता है। इस मामले में, अनुदेश मार्ग है:
Instruction Latency
bsrq 3
jmp 2
movl 1
jmp 2
total 8
सबसे खराब स्थिति इनपुट में, bsr
परिणाम दो संभावित परिमाणों के लिए मैप होगा, इसलिए जम्पटेबल प्रविष्टि यह cmp
जांचने के लिए एक अतिरिक्त करती है कि इनपुट> 10 एन है या नहीं । उदाहरण के लिए ६४-१२, रेंज में इनपुट के लिए, bsr
परिणाम ६ होगा। इसी जम्पटेबल प्रविष्टि तब जांचता है कि इनपुट> १०० है और तदनुसार उत्पादन परिमाण सेट करता है।
सबसे खराब स्थिति पथ के अलावा, हमारे पास उपयोग करने के लिए 64 बिट तत्काल मूल्य को लोड करने के लिए एक अतिरिक्त चल अनुदेश है cmp
, इसलिए सबसे खराब स्थिति निर्देश है:
Instruction Latency
bsrq 3
jmp 2
movabsq 1
cmpq 1
ja 2
movl 1
jmp 2
total 12
यहाँ कोड है:
/* 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 */
यह ज्यादातर प्रूफ-ऑफ-कॉन्सेप्ट C कोड मैंने लिखा था के लिए gcc असेंबलर आउटपुट से उत्पन्न हुआ था । नोट सी कोड जंप टेबल को लागू करने के लिए एक कम्प्यूटेशनल गोटो का उपयोग करता है। यह __builtin_clzll()
gcc बिलिन का भी उपयोग करता है , जो bsr
निर्देश (प्लस xor
) के लिए संकलित करता है ।
मैंने इस पर पहुंचने से पहले कई समाधानों पर विचार किया:
FYL2X
प्राकृतिक लॉग की गणना करने के लिए, फिर FMUL
आवश्यक स्थिरांक द्वारा। अगर यह एक [टैग: निर्देश: गोल्फ] प्रतियोगिता होती तो यह निश्चित रूप से जीतता। लेकिन FYL2X
आइवी ब्रिज के लिए 90-106 की विलंबता है।
हार्ड-कोडेड बाइनरी सर्च। यह वास्तव में प्रतिस्पर्धी हो सकता है - मैं इसे लागू करने के लिए किसी और को छोड़ दूँगा :)।
परिणामों की पूर्ण लुकिंग तालिका। मुझे यकीन है कि सैद्धांतिक रूप से सबसे तेज़ है, लेकिन 1TB लुकअप टेबल की आवश्यकता होगी - अभी तक व्यावहारिक नहीं - शायद कुछ वर्षों में अगर मूर का कानून जारी रहेगा।