यहाँ कुछ कोड है जो जीसीसी 6 और 7 जब std::array
का उपयोग कर अनुकूलन करने के लिए असफल है विफल रहता है:जीसीसी अनुकूलन करने के लिए गठबंधन std :: सी सरणी की तरह सरणी
#include <array>
static constexpr size_t my_elements = 8;
class Foo
{
public:
#ifdef C_ARRAY
typedef double Vec[my_elements] alignas(32);
#else
typedef std::array<double, my_elements> Vec alignas(32);
#endif
void fun1(const Vec&);
Vec v1{{}};
};
void Foo::fun1(const Vec& __restrict__ v2)
{
for (unsigned i = 0; i < my_elements; ++i)
{
v1[i] += v2[i];
}
}
g++ -std=c++14 -O3 -march=haswell -S -DC_ARRAY
साथ ऊपर संकलन का उत्पादन अच्छा कोड:
vmovapd ymm0, YMMWORD PTR [rdi]
vaddpd ymm0, ymm0, YMMWORD PTR [rsi]
vmovapd YMMWORD PTR [rdi], ymm0
vmovapd ymm0, YMMWORD PTR [rdi+32]
vaddpd ymm0, ymm0, YMMWORD PTR [rsi+32]
vmovapd YMMWORD PTR [rdi+32], ymm0
vzeroupper
यह 256-बिट रजिस्टरों के माध्यम से एक समय में चार युगल जोड़ने का मूल रूप से दो अनियंत्रित पुनरावृत्तियों है। लेकिन अगर आप -DC_ARRAY
बिना संकलन, तो आप इस के साथ शुरू एक विशाल गड़बड़ मिलती है:
mov rax, rdi
shr rax, 3
neg rax
and eax, 3
je .L7
कोड इस मामले में उत्पन्न (एक सादे सी सरणी के बजाय std::array
का प्रयोग करके) इनपुट के संरेखण के लिए जाँच करने के लिए लगता है array-- भले ही यह टाइप किए गए टाइप में 32 बाइट्स के रूप में निर्दिष्ट है।
ऐसा लगता है कि जीसीसी यह नहीं समझता कि std::array
की सामग्री std::array
के समान ही गठबंधन है। यह धारणा को तोड़ता है कि सी arrays के बजाय std::array
का उपयोग रनटाइम लागत नहीं लेता है।
क्या कुछ आसान है जो मुझे याद आ रही है जो इसे ठीक करेगी? अब तक मैं एक बदसूरत हैक के साथ आया था:
void Foo::fun2(const Vec& __restrict__ v2)
{
typedef double V2 alignas(Foo::Vec);
const V2* v2a = static_cast<const V2*>(&v2[0]);
for (unsigned i = 0; i < my_elements; ++i)
{
v1[i] += v2a[i];
}
}
भी ध्यान रखें: यदि my_elements
4 के बजाय 8, समस्या नहीं होती है। यदि आप क्लैंग का उपयोग करते हैं, तो समस्या नहीं होती है।
आप इसे यहाँ रहते देख सकते हैं: दिलचस्प बात यह है https://godbolt.org/g/IXIOst
Fwiw, बजना शिकायत है कि 'alignas', एक डेटा सदस्य पर होने की जरूरत है एक typedef पर नहीं है, लेकिन अगर बदलते' Vec' एक नेस्टेड क्लास होल्डिंग 'std :: array <...>' एक गठबंधन डेटा सदस्य के रूप में, और इसे 'ऑपरेटर []' अधिभार देता है, तो क्लैंग इसे अनुकूलित करने का प्रबंधन करता है। जीसीसी अभी भी नहीं है। – hvd
क्या 'std :: array' के अंतर्गत सरणी में' std :: array' के समान संरेखण है? –
और यदि 'वीईसी' को 'डबल डेटा [my_elements] alignas (32) धारण करने वाले वर्ग के रूप में लागू किया गया है,' कस्टम 'ऑपरेटर [] 'के साथ, तो जीसीसी इसे अनुकूलित करने का प्रबंधन करता है। मुझे संदेह है कि समस्या यह है कि 'सरणी :: ऑपरेटर [] 'एक असाइन किए गए' डबल 'को वापस लौटाता है जो कि इसके अनलाइन किए गए' सरणी :: _ M_elems' सदस्य से आता है, और तथ्य यह है कि यह एक गठबंधन सरणी का हिस्सा है, यह बहुत दूर है ऑप्टिमाइज़र इसे देखने में सक्षम होने के लिए। – hvd