2012-09-11 27 views
6

मैं एक परियोजना के लिए जीसीसी सिम वेक्टर एक्सटेंशन का उपयोग कर रहा हूं, सब कुछ काफी अच्छी तरह से काम करता है लेकिन रहता है, वे बस वेक्टर के सभी घटकों को रीसेट करते हैं।जीसीसी में तैरने के लिए सिमड इंट वैक्टर को कैसे डाला जाए?

manual कहता है:

यह एक से दूसरे वेक्टर प्रकार से कास्ट करने के लिए संभव है, बशर्ते कि वे (एक ही आकार के होते हैं, वास्तव में, आप भी करने के लिए और एक ही के अन्य डेटाटाइप्स से वैक्टर डाल सकता आकार)।

#include <stdio.h> 

typedef int int4 __attribute__ ((vector_size(sizeof(int) * 4))); 
typedef float float4 __attribute__ ((vector_size(sizeof(float) * 4))); 

int main() 
{ 
    int4 i = { 1 , 2 , 3 , 4 }; 
    float4 f = { 0.1 , 0.2 , 0.3 , 0.4 }; 

    printf("%i %i %i %i\n" , i[0] , i[1] , i[2] , i[3]); 
    printf("%f %f %f %f\n" , f[0] , f[1] , f[2] , f[3]); 

    f = (float4)i; 

    printf("%f %f %f %f\n" , f[0] , f[1] , f[2] , f[3]); 
} 

gcc cast.c -O3 -o cast साथ संकलन और मेरे मशीन पर चल रहा प्राप्त:

1 2 3 4 
0.100000 0.200000 0.300000 0.400000 
0.000000 0.000000 0.000000 0.000000 <-- no no no 

मुझे लगता है कि कोडांतरक गुरु नहीं कर रहा हूँ, लेकिन मैं सिर्फ कुछ बाइट आंदोलनों को देखने

यहाँ एक सरल उदाहरण है यहां:

 
[...] 
400454:  f2 0f 10 1d 1c 02 00 movsd 0x21c(%rip),%xmm3 
40045b:  00 
40045c:  bf 49 06 40 00   mov $0x400649,%edi 
400461:  f2 0f 10 15 17 02 00 movsd 0x217(%rip),%xmm2 
400468:  00 
400469:  b8 04 00 00 00   mov $0x4,%eax 
40046e:  f2 0f 10 0d 12 02 00 movsd 0x212(%rip),%xmm1 
400475:  00 
400476:  f2 0f 10 05 12 02 00 movsd 0x212(%rip),%xmm0 
40047d:  00 
40047e:  48 83 c4 08    add $0x8,%rsp 
400482:  e9 59 ff ff ff   jmpq 4003e0 

मैं स्केलर के वेक्टर समकक्ष का निरीक्षण करें:

*(int *)&float_value = int_value; 

आप इस व्यवहार को कैसे समझा सकते हैं?

+3

हाँ, यह है कि यह क्या लगता है कि क्या हो रहा है है। (या बल्कि, कोई रूपांतरण नहीं) तो आपको वास्तविक मूल्य रूपांतरण की बजाय 4 denormalized floats मिलते हैं। – Mysticial

+1

वही है जो वेक्टर कास्ट करने के लिए परिभाषित किया गया है (कुछ भी पूरी तरह से बोनर होगा, और मानक वेक्टर प्रोग्रामिंग मुहावरे लिखने के लिए बहुत दर्दनाक होगा)। यदि आप वास्तव में रूपांतरण प्राप्त करना चाहते हैं, तो आप शायद कुछ प्रकार के अंतर्निहित का उपयोग करना चाहेंगे, जैसे '_mm_cvtepi32_ps' (यह आपके वेक्टर कोड की अच्छी वास्तुशिल्प आजादी को तोड़ देता है, जो भी परेशान है; एक आम दृष्टिकोण है एक अनुवाद शीर्षलेख का उपयोग करने के लिए जो "intrinsics" के पोर्टेबल सेट को परिभाषित करता है)। –

