여기 일부 std::array
사용시 GCC 6,7 최적화 실패 코드의 C 배열처럼 정렬 표준 : 배열을 최적화하기 위해 실패 생성 g++ -std=c++14 -O3 -march=haswell -S -DC_ARRAY
와 상기 컴파일GCC가
#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];
}
}
좋은 코드 :
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 비트 레지스터를 통해 한 번에 4 개의 double을 추가하는 두 번 풀지 않은 반복 작업입니다. 당신이 -DC_ARRAY
없이 컴파일하는 경우, 당신은이로 시작하는 큰 혼란을 얻을 :
mov rax, rdi
shr rax, 3
neg rax
and eax, 3
je .L7
이 경우 생성 된 코드는 (대신 일반 C 배열의 std::array
사용)
std::array
의 내용이 std::array
과 동일하게 정렬되어있는 것으로 GCC에서 이해하지 못하는 것 같습니다. 이는 C 배열 대신 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 인 경우, 문제가 발생하지 않습니다. Clang을 사용하면 문제가 발생하지 않습니다. , GCC는 C의 경우뿐만 아니라 표준 : 배열 케이스를 최적화하기 위해 관리
https://godbolt.org/g/IXIOst
FWIW을, 그 소리는 alignas'이 아닌 형식 정의에 데이터 멤버에 있어야하지만,'Vec'을 변경하는 경우 '불평 'std :: array <...>'을 정렬 된 데이터 멤버로 가지고있는 중첩 클래스에'operator []'오버로드를 주면, clang은 이것을 최적화하도록 관리한다. GCC는 여전히 그렇지 않습니다. – hvd
'std :: array'의 기본 배열은'std :: array'와 같은 정렬을 가지고 있습니까? –
그리고'Vec'가'double data [my_elements] alignas (32);'를 가지고 있고, 커스텀'operator []'로 구현되어 있다면, GCC는 이것을 최적화 할 수 있습니다. 그 문제는'array :: operator []'가 정렬되지 않은'array :: _ M_elems' 멤버에서 오는 정렬되지 않은'double '을 반환한다는 것과 배열 된 배열의 일부라는 사실이 너무 멀었다는 것입니다 옵티 마이저가 그것을 볼 수 있도록. – hvd