2012-02-04 9 views
6

के साथ जोड़ें क्योंकि एडीसी के लिए कोई आंतरिक नहीं लगता है और मैं विज़ुअल सी ++ के साथ x64 आर्किटेक्चर के लिए इनलाइन असेंबलर का उपयोग नहीं कर सकता, अगर मुझे जोड़कर एक फ़ंक्शन लिखना है तो मुझे क्या करना चाहिए ले लो लेकिन इसे एक सी ++ नेमस्पेस में शामिल करें?विज़ुअल सी ++ x64 लेयर

(तुलना ऑपरेटरों के साथ नकल के लिए एक विकल्प है। यह 256 मेगाबिट ऐड प्रदर्शन महत्वपूर्ण है। नहीं है)

+0

हमें इस "256 मेगाबिट एड" के बारे में और बताएं। यह काफी संभावना है कि एक बार सिमड का उपयोग करके कई जोड़ों को जोड़ना काफी तेज होगा, भले ही कारों को एक अतिरिक्त कदम के रूप में संभाला जाना चाहिए। –

+0

मैंने पहले से ही थोड़ा सा शोध किया था। Http://stackoverflow.com/questions/8866973/can-long-integer-routines-benefit-from-sse देखें। – jnm2

+1

@ jnm2 - x64 तरीका अलग असेंबली कोड लिख रहा है और इसे आपके C++ फ़ंक्शन से कॉल करता है। असेंबलर पहले से ही पैकेज का हिस्सा है। –

उत्तर

4

There is now an instrinsic:, अभी भी, आप निम्न सी ++ एकमात्र समाधान है जो 256 बिट नंबर अनुकरण का एक अच्छा तरीका है पर विचार कर सकते एमएसवीसी में: _addcarry_u64। निम्नलिखित कोड

#include <inttypes.h> 
#include <intrin.h> 
#include <stdio.h> 

typedef struct { 
    uint64_t x1; 
    uint64_t x2; 
    uint64_t x3; 
    uint64_t x4; 
} uint256; 

void add256(uint256 *x, uint256 *y) { 
    unsigned char c = 0; 
    c = _addcarry_u64(c, x->x1, y->x1, &x->x1); 
    c = _addcarry_u64(c, x->x2, y->x2, &x->x2); 
    c = _addcarry_u64(c, x->x3, y->x3, &x->x3); 
    _addcarry_u64(c, x->x4, y->x4, &x->x4); 
} 

int main() { 
    //uint64_t x1, x2, x3, x4; 
    //uint64_t y1, y2, y3, y4; 
    uint256 x, y; 
    x.x1 = x.x2 = x.x3 = -1; x.x4 = 0; 
    y.x1 = 2; y.x2 = y.x3 = y.x4 = 0; 

    printf(" %016" PRIx64 "%016" PRIx64 "%016" PRIx64 "%016" PRIx64 "\n", x.x4, x.x3, x.x2, x.x1); 
    printf("+"); 
    printf("%016" PRIx64 "%016" PRIx64 "%016" PRIx64 "%016" PRIx64 "\n", y.x4, y.x3, y.x2, y.x1); 
    add256(&x, &y); 
    printf("="); 
    printf("%016" PRIx64 "%016" PRIx64 "%016" PRIx64 "%016" PRIx64 "\n", x.x4, x.x3, x.x2, x.x1); 
} 

विजुअल स्टूडियो एक्सप्रेस 2013

mov rdx, QWORD PTR x$[rsp] 
mov r8, QWORD PTR x$[rsp+8] 
mov r9, QWORD PTR x$[rsp+16] 
mov rax, QWORD PTR x$[rsp+24] 
add rdx, QWORD PTR y$[rsp] 
adc r8, QWORD PTR y$[rsp+8] 
adc r9, QWORD PTR y$[rsp+16] 
adc rax, QWORD PTR y$[rsp+24] 

जो एक add और तीन adc अपेक्षा के अनुरूप है से निम्नलिखित विधानसभा उत्पादन पैदा करता है।

संपादित करें:

