C++Guns – RoboBlog

05.06.2018

C++ Guns: fold over std::tuple und erzeugten Assembler Code

Filed under: Allgemein — Tags: — Thomas @ 00:06

Hier ein Ausschnitt aus dem Kniffel Spiel Code. Habe jede gültige Kombination als einen Typ dargestellt mit einem gemeinsamen Typ Score, welcher die erzielten Punkte enthält. Um die gesamte Punktzahl zu erhalten, muss über jeden Typ im tuple iteriert werden und die einzelnen Punkte aufaddiert. Dies wird mit std::apply und fold erledigt.
Alternativ dazu wird in func2() nur über sieben Score Objekte iteriert und auf addiert. Mit Compiler Optimierung O1 ist der generierte Assembler Code mit dem std::apply und fold definitiv besser. Es werden sechs Addition Instruktionen erzeugt. Genau soviel wie benötigt werden um sieben Zahlen zu generieren ;)

Der Assembler Code von func2() hingegen zeigt eine Schleife. Dies finde ich bei so kleinen Datenmengen unnötig. Natürlich kann man mit Optimierung O3 loop unrolling aktivieren, aber der erzeugte Code wird damit noch schlechter. Die manuelle Aktivierung mit O1 und -funroll-loops oder -fpeel-loops erzeugt am Ende auch nur sechs Addition Instruktionen, aber dann ist loop unrolling für alle fix size Schleifen aktiviert. Auch für die, wo man es lieber nicht haben möchte.

Und natürlich geht mit der func2() Variante die Typ Information verloren. Also, std::apply und fold um über Typen zu iterieren. Find ich gut.

struct Score 
{
    int points = 0;
    
};

struct Dreierpasch : Score {
};

struct Viererpasch : Score {
};

struct FullHouse : Score {
};

struct KleineStrasse : Score {
};

struct GrosseStrasse : Score {
};

struct Kniffel : Score {
};

struct Chance : Score {
};

struct LowerScore;
namespace std {
    template<>
    struct tuple_size<LowerScore> : std::integral_constant<size_t,7> {};
}

struct LowerScore : std::tuple<Dreierpasch, Viererpasch, FullHouse, KleineStrasse, GrosseStrasse, Kniffel, Chance>
{
    int totalPoints() const {
        auto f = [](const auto...x){ return (x.points + ...); };
        return std::apply(f, *this );
    }
};

auto func(const LowerScore& score) {
    return score.totalPoints();
}

auto func2(const std::array<Score,7>& score) {
    int points = 0;
    for(const Score& s : score) {
        points += s.points;
    }
    return points;
}
func(LowerScore const&):
  movl (%rdi), %eax
  addl 4(%rdi), %eax
  addl 8(%rdi), %eax
  addl 12(%rdi), %eax
  addl 16(%rdi), %eax
  addl 20(%rdi), %eax
  addl 24(%rdi), %eax
  ret
func2(std::array<Score, 7ul> const&):
  leaq 28(%rdi), %rdx
  movl $0, %eax
.L3:
  addl (%rdi), %eax
  addq $4, %rdi
  cmpq %rdx, %rdi
  jne .L3
  ret

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress