दिलचस्प पोस्ट
संस्करण नियंत्रण के तहत आईप्याथॉन नोटबुक का उपयोग करना मैक ओएस पर माइस्क्ल स्थापित करें मैं चर की एक चर संख्या कैसे बना सकता हूँ? उपयोगकर्ता छवियां – डाटाबेस बनाम फाइलसिस्टम स्टोरेज / usr / bin / codeign निकास कोड 1 के साथ विफल एंड्रॉइड में सिंगलटन्स बनाम एप्लिकेशन प्रसंग? PHP में URL फिर से लिखना कैसे करें? अनुक्रमितों का सी ++ सॉर्टिंग और रखे जाने का तरीका पायथन अनुकरण keydown jQuery अनचाहे प्रकार त्रुटि: ऑब्जेक्ट की संपत्ति '$' फ़ंक्शन नहीं है सिम्युलेटर में स्विफ्ट (आईओएस 8) में एमएफमेल कॉम्पोज़ वीक कंट्रोलर के साथ असली गलतफहमी है मैं जेएसपी / जावा में डबल से पूरे और आंशिक हिस्से कैसे प्राप्त करूं? सी में फ़ंक्शन से मैं कई मान कैसे वापस करूँ? जावा मूल पद्धति स्रोत कोड रूबी तरीके में विस्मयादिबोधक चिह्न क्यों उपयोग किए जाते हैं?

लेरि फ्लैग के प्रयोग से 128-बिट अतिरिक्त कुशल

मैं अपने सी ++ कोड के बहुत ही आंतरिक छोरों में 128 बिट पूर्णांक काउंटर का उपयोग कर रहा हूँ (अप्रासंगिक पृष्ठभूमि: वास्तविक अनुप्रयोग एक नियमित ग्रिड पर परिमित अंतर समीकरण का मूल्यांकन कर रहा है, जिसमें पुनरावृत्त रूप से बड़े पूर्णांक को बढ़ाना शामिल है, और यहां तक ​​कि 64 बिट्स पर्याप्त सटीक नहीं हैं क्योंकि छोटे गोलाकार जवाब को प्रभावित करने के लिए पर्याप्त रूप से एकत्रित होते हैं।)

मैंने पूर्णांक को दो 64 बिट अहस्ताक्षरित लंबे के रूप में प्रतिनिधित्व किया है मुझे अब उन मानों को एक 128 बिट स्थिरांक से बढ़ाना होगा। यह मुश्किल नहीं है, लेकिन आपको मैन्युअल रूप से कम शब्द से उच्च शब्द तक ले जाने की आवश्यकता है।

मैंने इस तरह कुछ कोड काम किया है:

