class Wrapper {
public:
// some functions operating on the value_
__m128i value_;
};
int main() {
std::vector<Wrapper> a;
a.resize(100);
}
ли атрибут из Wrapper
объектов в vector a
всегда value_
занимает непрерывную память без каких-либо зазоров между __m128i values
?Имеет ли std :: vector <Simd_wrapper> непрерывные данные в памяти?
Я имею в виду:
[128 bit for 1st Wrapper][no gap here][128bit for 2nd Wrapper] ...
До сих пор, это, кажется, верно для г ++ и процессор Intel я использую, и GCC godbolt.
Поскольку существует только один атрибут __m128i в Wrapper
объекта, то это значит компилятор всегда не нужно добавлять любые дополнения в памяти? (Memory layout of vector of POD objects)
код Тест 1:
#include <iostream>
#include <vector>
#include <x86intrin.h>
int main()
{
static constexpr size_t N = 1000;
std::vector<__m128i> a;
a.resize(1000);
//__m128i a[1000];
uint32_t* ptr_a = reinterpret_cast<uint32_t*>(a.data());
for (size_t i = 0; i < 4*N; ++i)
ptr_a[i] = i;
for (size_t i = 1; i < N; ++i){
a[i-1] = _mm_and_si128 (a[i], a[i-1]);
}
for (size_t i = 0; i < 4*N; ++i)
std::cout << ptr_a[i];
}
Предупреждение:
warning: ignoring attributes on template argument
'__m128i {aka __vector(2) long long int}'
[-Wignored-attributes]
Ассамблея (gcc god bolt):
.L9:
add rax, 16
movdqa xmm1, XMMWORD PTR [rax]
pand xmm0, xmm1
movaps XMMWORD PTR [rax-16], xmm0
cmp rax, rdx
movdqa xmm0, xmm1
jne .L9
Я предполагаю, что это означает, что данные смежный, так как петли просто добавьте 16 байт в адрес памяти, который он читает в каждом цикле loo п. Он использует pand
для поразрядного и.
код Тест 2:
#include <iostream>
#include <vector>
#include <x86intrin.h>
class Wrapper {
public:
__m128i value_;
inline Wrapper& operator &= (const Wrapper& rhs)
{
value_ = _mm_and_si128(value_, rhs.value_);
}
}; // Wrapper
int main()
{
static constexpr size_t N = 1000;
std::vector<Wrapper> a;
a.resize(N);
//__m128i a[1000];
uint32_t* ptr_a = reinterpret_cast<uint32_t*>(a.data());
for (size_t i = 0; i < 4*N; ++i) ptr_a[i] = i;
for (size_t i = 1; i < N; ++i){
a[i-1] &=a[i];
//std::cout << ptr_a[i];
}
for (size_t i = 0; i < 4*N; ++i)
std::cout << ptr_a[i];
}
Ассамблея (gcc god bolt)
.L9:
add rdx, 2
add rax, 32
movdqa xmm1, XMMWORD PTR [rax-16]
pand xmm0, xmm1
movaps XMMWORD PTR [rax-32], xmm0
movdqa xmm0, XMMWORD PTR [rax]
pand xmm1, xmm0
movaps XMMWORD PTR [rax-16], xmm1
cmp rdx, 999
jne .L9
Похоже, без заполнения тоже. rax
увеличивается на 32 в каждом шаге, и что 2 х 16. Это дополнительный add rdx,2
, безусловно, не так хорошо, как цикл из тестового кода 1.
Тест авто-векторизации
#include <iostream>
#include <vector>
#include <x86intrin.h>
int main()
{
static constexpr size_t N = 1000;
std::vector<__m128i> a;
a.resize(1000);
//__m128i a[1000];
uint32_t* ptr_a = reinterpret_cast<uint32_t*>(a.data());
for (size_t i = 0; i < 4*N; ++i)
ptr_a[i] = i;
for (size_t i = 1; i < N; ++i){
a[i-1] = _mm_and_si128 (a[i], a[i-1]);
}
for (size_t i = 0; i < 4*N; ++i)
std::cout << ptr_a[i];
}
Ассамблея (god bolt) :
.L21:
movdqu xmm0, XMMWORD PTR [r10+rax]
add rdi, 1
pand xmm0, XMMWORD PTR [r8+rax]
movaps XMMWORD PTR [r8+rax], xmm0
add rax, 16
cmp rsi, rdi
ja .L21
... Я просто не знаю, если это всегда верно для процессоров Intel и г ++/Intel C++ компиляторы/(вставить имя компилятора здесь) ...
Да, но не гарантировано правильное выравнивание – MikeMB
это __m128i элементы. поэтому я надеюсь, что это означает, что каждый элемент вектора имеет 128-битное выравнивание. –
Это другой вопрос. Непрерывное хранение гарантировано, чрезмерное выравнивание - нет. –