+0

मैं आपका बिंदु देख सकता हूं, लेकिन सवाल बन गया: यह _cast_ कब उपयोगी होगा? – cYrus

उत्तर

8

वही है जो वेक्टर कास्ट करने के लिए परिभाषित किया जाता है (कुछ भी पूरी तरह से बोनर होगा, और मानक वेक्टर प्रोग्रामिंग मुहावरे लिखने के लिए बहुत दर्दनाक होगा)। यदि आप वास्तव में रूपांतरण प्राप्त करना चाहते हैं, तो आप शायद कुछ प्रकार के आंतरिक उपयोग करना चाहेंगे, जैसे कि _mm_cvtepi32_ps (यह आपके वेक्टर कोड की अच्छी वास्तुशिल्प आजादी को तोड़ देता है, जो भी परेशान है; एक आम दृष्टिकोण उपयोग करना है एक अनुवाद शीर्षलेख जो "अंतर्निहित" के पोर्टेबल सेट को परिभाषित करता है)।

यह उपयोगी क्यों है? कई कारण हैं, लेकिन यहां सबसे बड़ा है:

वेक्टर कोड में, आप लगभग कभी शाखा नहीं बनाना चाहते हैं। इसके बजाय, अगर आपको सशर्त रूप से कुछ करने की ज़रूरत है, तो आप इस शर्त के दोनों पक्षों का मूल्यांकन करते हैं, और लेन द्वारा उपयुक्त परिणाम लेन का चयन करने के लिए मास्क का उपयोग करते हैं। इन मुखौटा वैक्टरों में "स्वाभाविक रूप से" पूर्णांक प्रकार होता है, जबकि आपके डेटा वेक्टर अक्सर फ़्लोटिंग-पॉइंट होते हैं; आप लॉजिकल ऑपरेशंस का उपयोग करके दोनों को गठबंधन करना चाहते हैं। यह बेहद आम मुहावरे सबसे स्वाभाविक है यदि वेक्टर बिट्स को फिर से समझता है।

अनुमोदित, इस मामले के आसपास काम करना संभव है, या अन्य सामान्य वेक्टर मुहावरों के किसी भी बैग के लिए काम करना संभव है, लेकिन "वेक्टर बिट्स का एक बैग है" दृश्य बेहद आम है, और अधिकांश वेक्टर प्रोग्रामर सोचने के तरीके को दर्शाता है।

2

वास्तव में, आपके मामले में कोई भी वेक्टर निर्देश भी उत्पन्न नहीं हो रहा है और रनटाइम पर भी कोई टाइपकास्ट नहीं किया जा रहा है। यह सब -O3 स्विच की वजह से संकलित समय पर किया जाता है। चार MOVSD निर्देश वास्तव में पूर्ववर्ती तर्कों को printf पर लोड कर रहे हैं। दरअसल, एसआईएसवी एएमडी 64 एबीआई के अनुसार, एक्सएमएम रजिस्टरों में फ्लोटिंग पॉइंट तर्क पारित किए जाते हैं।

movsd .LC6(%rip), %xmm3 
    movl $.LC5, %edi 
    movsd .LC7(%rip), %xmm2 
    movl $4, %eax 
    movsd .LC8(%rip), %xmm1 
    movsd .LC9(%rip), %xmm0 
    addq $8, %rsp 
    .cfi_def_cfa_offset 8 
    jmp  printf 
    .cfi_endproc 

.LC5 लेबल प्रारूप स्ट्रिंग:

.LC5: 
    .string "%f %f %f %f\n" 

