Hier einige Code, der GCC 6 und 7 nicht zur Optimierung zu optimieren schlägt fehl, wenn std::array
mit:GCC ausgerichtet std :: Array wie C-Array
#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];
}
}
die oben Kompilieren mit g++ -std=c++14 -O3 -march=haswell -S -DC_ARRAY
produziert schöne Code:
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
, die über 256-Bit-Register zu einem Zeitpunkt der Zugabe von vier Doppel grundsätzlich zwei abgerollt Iterationen ist. Aber wenn Sie ohne -DC_ARRAY
kompilieren, erhalten Sie ein großes Durcheinander mit dieser Start:
mov rax, rdi
shr rax, 3
neg rax
and eax, 3
je .L7
Der Code erzeugt in diesem Fall (std::array
anstelle eines einfachen C-Array verwendet wird) für die Ausrichtung der Eingabe zu überprüfen scheint array-- obwohl es in typedef als auf 32 Bytes ausgerichtet angegeben ist.
Es scheint, dass GCC nicht versteht, dass der Inhalt eines die gleichen wie die selbst ausgerichtet sind. Dies unterbindet die Annahme, dass die Verwendung von anstelle von C-Arrays keine Laufzeitkosten verursacht.
Gibt es etwas, einfach fehlt mir, dass dieses Problem beheben würde? Bisher habe ich mit einem hässlichen Hack kam:
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];
}
}
Beachten Sie auch: wenn my_elements
4 statt 8, tritt das Problem nicht auf. Wenn Sie Clang verwenden, tritt das Problem nicht auf.
Sie können es hier live sehen: https://godbolt.org/g/IXIOst
FWIW, Klirren beklagt, dass 'alignas' auf einem Datum Mitglied sein muss, nicht auf einem typedef, aber wenn Wechsel' Vec' zu einer geschachtelten Klasse, die 'std :: array <...>' als ein ausgerichteter Datenmember hält und ihm 'operator []' overloads gibt, dann kann clang das optimieren. GCC tut es immer noch nicht. – hvd
Hat das dem 'std :: array' zugrunde liegende Array die gleiche Ausrichtung wie das' std :: array'? –
Und wenn 'Vec' als eine Klasse implementiert wird, die' double data [my_elements] alignas (32); ', mit benutzerdefiniertem' operator [] 'enthält, dann kann GCC dies optimieren. Ich vermute, das Problem ist, dass 'array :: operator []' ein nicht ausgerichtetes 'double &' zurückgibt, das von seinem nicht ausgerichteten 'array :: _ M_elems' Element kommt, und die Tatsache, dass es Teil eines ausgerichteten Arrays ist, ist nur ein bisschen zu weit damit der Optimierer es sehen kann. – hvd