2008-12-10 8 views
9

निम्नलिखित कोड जीसीसी में क्लोज/सीटीजेड के लिए बिल्टिन फ़ंक्शंस को कॉल करता है और अन्य सिस्टम पर, सी संस्करण हैं। जाहिर है, सी संस्करण एक बिट सबोपेटिमल हैं यदि सिस्टम में बिल्टिन क्लोज/सीटीजेड निर्देश है, जैसे कि x86 और एआरएम।इस जीसीसी कोड के बराबर पाने के लिए एमएसवीसी इंट्रिनिक्स का उपयोग कैसे करें?

#ifdef __GNUC__ 
#define clz(x) __builtin_clz(x) 
#define ctz(x) __builtin_ctz(x) 
#else 
static uint32_t ALWAYS_INLINE popcnt(uint32_t x) 
{ 
    x -= ((x >> 1) & 0x55555555); 
    x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); 
    x = (((x >> 4) + x) & 0x0f0f0f0f); 
    x += (x >> 8); 
    x += (x >> 16); 
    return x & 0x0000003f; 
} 
static uint32_t ALWAYS_INLINE clz(uint32_t x) 
{ 
    x |= (x >> 1); 
    x |= (x >> 2); 
    x |= (x >> 4); 
    x |= (x >> 8); 
    x |= (x >> 16); 
    return 32 - popcnt(x); 
} 
static uint32_t ALWAYS_INLINE ctz(uint32_t x) 
{ 
    return popcnt((x & -x) - 1); 
} 

#endif 

क्या कार्यों मैं जो हेडर मैं यहाँ MSVC के लिए एक उचित ifdef जोड़ने के लिए शामिल करने की जरूरत है, आदि कॉल करने के लिए की आवश्यकता क्यों है? मैंने पहले से ही this page देखा है, लेकिन मुझे पूरी तरह से यकीन नहीं है कि #pragma क्या है (क्या यह आवश्यक है?) और संकलन के लिए एमएसवीसी संस्करण आवश्यकताओं पर क्या प्रतिबंध लगाते हैं। किसी ऐसे व्यक्ति के रूप में जो वास्तव में एमएसवीसी का उपयोग नहीं करता है, मुझे यह भी नहीं पता कि इन इंट्रिनिक्स में अन्य आर्किटेक्चर पर सी समकक्ष हैं या क्या मुझे #dedef x86/x86_64 के साथ-साथ # परिभाषित करना है।

+0

पेज आप ऊपर का उल्लेख है, एक समारोह है कि .NET रनटाइम का हिस्सा है को संदर्भित करता है आप नेट के लिए या एक देशी विंडोज निष्पादन योग्य के रूप में अपने कार्यक्रम बनाने की कोशिश कर रहे हैं ? –

+0

यह एक देशी विंडोज निष्पादन योग्य है - मैं जिस कारण से पूछ रहा हूं उसका एक हिस्सा यह है कि मुझे माइक्रोसॉफ्ट प्रलेखन पृष्ठों को खोजने में मुश्किल होती है जो वास्तव में इन दिनों सी के बारे में बात करते हैं। –

+0

Libcxx कार्यान्वयन https://github.com/llvm-mirror/libcxx/blob/9dcbb46826fd4d29b1485f25e8986d36019a6dca/include/support/win32/support.h#L106-L182 – KindDragon

उत्तर

1

MSVC एक संकलक इस के लिए आंतरिक है, यह यहाँ हो जाएगा:

Compiler Intrinsics on MSDN

अन्यथा, आप __asm ​​का उपयोग कर

-2

वहाँ दो intrinsics रहे हैं "_BitScanForward" यह लिखने के लिए होगा और "_BitScanReverse", जो एमएसवीसी के लिए एक ही उद्देश्य के अनुरूप है। शामिल । कार्य हैं:

#ifdef _MSC_VER 
#include <intrin.h> 

static uint32_t __inline ctz(uint32_t x) 
{ 
    int r = 0; 
    _BitScanReverse(&r, x); 
    return r; 
} 

static uint32_t __inline clz(uint32_t x) 
{ 
    int r = 0; 
    _BitScanForward(&r, x); 
    return r; 
} 
#endif 

बराबर 64 बिट संस्करण हैं "_BitScanForward64" और "_BitScanReverse64"।

और पढ़ें यहाँ:

x86 Intrinsics on MSDN

+11

ctz और clz गलत फ़ंक्शंस को कॉल करें (उन्हें _BitScanForward और BitScanReverse का उपयोग करना चाहिए क्रमशः, बिटस्केन रिवरसे/बिटस्केनफॉरवर्ड नहीं) और क्लैज गलत है क्योंकि यह प्रमुख शून्यों की संख्या के बजाय बिट सेट के ऑफसेट को लौटाता है। – Vitali

15

sh0dan कोड से बाउंस, कार्यान्वयन इस तरह सही किया जाना चाहिए:

#ifdef _MSC_VER 
#include <intrin.h> 

uint32_t __inline ctz(uint32_t value) 
{ 
    DWORD trailing_zero = 0; 

    if (_BitScanForward(&trailing_zero, value)) 
    { 
     return trailing_zero; 
    } 
    else 
    { 
     // This is undefined, I better choose 32 than 0 
     return 32; 
    } 
} 

uint32_t __inline clz(uint32_t value) 
{ 
    DWORD leading_zero = 0; 

    if (_BitScanReverse(&leading_zero, value)) 
    { 
     return 31 - leading_zero; 
    } 
    else 
    { 
     // Same remarks as above 
     return 32; 
    } 
} 
#endif 

के रूप में कोड में टिप्पणी की, दोनों CTZ और CLZ अगर अपरिभाषित हैं मान 0 है। हमारे अमूर्तता में, हमने __builtin_clz(value) को (value?__builtin_clz(value):32) के रूप में तय किया है, लेकिन यह एक विकल्प है

+1

एमएसवीसी में '__builtin_clz()' के लिए लगभग 1-से-1 प्रतिस्थापन '__lzcnt()' है। हालांकि हार्डवेयर को एसएसई 4 का समर्थन करना चाहिए। [अधिक जानकारी] (https://msdn.microsoft.com/en-US/library/bb384809.aspx)। – rustyx

+1

मेरा हार्डवेयर एसएसई 4 का समर्थन करता है, लेकिन बीएमआई 1 नहीं, इसलिए __lzcnt() संकलित करता है लेकिन मैं जो अपेक्षा करता हूं वह नहीं करता बल्कि बीएसआर के रूप में काम करता है। – GregC

+0

'31^__ buildin_clz'' _BitScanReverse' – KindDragon

-2

टी दिलचस्पी लिनक्स और विंडोज (x86) पर:

#ifdef WIN32 
    #include <intrin.h> 
    static uint32_t __inline __builtin_clz(uint32_t x) { 
     unsigned long r = 0; 
     _BitScanReverse(&r, x); 
     return (31-r); 
    } 
#endif 

uint32_t clz64(const uint64_t x) 
{ 
    uint32_t u32 = (x >> 32); 
    uint32_t result = u32 ? __builtin_clz(u32) : 32; 
    if (result == 32) { 
     u32 = x & 0xFFFFFFFFUL; 
     result += (u32 ? __builtin_clz(u32) : 32); 
    } 
    return result; 
} 
+0

के बराबर है क्या आपने अपने clz64 के प्रदर्शन का परीक्षण किया है? मुझे आश्चर्य नहीं होगा कि यह सभी शाखाएं ओपी के कार्यान्वयन से धीमी हो जाती हैं। – plamenko

संबंधित मुद्दे