वहाँ _addcarry_u64 क्या करता है के रूप में कुछ भ्रम की स्थिति हो रहा है। यदि आप माइक्रोसॉफ्ट के दस्तावेज को देखते हैं जिसके लिए मैंने इस उत्तर की शुरुआत में लिंक किया है, तो यह दिखाता है कि इसे किसी विशेष हार्डवेयर की आवश्यकता नहीं है। यह adc उत्पन्न करता है और यह सभी x86-64 प्रोसेसर पर काम करेगा (और _addcarry_u32 पुराने प्रोसेसर पर भी काम करेगा)। यह आईवी ब्रिज सिस्टम पर ठीक काम करता है जिस पर मैंने परीक्षण किया था।

हालांकि, _addcarryx_u64 को adx (जैसा कि एमएसएफटी के दस्तावेज़ीकरण में दिखाया गया है) की आवश्यकता होती है और वास्तव में यह मेरी आइवी ब्रिज सिस्टम पर चलाने में विफल रहता है।

+1

इस उत्तर को अस्वीकरण की आवश्यकता है, यह निर्देश केवल 4 वें पीढ़ी के कोर प्रोसेसर (हैसवेल और ऊपर) पर उपयोग किया जा सकता है। एक और 5 से 10 साल और एक समर्थन फोन नंबर इससे पहले कि आप अंधेरे पर उपलब्ध हो सकें। –

+0

@ हंसपैसेंट मैं इसकी पुष्टि करने में सक्षम नहीं हूं। क्या आपके पास इसका संदर्भ है? – jnm2

+0

https://software.intel.com/en-us/node/523867 –

7

VS2010 संकलन और कोड विधानसभा में लिखा और MASM द्वारा अनुवादित जोड़ने के लिए निर्मित समर्थन किया है (ml64.exe) । इसे सक्षम करने के लिए आपको बस कुछ हुप्स से कूदना होगा:

  • समाधान एक्सप्लोरर विंडो में प्रोजेक्ट पर राइट-क्लिक करें, अनुकूलन बनाएं, "मैस्म" पर टिकटें।
  • परियोजना + नया आइटम जोड़ें,
  • सुनिश्चित करें कि आप इस परियोजना के लिए 64 मंच लक्ष्य मिल गया है सी ++ फ़ाइल टेम्पलेट लेकिन नाम यह something.asm लेने। बिल्ड + कॉन्फ़िगरेशन प्रबंधक, "सक्रिय समाधान प्लेटफ़ॉर्म" कॉम्बो में "x64" चुनें। यदि अनुपलब्ध है, तो <New> चुनें और पहले कॉम्बो से x64 चुनें। यदि गुम हो तो आपको सेटअप को फिर से चलाने और 64-बिट कंपाइलर्स के लिए समर्थन जोड़ने होंगे।

एमएएसएम वाक्यविन्यास, संदर्भ is here का उपयोग करके असेंबली कोड लिखें। त्वरित प्रारंभ ट्यूटोरियल is here

विधानसभा कोड के लिए कंकाल इस तरह दिखता है:

.CODE 
PUBLIC Foo 
Foo PROC 
    ret     ; TODO: make useful 
Foo ENDP 
END 

और C++ से इस तरह कोड कहा जाता है:

extern "C" void Foo(); 

int main(int argc, char* argv[]) 
{ 
    Foo(); 
    return 0; 
} 

पूर्ण डिबगिंग समर्थन उपलब्ध है, आप आमतौर पर चाहता हूँ कम से कम डीबग + विंडोज + रजिस्टर्स विंडो का उपयोग करें।

+0

इस मामले में आदर्श समाधान इनलाइन फ़ंक्शन (इनलाइन असेंबली) होगा। एक असेंबलर का उपयोग करना और ऑब्जेक्ट फ़ाइलों में लिंक करना ऐसा नहीं करेगा और एमएसवीसी में 64-बिट कोड इनलाइन असेंबली की अनुमति नहीं देता है। तो इसका मतलब है कि ओपी को कई अन्य कार्यों को लिखना है (जो संकलक शायद पहले से ही एक अच्छी नौकरी करता है) असेंबली में और साथ ही फ़ंक्शन कॉल से बचने के लिए भी। –