inline void increment128(unsigned long &hiWord, unsigned long &loWord) { const unsigned long hiAdd=0x0000062DE49B5241; const unsigned long loAdd=0x85DC198BCDD714BA; loWord += loAdd; if (loWord < loAdd) ++hiWord; // test_and_add_carry hiWord += hiAdd; } 

यह तंग और सरल कोड है यह काम करता हैं।

दुर्भाग्य से यह मेरे क्रम का लगभग 20% है। हत्यारे की रेखा यह है कि लोवर्ड टेस्ट अगर मैं इसे हटा देता हूं, मुझे स्पष्ट रूप से गलत उत्तर मिलते हैं लेकिन रनटाइम ओवरहेड 20% से 4% तक गिर जाता है! इसलिए ले जाने के लिए परीक्षण विशेष रूप से महंगा है!

मेरा प्रश्न: क्या सी ++ जीएससी के विस्तार के साथ-साथ हार्डवेयर वाले ध्वज को बेनकाब करता है? ऐसा लगता है कि अतिरिक्त संकलित निर्देशों का उपयोग वर्चुअल वर्ड के लिए पिछले लेयर निर्देशों का उपयोग करते हुए एक जोड़े का उपयोग करते हुए, ऊपर दिए गए परीक्षण और ऐड-लेयर लाइन के बिना किया जा सकता है। क्या आंतरिक ऑप्लोड का उपयोग करने के लिए कंपाइलर प्राप्त करने के लिए परीक्षण और ऐड-लेयर लाइन को फिर से लिखने का कोई तरीका है?

वेब के समाधान से एकत्रित समाधान "लेरि फ्लैग के प्रयोग से 128-बिट अतिरिक्त कुशल"

असल में जीसीसी स्वचालित रूप से ले जाने का उपयोग करेगा यदि आप अपना कोड सावधानी से लिखते हैं …

मैंने इस कोड को gcc -O2 -Wall -Werror -S के साथ संकलित किया है:

 void increment128_1(unsigned long &hiWord, unsigned long &loWord) { const unsigned long hiAdd=0x0000062DE49B5241; const unsigned long loAdd=0x85DC198BCDD714BA; loWord += loAdd; if (loWord < loAdd) ++hiWord; // test_and_add_carry hiWord += hiAdd; } void increment128_2(unsigned long &hiWord, unsigned long &loWord) { const unsigned long hiAdd=0x0000062DE49B5241; const unsigned long loAdd=0x85DC198BCDD714BA; loWord += loAdd; hiWord += hiAdd; hiWord += (loWord < loAdd); // test_and_add_carry } 

यह increment128_1 के लिए विधानसभा है:

 .cfi_startproc movabsq $-8801131483544218438, %rax addq (%rsi), %rax movabsq $-8801131483544218439, %rdx cmpq %rdx, %rax movq %rax, (%rsi) ja .L5 movq (%rdi), %rax addq $1, %rax .L3: movabsq $6794178679361, %rdx addq %rdx, %rax movq %rax, (%rdi) ret 

… और यह increment128_2 के लिए विधानसभा है:

  movabsq $-8801131483544218438, %rax addq %rax, (%rsi) movabsq $6794178679361, %rax addq (%rdi), %rax movabsq $-8801131483544218439, %rdx movq %rax, (%rdi) cmpq %rdx, (%rsi) setbe %dl movzbl %dl, %edx leaq (%rdx,%rax), %rax movq %rax, (%rdi) ret 

दूसरे संस्करण में सशर्त शाखाओं की कमी का ध्यान रखें।

[संपादित करें]

इसके अलावा, संदर्भ अक्सर प्रदर्शन के लिए खराब होते हैं, क्योंकि जीसीसी को अलियासिंग के बारे में चिंतित होना पड़ता है … यह मूल्य के आधार पर बस कुछ ही पारित करना बेहतर होता है विचार करें:

 struct my_uint128_t { unsigned long hi; unsigned long lo; }; my_uint128_t increment128_3(my_uint128_t x) { const unsigned long hiAdd=0x0000062DE49B5241; const unsigned long loAdd=0x85DC198BCDD714BA; x.lo += loAdd; x.hi += hiAdd + (x.lo < loAdd); return x; } 

सभा:

  .cfi_startproc movabsq $-8801131483544218438, %rdx movabsq $-8801131483544218439, %rax movabsq $6794178679362, %rcx addq %rsi, %rdx cmpq %rdx, %rax sbbq %rax, %rax addq %rcx, %rax addq %rdi, %rax ret 

यह वास्तव में तीनों का सबसे छोटा कोड है

… ठीक है तो उनमें से कोई भी वास्तव में स्वत: ही नहीं लेता 🙂 लेकिन वे सशर्त शाखा से बचते हैं, जो मैं शर्त लगाता हूं कि धीमी गति से भाग रहा है (चूंकि शाखा भविष्यवाणी तर्क यह गलत आधा समय मिलेगा)।

[संपादित करें 2]

और एक और, जिसने मुझे थोड़ा सा खोज करने में ठोकर खाई। क्या आपको पता है कि जीसीसी ने 128-बिट इंटिजर्स के लिए अंतर्निहित समर्थन दिया है?

 typedef unsigned long my_uint128_t __attribute__ ((mode(TI))); my_uint128_t increment128_4(my_uint128_t x) { const my_uint128_t hiAdd=0x0000062DE49B5241; const unsigned long loAdd=0x85DC198BCDD714BA; return x + (hiAdd << 64) + loAdd; } 

इस एक के लिए विधानसभा के बारे में के रूप में अच्छी तरह से यह हो जाता है:

  .cfi_startproc movabsq $-8801131483544218438, %rax movabsq $6794178679361, %rdx pushq %rbx .cfi_def_cfa_offset 16 addq %rdi, %rax adcq %rsi, %rdx popq %rbx .cfi_offset 3, -16 .cfi_def_cfa_offset 8 ret 

(यकीन नहीं है कि जहां ebx का पुश / पॉप आया था, लेकिन यह अभी भी बुरा नहीं है।)

ये सभी जीसीसी 4.5.2 के साथ हैं।

सबसे अच्छा जवाब, बेशक, अंतर्निहित __int128_t समर्थन का उपयोग करना है।

वैकल्पिक रूप से, एक इनलाइन asm का उपयोग करें मैं नाम-तर्क फ़ॉर्म का उपयोग करना पसंद करता हूं:

 __asm("add %[src_lo], %[dst_lo]\n" "adc %[src_hi], %[dst_hi]" : [dst_lo] "+&r" (loWord), [dst_hi] "+r" (hiWord) : [src_lo] "erm" (loAdd), [src_hi] "erm" (hiAdd) : ); 

loWord को एक शुरुआती loWord ऑपरेंड के रूप में चिह्नित किया गया है, क्योंकि इसमें कुछ अन्य ऑपरेंड पढ़ने से पहले लिखी गई है यह hiAdd = loWord के लिए गलत कोड से बचा जाता है, क्योंकि यह जीसीसी दोनों को धारण करने के लिए उसी रजिस्टर का उपयोग करने से रोक देगा। यह कंपाइलर को loAdd = loWord मामले के लिए एक ही रजिस्टर का उपयोग करने से loAdd = loWord है, हालांकि, जहां यह सुरक्षित है

जैसा कि शुरुआती समापन प्रश्न बताता है, इनलाइन एएसएम गलत हो जाना बहुत आसान है (हार्ड-टू-डिबग के तरीके में जो इसे कोड में कुछ बदलाव के बाद परेशान करता है)।

x86 और x86-64 इनलाइन एएसएम को झंडे को पकड़ना माना जाता है, इसलिए एक स्पष्ट "सीसी" क्लॉबर की आवश्यकता नहीं है।