[C++] Mikrooptimierungs-Log

Hier können Artikel, Tutorials, Bücherrezensionen, Dokumente aller Art, Texturen, Sprites, Sounds, Musik und Modelle zur Verfügung gestellt bzw. verlinkt werden.
Forumsregeln
Möglichst sinnvolle Präfixe oder die Themensymbole nutzen.

Re: Jammer-Thread

Beitragvon mrz » 09.08.2017, 16:00

MasterQ32 hat geschrieben:Junge Junge Junge, ihr diskutiert hier auf nem ganz schön hohen Niveau! Mal wieder alles sehr lehrreich!

Dem kann ich mich nur anschliessen.

Und wünsche mir dass ihr resp Krishty seine Entdeckungen auch jeweils den Jungs von Clang/LLVM
meldet damit ich irgendwann auch indirekt davon profitiere.
mrz
 
Beiträge: 26
Registriert: 07.08.2008, 14:34

Re: Jammer-Thread

Beitragvon Krishty » 09.08.2017, 16:15

Ganz ehrlich … die Zeit habe ich nicht. Wenn ich ein Patreon aufmache, und ihr mich dafür durchfüttert, dann vielleicht. Aber jetzt nicht auch noch Bug Tracker füttern, bitte nicht. Das kann jemand machen, der hier mitliest.

Ich habe eben fast eine Stunde(!) an der Konvertierung von unsigned char zu unsigned int gesessen. Dass GCC zwei Register nullt statt einem, das muss jemand anders melden. Ich krieg’s nicht gelöst und mein Hirn ist erstmal Matsche.

Code: Ansicht erweitern :: Alles auswählen
// Expands all elements to 4-B signed integers.
SInt4Bx4 SIMD_CALL asSInt4B(UInt1Bx4 const v) {
        // • interleave each 1-B lane with three zero bytes
        //   – first interleave each 1-B lane with 1 B of zeroes via SSE2’s PUNPCKLBW
        //   – then interleave each 2-B lane with 2 B of zeroes via SSE2’s PUNPCKLWD

#       if COMPILED_BY_VISUAL_CPP
                // • PUNPCKLBW is available via “_mm_unpacklo_epi8()” intrinsic
                // • PUNPCKLWD is available via “_mm_unpacklo_epi16()” intrinsic
                auto const v0v0v0v0         = _mm_unpacklo_epi8(v.uints, _mm_setzero_si128());
                auto const v000v000v000v000 = _mm_unpacklo_epi16(v0v0v0v0, _mm_setzero_si128());
                return { v000v000v000v000 };
#       elif COMPILED_BY_CLANG
                // • Clang’s code generation miserably fails vector initializer lists and vector casting
                // • no intrinsics available; need to use “__builtin_shufflevector()” instead
                auto const v0v0v0v0         = (IMPL_UINT2BX8)__builtin_shufflevector(v.uints, IMPL_UINT1BX16(), 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23);
                auto const v000v000v000v000 = (IMPL_SINT4BX4)__builtin_shufflevector(v0v0v0v0, IMPL_UINT2BX8(), 0, 8, 1, 9, 2, 10, 3, 11);
                return { v000v000v000v000 };
#       elif COMPILED_BY_GCC
                // • PUNPCKLBW is available via “__builtin_ia32_punpcklbw128()” intrinsic
                // • PUNPCLWD is available via “__builtin_ia32_punpcklwd128()” intrinsic
                // • code generation fails miserably with anything else
                // • TODO: for some reason, GCC zeroes two registers instead of one (not even Visual C++ fails here)
                auto const v0v0v0v0         = (IMPL_SINT2BX8)__builtin_ia32_punpcklbw128((IMPL_CHARX16)v.uints, IMPL_CHARX16());
                auto const v000v000v000v000 = (IMPL_SINT4BX4)__builtin_ia32_punpcklwd128(v0v0v0v0, IMPL_SINT2BX8());
                return { v000v000v000v000 };
#       endif
}


GCC erzeugt

  pxor xmm1, xmm1
  punpcklbw xmm0, xmm1
  pxor xmm1, xmm1
  punpcklwd xmm0, xmm1
  ret