1

मैंने unsigned long long की सरणी का उपयोग करके 256 बिट पूर्णांक लागू किया है और कैर्री के साथ जोड़ने को लागू करने के लिए x64 असेंबली का उपयोग किया है।

#include "stdafx.h" 

extern "C" void add256(unsigned long long *a, unsigned long long * b, unsigned long long *c); 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    unsigned long long a[4] = {0x8000000000000001, 2, 3, 4}; 
    unsigned long long b[4] = {0x8000000000000005, 6, 7, 8}; 
    unsigned long long c[4] = {0, 0, 0, 0}; 
    add256(a, b, c); // c[] == {6, 9, 10, 12}; 
    return 0; 
} 

add256 विधानसभा में कार्यान्वित किया जाता है:: यहाँ सी ++ फोन करने वाले है

; void add256(unsigned long long *a, unsigned long long * b, unsigned long long *c) 

.CODE 
PUBLIC add256 
add256 PROC 

    mov     qword ptr [rsp+18h],r8  
    mov     qword ptr [rsp+10h],rdx  
    mov     qword ptr [rsp+8],rcx  
    push    rdi  

    ; c[0] = a[0] + b[0]; 

    mov     rax,qword ptr 16[rsp] 
    mov     rax,qword ptr [rax]  
    mov     rcx,qword ptr 24[rsp] 
    add     rax,qword ptr [rcx]  
    mov     rcx,qword ptr 32[rsp] 
    mov     qword ptr [rcx],rax  

    ; c[1] = a[1] + b[1] + CARRY; 

    mov     rax,qword ptr 16[rsp] 
    mov     rax,qword ptr [rax+8]  
    mov     rcx,qword ptr 24[rsp] 
    adc     rax,qword ptr [rcx+8]  
    mov     rcx,qword ptr 32[rsp] 
    mov     qword ptr [rcx+8],rax  

    ; c[2] = a[2] + b[2] + CARRY; 

    mov     rax,qword ptr 16[rsp] 
    mov     rax,qword ptr [rax+10h]  
    mov     rcx,qword ptr 24[rsp] 
    adc     rax,qword ptr [rcx+10h]  
    mov     rcx,qword ptr 32[rsp] 
    mov     qword ptr [rcx+10h],rax  

    ; c[3] = a[3] + b[3] + CARRY; 

    mov     rax,qword ptr 16[rsp] 
    mov     rax,qword ptr [rax+18h]  
    mov     rcx,qword ptr 24[rsp] 
    adc     rax,qword ptr [rcx+18h]  
    mov     rcx,qword ptr 32[rsp] 
    mov     qword ptr [rcx+18h],rax  

    ; } 

    pop     rdi  
    ret  

    add256    endp 

    end       

मैं तुम्हें यह दर्शाता है कि आप एक अनुकरणीय समाधान कैरी के साथ जोड़ने नहीं करना चाहता था पता है, और यदि कोई उच्च प्रदर्शन समाधान चाहता था, लेकिनके लिए

#include "stdafx.h" 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    unsigned long long a[4] = {0x8000000000000001, 2, 3, 4}; 
    unsigned long long b[4] = {0x8000000000000005, 6, 7, 8}; 
    unsigned long long c[4] = {0, 0, 0, 0}; 
    c[0] = a[0] + b[0]; // 6 
    c[1] = a[1] + b[1] + (c[0] < a[0]); // 9 
    c[2] = a[2] + b[2] + (c[1] < a[1]); // 10 
    c[3] = a[3] + b[3] + (c[2] < a[2]); // 12 
    return 0; 
} 
+0

देर से होने के लिए खेद है, लेकिन सी ++ समाधान सही नहीं है। सरलीकरण के रूप में एक = 01 और बी = 11 को लेयर = 1 के साथ मानें, फिर सी = 01 लेयर = 1 के साथ लेकिन सी <ए झूठा है। – knivil