सूचक प्रारूप स्ट्रिंग के लिए वर्ग INTEGER की है और अनुभाग है कि आप disassembled है (विधानसभा -S साथ संकलन द्वारा प्राप्त कोड) है इस प्रकार RDI रजिस्टर में पास किया गया है (वीए स्पेस के पहले 4 जीबीबी में कहीं भी, कुछ कोड बाइट RDI के निचले हिस्से में 32-बिट चाल जारी करके सहेजे जाते हैं)। RAX (EAX कोड बाइट्स पर सहेजने के लिए उपयोग किया जाता है) एक्सएमएम रजिस्टरों में पारित तर्कों की संख्या से भरा हुआ है (फिर से एसईएसवी एएमडी 64 एबीआई के अनुसार तर्कों की परिवर्तनीय संख्या के साथ कार्यों के लिए कॉल के लिए)। सभी चार MOVSD (MOVe Scalar Double-precision) XMM रजिस्टरों में संबंधित तर्कों को स्थानांतरित करते हैं।

.align 8 
.LC9: 
    .long 0 
    .long 916455424 

उन दो प्रपत्र 64-बिट quadword 0x36A0000000000000 जो होता है 2 -149 64-बिट आईईईई 754 प्रतिनिधित्व में होने के लिए: उदाहरण के लिए .LC9 दो doublewords लेबल करता है। 32-बिट आईईईई 754 में यह 0x00000001 जैसा दिखता है, इसलिए वास्तव में यह पूर्णांक 1 का कोई रूपांतरण नहीं है (लेकिन printfdouble तर्कों की अपेक्षा करता है कि यह अभी भी डबल परिशुद्धता के लिए पूर्ववर्ती है)। दूसरा तर्क है:

.align 8 
.LC8: 
    .long 0 
    .long 917504000 

यह 0x36B0000000000000 या 2 -148 64-बिट आईईईई 754 में और denormalised 32-बिट में 0x00000002 आईईईई 754 है यह अन्य दो तर्क के लिए एक ही चला जाता है।

ध्यान दें कि उपर्युक्त कोड एकल स्टैक वैरिएबल का उपयोग नहीं करता है - यह केवल प्रीकंप्यूटेड स्थिरांक के साथ संचालित होता है। यह बहुत उच्च अनुकूलन स्तर (-O3) का उपयोग करने से परिणाम देता है। एक वास्तविक रनटाइम रूपांतरण होता है यदि आप कम अनुकूलन स्तर (-O2 या उससे कम) के साथ संकलित करते हैं। निम्नलिखित कोड तो समान किरदार को करने के लिए उत्सर्जित होता है:

movaps -16(%rbp), %xmm0 
    movaps %xmm0, -32(%rbp) 

यह सिर्फ चार पूर्णांक मूल्यों चल बिन्दु वेक्टर की इसी स्लॉट में, ले जाता है इसलिए कोई भी रूपांतरण। फिर प्रत्येक तत्व के लिए कुछ SSE mumbo- जंबो ताकि इसे एकल परिशुद्धता से डबल परिशुद्धता (के रूप में printf द्वारा की उम्मीद) में बदलने के लिए में किया जाता है:

movss -20(%rbp), %xmm0 
    unpcklps  %xmm0, %xmm0 
    cvtps2pd  %xmm0, %xmm3 

(क्यों नहीं बस का उपयोग CVTSS2SD SSE अनुदेश की मेरी समझ से परे है सेट)

+0

स्पष्टीकरण के लिए धन्यवाद! – cYrus

+0

आपका स्वागत है! –

1

आप पूर्णांक से डाली सीधे

float4 cast(int4 x) { 
    float4 y; 
    for(int i=0; i<4; i++) y[i] = x[i]; 
    return y; 
} 

जीसीसी, बजना, और आईसीसी तत्वों से अधिक पाशन द्वारा फ्लोट करने के लिए कर सकते हैं यह सब के लिए एक अनुदेश cvtdq2ps xmm0, xmm0 उत्पन्न करते हैं। एक बिटवाइज़ रूपांतरण -

https://godbolt.org/g/KU1aPg