und ich denke nicht, dass das doppelte pxor xmm1, xmm1 (Register auf Null setzen) eine blöde verpasste Optimierung ist, sondern dass im Gegenteil GCC zu stark zu optimieren versucht – wahrscheinlich etwas wie „das zweite Nullen kann ich die CPU unabhängig vom ersten ausführen lassen, damit es schneller fertig wird“ ohne zu begreifen, dass die Befehle sowieso aufeinander aufbauen und man deshalb nichts nebenläufig schedulen kann.

1.800 Zeichen, um drei Assembler-Befehle zu erzeugen. Mit direkter Nutzung der Intrinsic-Header (was jeder tun würde, der nicht bekloppt wie ich ist) wären es immernoch 665. Den Assembler-Code direkt hinschreiben wären … weniger als 100. Aber das darf ich ja nicht, denn Inline Assembly verwirrt die Compiler! Zum Kotzen. Einfach nur zum Kotzen. Seht, wie viel Zeit sie uns gespart haben mit ihrer portablen, leicht verständlichen, allmächtigen, Vektorsyntax! (CAST)__builtin_shufflevector((CAST)am, (CAST)arsch, 0, 13, 4, 9, 42, 36, Superzahl 666, achlecktmichdoch
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6026
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: Jammer-Thread

Beitragvon Krishty » 10.08.2017, 00:01

Ich bin immer noch bei WIRKLICH trivialen Funktionen und wollte mal was machen, das zu mehr als fünf Befehlen führt … OMFG, da geht alles schief.

Nehmen wir mal das hier:

  __m128i multiply_r8g8b8a8(__m128i l, __m128i r)

Zwei Farben multiplizieren, die als 8-Bit RGBA vorliegen. Nichts ausgefallenes. Kein Linear Color Space Blending. Kein garnichts. Trivial wäre:

  return {
    l.m128i_u8[0] * r.m128i_u8[0] / 255,
    l.m128i_u8[1] * r.m128i_u8[1] / 255,
    l.m128i_u8[2] * r.m128i_u8[2] / 255,
    l.m128i_u8[3] * r.m128i_u8[3] / 255
  };


Im Internet findet man viele Leute, die nicht einmal das schaffen. Die teilen durch 256. WTF?! 255 * 255 / 256 != 255. Eure Farben werden mit jedem Blending dunkler. Aber was weiß ich schon – ihr könnt eine Division durch Bit Shifting ersetzen. Ihr kennt euch mit Optimierung aus.

Die Befehle, die Visual C++ dafür ausspuckt, sind nicht der Rede wert: 37 Stück. Jeder unsigned char wird extrahiert, multipliziert, dividiert (die Division wird zu Shifts/Addition/Subtraktion optimiert), dann wieder zurückgeschrieben. Einerseits enttäuschend, andererseits haben wir aber die oberen 12 Bytes nicht definiert und der Compiler denkt nun, dass wir da unbedingt Nullen drin haben wollen und damit ist das alles schlecht optimierbar.

Auf Clang/GCC kompiliert das nicht, da muss man deren Vektorsyntax verwenden. Erstmal GCC mit 4×unsigned char:

  using UINT1BX4 = unsigned char __attribute__((vector_size(4)));
  UINT1BX4 mul_r8g8b8a8(UINT1BX4 l, UINT1BX4 r) {
    return l * r / 255;
  }


Etwa gleich viele Befehle wie Visual C++, nur dass die Vektorregister komplett übergangen werden. RICHTIG katastrophal auf Clang (mit richtigen skalaren Divisionen, man kann’s sich nicht ausdenken!). Erzwingen wir SSE durch 16 Vektorkomponenten:

  using UINT1BX4 = unsigned char __attribute__((vector_size(16)));
  UINT1BX4 mul_r8g8b8a8(UINT1BX4 const l, UINT1BX4 const r) {
    return l * r / (UINT1BX4){ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
  }


(ohne die lange Liste von 255ern frisst Clang es nicht)

29 Befehle in Clang; rund 125 in GCC. Beide fangen nun an, Vektorbefehle zu benutzen und z.B. vier Zahlen parallel zu multiplizieren. Nicht, dass es was helfen würde. Füttern wir nochmal genau die gleiche Beschreibung rein wie damals Visual C++, nur in Clang/GCC-Syntax:

  using UINT1BX4 = unsigned char __attribute__((vector_size(16)));
  UINT1BX4 mul_r8g8b8a8(UINT1BX4 const l, UINT1BX4 const r) {
    return (UINT1BX4){
      (unsigned char)(l[0] * r[0] / 255),
      (unsigned char)(l[1] * r[1] / 255),
      (unsigned char)(l[2] * r[2] / 255),
      (unsigned char)(l[3] * r[3] / 255)
    };
  }


33 Befehle in Clang, 45 in GCC, und beide umgehen Vektorisierung fast komplett.

Erstmal ist sicher: Autovektorisierung, SIMD-Syntax usw. kann man in die Tonne kloppen. Will man ordentlichen SIMD-Code, muss man von Hand Intrinsics aufrufen. Dummerweise ist das nur in Visual C++ einfach; in GCC noch umständlich möglich; in Clang quasi unmöglich.

„Einfache“ Intrinsics à „multiplizier den Vektor hier mit dem da“ gibt es nur, so lange man mit 4×float arbeitet. In alles andere muss man sich erstmal einarbeiten (es gibt um die 20 verschiedenen Intrinsics für Integermultiplikation, und fast keiner davon berechnet tatsächlich das Produkt).

Hier der beste skalare Compiler (Clang im letzten Versuch):
Code: Ansicht erweitern :: Alles auswählen
  movdqa xmmword ptr [rsp - 40], xmm0
  movzx r8d, byte ptr [rsp - 37]
  movzx r9d, byte ptr [rsp - 38]
  movzx r10d, byte ptr [rsp - 39]
  movzx edi, byte ptr [rsp - 40]
  movaps xmmword ptr [rsp - 24], xmm1
  movzx edx, byte ptr [rsp - 21]
  movzx esi, byte ptr [rsp - 22]
  movzx eax, byte ptr [rsp - 23]
  movzx ecx, byte ptr [rsp - 24]
  imul ecx, edi
  mov edi, 2155905153
  imul rcx, rdi
  shr rcx, 39
  imul eax, r10d
  imul rax, rdi
  shr rax, 39
  imul esi, r9d
  imul rsi, rdi
  shr rsi, 39
  imul edx, r8d
  imul rdx, rdi
  shr rdx, 39
  shl edx, 8
  movzx esi, sil
  or esi, edx
  shl eax, 8
  movzx ecx, cl
  or ecx, eax
  pxor xmm0, xmm0
  pinsrw xmm0, ecx, 0
  pinsrw xmm0, esi, 1
  ret
Hier von Hand aufgerufene Intrinsics in Visual C++:
Code: Ansicht erweitern :: Alles auswählen
  movaps   xmm3, xmm0
  xorps    xmm2, xmm2
  movaps   xmm4, xmm1
  punpcklbw xmm3, xmm2
  punpcklbw xmm4, xmm2
  pmullw   xmm4, xmm3
  pmulhuw xmm4, XMMWORD PTR __xmm@80818081808180818081808180818081
  psrlw    xmm4, 7
  packuswb xmm4, xmm4
  movaps   xmm0, xmm4
  ret      0
Die Division durch 255 muss man von Hand in Multiplikation + Shift umwandeln, weil das kein Compiler außer GCC mit Vektoren kann.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6026
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [C++] Mikrooptimierungs-Log

Beitragvon Krishty » 10.08.2017, 15:50

Ich habe endlich einen großen Vorteil von Clangs Syntax gefunden: Shuffling mit undefinierten Elementen.

Liegt meine RGBA-Farbe in einem 16-Byte-SSE-Register, sind die zwölf oberen Spuren unbenutzt. Sagen wir, ich möchte die Alpha-Komponente in den unteren vier Spuren haben, und die oberen zwölf interessieren mich nicht.

Schreibe ich return { rgba[3], rgba[3], rgba[3], rgba[3] }, muss der Compiler garantieren, dass die oberen zwölf Spuren genullt sind. So fordert das C++. Dem Compiler ist nicht vermittelbar, dass sie unbenutzt sind. Das Nullen bedeutet zusätzlichen Aufwand.

Schreibe ich return { rgba[3], rgba[3], rgba[3], rgba[3], rgba[3], rgba[3], rgba[3], rgba[3], rgba[3], rgba[3], rgba[3], rgba[3], rgba[3], rgba[3], rgba[3], rgba[3] }, entfällt das Nullen. Der Compiler verbaut aber immernoch zu viele Befehle, um die dritte Spur nach ganz oben zu schieben.

Clang glänzt mit return { __builtin_shufflevector(rgba, rgba, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }. Das -1 bedeutet, dass die entsprechende Spur undefiniert ist und der Compiler frei Befehle auswählen kann, so lange die unteren vier Spuren korrekt befüllt werden.

Das ist die erste Situation, in der ein Compiler meine selbstgeschriebene Intrinsic-Version deutlich abhängt. Was Clang hier teilweise über recht abwegige Befehle rausholen kann, ist beachtlich.

__builtin_shufflevector() ist auf GCC nicht verfügbar und AFAIK gibt es auch kein entsprechendes Pendant. Visual C++ kann sowieso nichts anderes als Intrinsics. Ich empfehle also, bei sowas immer erst eine Clang-Version mit __builtin_shufflevector() und undefinierten Elementen zu machen, und dann das resultierende Disassembly auf Intrinsics in GCC und Visual C++ zu übertragen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6026
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [C++] Mikrooptimierungs-Log

Beitragvon Krishty » 10.08.2017, 16:20

Ich weiß nicht, was in den Compilern vorgeht. Zur Hölle, ich verstehe nicht, wie sowas passieren kann.

  void store(UInt1B memory[4], UINT1BX4 vector) {
    memory[0] = vector[0];
    memory[1] = vector[1];
    memory[2] = vector[2];
    memory[3] = vector[3];
  }


Das sollte ein einziges MOVD oder MOVSS sein – die unteren 4 B in einem Rutsch in den Speicher schreiben. Stattdessen Clang:
Code: Ansicht erweitern :: Alles auswählen
  movaps xmmword ptr [rsp - 24], xmm0
  mov sil, byte ptr [rsp - 21]
  mov cl, byte ptr [rsp - 22]
  mov dl, byte ptr [rsp - 23]
  mov al, byte ptr [rsp - 24]
  mov byte ptr [rdi], al
  mov byte ptr [rdi + 1], dl
  mov byte ptr [rdi + 2], cl
  mov byte ptr [rdi + 3], sil
  ret

Visual C++:
Code: Ansicht erweitern :: Alles auswählen
        movd     eax, xmm1
        movdqa   xmm0, xmm1
        psrldq   xmm0, 1
        mov      BYTE PTR [rcx], al
        movd     eax, xmm0
        movdqa   xmm0, xmm1
        psrldq   xmm0, 2
        psrldq   xmm1, 3
        mov      BYTE PTR [rcx+1], al
        movd     eax, xmm0
        mov      BYTE PTR [rcx+2], al
        movd     eax, xmm1
        mov      BYTE PTR [rcx+3], al
        ret      0

GCC (WTF):
Code: Ansicht erweitern :: Alles auswählen
  movaps XMMWORD PTR [rsp-72], xmm0
  movzx eax, BYTE PTR [rsp-72]
  movaps XMMWORD PTR [rsp-40], xmm0
  movaps XMMWORD PTR [rsp-56], xmm0
  mov BYTE PTR [rdi], al
  movzx eax, BYTE PTR [rsp-39]
  mov BYTE PTR [rdi+1], al
  movzx eax, BYTE PTR [rsp-54]
  mov BYTE PTR [rdi+2], al
  movzx eax, BYTE PTR [rsp-69]
  mov BYTE PTR [rdi+3], al
  ret


… nun muss ich wieder einen zehn-Zeilen-Aufsatz schreiben:

  void store(UInt1B memory[4], UInt1Bx4 const v) {
    // • try to store four lanes at once via SSE2’s MOVD
    // • this works only when treating the four lowest lanes as a single 4-B integer

  # if COMPILED_BY_VISUAL_CPP

      // • the “_mm_cvtsi128_si32()” intrinsic casts the four lowest lanes to a 4-B integer
      *reinterpret_cast<int *>(memory) = _mm_cvtsi128_si32(v);

  # elif COMPILED_BY_CLANG || COMPILED_BY_GCC

      // • “reinterpret_cast” does not violate strict aliasing here because 1-B types may alias anything
      // • GCC’s/Clang’s code generation miserably fails anything else
      *reinterpret_cast<UInt4B *>(memory) = ((UINT4BX4)v)[0];

  # endif
  }

… und was mache ich mit Strict Aliasing und 16-Bit-Zahlen? Zu Bjarne Stroustrup beten und ihm zum Opfer meinen Computer verbrennen?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6026
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [C++] Mikrooptimierungs-Log

Beitragvon Spiele Programmierer » 10.08.2017, 22:48

Das ist wirklich schrecklich.

und was mache ich mit Strict Aliasing und 16-Bit-Zahlen? Zu Bjarne Stroustrup beten und ihm zum Opfer meinen Computer verbrennen?

Strict Aliasing ist immer eine sehr komplizierte Angelegenheit.
Aber ich bin mir ziemlich sicher, dass dieser Code auch jetzt Strict Aliasing verletzt. Man darf zwar jeden Pointer in unsigned char* casten und damit zugreifen, aber man darf nicht in die andere Richtung jeden unsigned char* in einen beliebigen Typ casten und zugreifen. Der Pointer muss ursprünglich mit diesem Typ konstruiert/zugewiesen worden sein. Aus praktischer Sicht kann der Compiler nicht garantieren das der ursprüngliche char-Pointer das notwendige Alignment für einen anderen Typen hat. Außerdem könnte man sonst Strict Aliasing immer umgehen in dem man einfach einen Umweg über unsigned char* macht und die ganze Regel wäre zwecklos: reinterpret<T*>(reinterpret<unsigned char*>(...))

Die jeweiligen Standards sind da wohl nicht unbedingt ganz eindeutig zu interpretieren, aber der Konsens ist wohl, dass memcpy solche Probleme vermeidet: https://stackoverflow.com/questions/3275353/c-aliasing-rules-and-memcpy

Also das sollte gehen:
Code: Ansicht erweitern :: Alles auswählen


void store2(UInt1B memory[4], UINT1BX4 vector)
{
#if COMPILED_BY_VISUAL_CPP
*reinterpret_cast<int *>(memory) = _mm_cvtsi128_si32(v);
#else
memcpy(memory, &vector, 4); // Catastrophic code generation with Microsoft
#endif
}

GCC und Clang erzeugen da perfekten Code.
Zuletzt geändert von Spiele Programmierer am 11.08.2017, 00:17, insgesamt 1-mal geändert.
Spiele Programmierer
Establishment
 
Beiträge: 341
Registriert: 23.01.2013, 16:55

Re: [C++] Mikrooptimierungs-Log

Beitragvon Krishty » 10.08.2017, 23:02

Ich vergaß zu schreiben: Was Strict Aliasing angeht, machen es die Intrinsic-Implementierungen in Clang & GCC intern beim Laden so:

  struct MOVD {
    int i32;
  } __attribute__((__packed__, __may_alias__));
  return (UINT1BX4)(intx4){ ((MOVD const *)memory)->i32, 0, 0, 0 };


… und beim Speichern umgekehrt.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6026
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [C++] Mikrooptimierungs-Log

Beitragvon Krishty » 10.08.2017, 23:13

Spiele Programmierer hat geschrieben:Das ist wirklich schrecklich.

Aber ich bin mir ziemlich sicher, dass dieser Code auch jetzt Strict Aliasing verletzt. Man darf zwar jeden Pointer in unsigned char* casten und damit zugreifen, aber man darf nicht in die andere Richtung jeden unsigned char* in einen beliebigen Typ casten und zugreifen. Der Pointer muss ursprünglich mit diesem Typ konstruiert/zugewiesen worden sein. Aus praktischer Sicht kann der Compiler nicht garantieren das der ursprüngliche char-Pointer das notwendige Alignment für einen anderen Typen hat. Außerdem könnte man sonst Strict Aliasing immer umgehen in dem man einfach einen Umweg über unsigned char* macht und die ganze Regel wäre zwecklos: reinterpret<T*>(reinterpret<unsigned char*>(...))
Das ist schon klar; in diesem Fall lade ich aber tatsächlich vier unsigned chars in einen Vektor von 16×unsigned chars, indem ich ihn kurz int uminterpretiere. Ich hätte gedacht, dass das legal ist; und schnellem Googeln nach ist es wirklich kompliziert – wahrscheinlich noch mehr, als den Compiler dazu zu bekommen, ordentlichen Code zu generieren :D

Danke für den memcpy()-Tipp; das probiere ich tatsächlich mal umzusetzen. Ich bin gespannt, wie gut/schlecht es z.B. mit oberen Hälften von Registern funktionieren wird.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6026
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [C++] Mikrooptimierungs-Log

Beitragvon Krishty » 10.08.2017, 23:32

Krishty hat geschrieben:Danke für den memcpy()-Tipp; das probiere ich tatsächlich mal umzusetzen. Ich bin gespannt, wie gut/schlecht es z.B. mit oberen Hälften von Registern funktionieren wird.

Ach, das wäre auch zu schön gewesen. Perfekter Code mit GCC, aber Clang sagt error: address of vector element requested. Für komplette Vektoren ist das Jackpot, aber für z.B. die obere Hälfte der Elemente muss ich weiter über struct __attribluärgh gehen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6026
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [C++] Mikrooptimierungs-Log

Beitragvon Spiele Programmierer » 11.08.2017, 00:16

Hm, also vielleicht verstehe ich dich falsch, aber auf Godbolt scheint es zu gehen:
Click
Spiele Programmierer
Establishment
 
Beiträge: 341
Registriert: 23.01.2013, 16:55

Re: [C++] Mikrooptimierungs-Log

Beitragvon Krishty » 11.08.2017, 00:39

Argh, ich hatte &vector[12] ausprobiert! Danke :)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6026
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [C++] Mikrooptimierungs-Log

Beitragvon Krishty » 11.08.2017, 01:50

Spiele,

schau dir bitte mal das hier an:

https://godbolt.org/g/azjxkX

Änder das #if 1 zu #if 0 und prüf, was rauskommt. Vielleicht ist es aber auch bloß spät und ich sehe den Wald vor lauter Bäumen nicht.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6026
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [C++] Mikrooptimierungs-Log

Beitragvon dot » 11.08.2017, 15:48

Krishty hat geschrieben:Änder das #if 1 zu #if 0 und prüf, was rauskommt. Vielleicht ist es aber auch bloß spät und ich sehe den Wald vor lauter Bäumen nicht.

Das ist wohl einfach Undefined Behavior; ich nehme an du hast dich da von der Operator Precedence beißen lassen!? ;)

&result[8] ist das selbe wie &(result[8]) und gibt die Adresse des achten Elements des result vectors. &result dagegen ist die Adresse des ganzen vectors. (&result) + 8 ist dann nicht die Adresse des achten Elements von results sondern die Adresse des Vektors + 8 * sizeof(result) und das liegt definitiv außerhalb des Buffers -> UB...
Benutzeravatar
dot
Michael Kenzel
Establishment
 
Beiträge: 1587
Registriert: 06.03.2004, 19:10

Re: [C++] Mikrooptimierungs-Log

Beitragvon Krishty » 11.08.2017, 17:18

DAS war der Wald. Ich hatte die ganze Zeit mit Schritten in sizeof result[0] gerechnet statt in sizeof result; danke :)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6026
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [C++] Mikrooptimierungs-Log

Beitragvon Artificial Mind » 26.08.2017, 10:47

Keine Ahnung ob wir sowas hier schon hatte, aber ich finde es passt hervorragend:

Hochoptimierte Linear-Search vs. Binary-Search

Beinhaltet ASM-level analyse und Späße wie branchless binary search.
Benutzeravatar
Artificial Mind
Establishment
 
Beiträge: 802
Registriert: 17.12.2007, 18:51
Wohnort: Aachen

VorherigeNächste

Zurück zu Artikel, Tutorials und Materialien

Wer ist online?

Mitglieder in diesem Forum: Yahoo [Bot] und 3 Gäste