Sammelthread zu Visual C++’ Compiler

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

… bevor ich den Jammer-Thread vollends flute, sammle ich meine Beschwerden und Entdeckungen hier.

Also … Update von Visual Studio 15.5.5 auf 15.6. Einige Programme werden größer.

Ursache scheinen zwei Änderungen in der CRT zu sein:
  1. Eine der Standardfunktionen nutzt nun Exception Handling (ich befürchte, eine von sin() cos() tan() exp() pow()). Also landet nun Exception Handling in meiner EXE.
    Ich sehe folgende neue Symbole in meinen Modulen:
    • 192 B: __acrt_exception_action_table (exception_filter.obj)
    • 132 B: __DestructExceptionObject (ehhelpers.obj)
    • 64 B: _CallSettingFrame (handlers.obj)
    • 24 B: __DestructExceptionObject$filt$0 (ehhelpers.obj)
  2. Die CRT bringt eine Funktion mit, um die Dekoration von Funktionsnamen zu entfernen (UnDecorator). Diese Funktion wurde umgeschrieben, so dass sie nun strncmp() nutzt (geraten – könnte auch das Exception Handling sein). Gelöscht:
    • 8 B: UnDecorator::outputString (undname.obj)
    • 4 B: UnDecorator::maxStringLength (undname.obj)
    Neu hinzugefügt:
    • 125 B: strncmp (strncmp.obj)
    • 4 B: UnDecorator::m_CHPENameOffset (undname.obj)
    • 4 B: UnDecorator::m_recursionLevel (undname.obj)
  3. Irgendwo wird eine Lookup-Tabelle __newctype benutzt (768 B).
    Dummerweise finde ich die betreffende Datei ctype.c nicht in dem CRT-Quelltext, darum weiß ich nicht mehr drüber.
… das kostet um die 500 B zusätzlichen Code und rund 1000 B zusätzliche Daten.

Das mit den Exceptions wäre vermeidbar gewesen, da bin ich mir sicher.

Weiter mit der Code Generation:
  1. optimize for speed: return ~0; erzeugt nun statt OR EAX, -1 (drei Bytes) MOV EAX, -1 (fünf Bytes).
  2. optimize for speed: Sprünge erzwingen nun häufiger glatte Adressen (viel mehr Padding).

    15.5 (Schleifenanfang sieben Bytes vom Funktionsanfang):
      49 FF C1                    INC R9

    15.6 (selbe Situation):
      66 0F 1F 84 00 00 00 00 00  NOP WORD PTR[RAX+RAX]
      49 FF C1                    INC R9
  3. optimize for size: Mehrfache _mm_setzero_ps() werden nun zusammengefasst. Wenn in 15.5 zwei Funktionen einen Vektor via _mm_setzero_ps() genullt haben, landeten sehr oft auch zwei XORPS im Code. Ab 15.6 werden sie öfter zusammengefasst.

    Das ist schwer zu entscheiden – meist möchte man tatsächlich doppelt nullen, um die Parallelität zu erhöhen. Wenn aber z.B. die Abhängigkeitsketten gleich lang sind, ist es sinnlos, zwei Register zu nullen. Ich vermute, dass sie was in diese Richtung verbessert haben.

    Die Optimierung greift durchaus an 10, 20 Stellen in meinen Programmen und spart dort jeweils ein paar Bytes. Der Gewinn kommt eher nicht durch weniger XORPS-Befehle, sondern durch reduzierten Registerdruck (weniger Spilling auf den Stack).

    Gut möglich, dass diese Optimierung auch bei Geschwindigkeitsoptimierung greift – dort wird sie aber wohl durch die anderen Änderungen verdrängt.

    Ich messe hier zum ersten Mal, dass meine Programme durch ein Release minimal kleiner geworden sind. Schön. Aber eben nur, sofern man nicht die statische CRT linkt und von dem Kilobyte neuem Bloat getroffen wurde :(
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Ich habe wieder einen Bug gemeldet: https://developercommunity.visualstudio ... s-mix.html

Visual C++ verwechselt Funktionsparameter in Code, der viel SSE einsetzt. Ich hatte den Bug Report Monate vor mir hergeschoben weil ich wusste, dass es PITA sein würde, ihn zu reproduzieren – und tatsächlich hat’s mich vier Stunden gekostet. Falls sie ihn anerkennen, wird es wohl um die sechs Monate dauern, bis ein Fix ausgerollt ist. Sonst komme ich persönlich vorbei und erinnere sie dran.

Fun fact: Erfordert das Schreiben durch einen Zeiger innerhalb eines if in einer __vectorcall-Funktion mit einer bestimmten Anzahl Parametern und einer bestimmten Anzahl lokaler Zwischenergebnisse. Dann ist aber eben nicht der geschriebene Wert kaputt, sondern ein ganz anderer.

Wie man darauf kommt? Indem man Vertex Shader Constants aktualisiert, und irgendwie die Farbe der Objekte nicht so ganz richtig ist.

Repro:

Code: Alles auswählen

// compile with /LTCG /O1 (favor size, not speed)


#include <emmintrin.h>
#include <stdio.h>



// REQUIRED: must use struct -- bug does not show using __m128 directly
// (may be related to 140160 "_vectorcall calling convention via struct accesses wrong xmm register")
struct floatx4 {
	__m128 f;
};
struct floatx12 {
	floatx4 c0, c1, c2;
};

floatx4 __vectorcall zero() {
	return { _mm_setzero_ps() };
}
floatx4 __vectorcall operator +(floatx4 a, floatx4 b) {
	return { _mm_add_ps(a.f, b.f) };
}


floatx12 __vectorcall someMath(
	floatx4   v,
	floatx12  m
) {
	return {
		m.c0,
		m.c1,
		v + m.c2 // REQUIRED
	};
}



struct SIDE_EFFECT {
	floatx4  global_0;
	floatx4  global_1;
};

SIDE_EFFECT global_side_effect = { };


// REQUIRED: must be __vectorcall
// REQUIRED: inlining hides the bug
void __declspec(noinline) __vectorcall inner(
	floatx4   param_0_should_be_zero,
	floatx12  param_1,
	floatx12  param_2_unused_but_required,
	floatx4   param_3
) {
	// this should print 0 0 0 0 but instead it prints param_3
	printf("should be zero: %f %f %f %f\n", param_0_should_be_zero.f.m128_f32[0], param_0_should_be_zero.f.m128_f32[1], param_0_should_be_zero.f.m128_f32[2], param_0_should_be_zero.f.m128_f32[3]);
	// REQUIRED: bug does not show if printing param_3

	// REQUIRED: must use a pointer; accessing the structure directly hides the bug
	auto const side_effect_ptr = &global_side_effect;
	// REQUIRED: must branch; removing the if hides the bug
	if(nullptr != side_effect_ptr) {

		// REQUIRED: writing param_3 + param_1.c2 hides the bug although it should be equivalent
		// ARBITRARY: can also use param_2 instead
		// ARBITRARY: can flip order of operands
		side_effect_ptr->global_0 = someMath(param_3, param_1).c2;
		side_effect_ptr->global_1 = param_3;

	}
}

void outer( // inlining and __vectorcall here have no effect on the bug
	floatx4   param_0_is_zero,
	floatx12  param_1
) {
	inner(
		param_0_is_zero,
		param_1,
		param_1,
		param_1.c0 + param_1.c1 // REQUIRED: arbitrary operands, but *some* computation must take place
	);
}

int main() {

	// Arbitrary vectors, but NOT zero!
	floatx12 arbitrary = {
		{ { 1, 2, 3, 4 } },
		{ { 1, 2, 3, 4 } },
		{ { 1, 2, 3, 4 } }
	};

	outer(zero(), arbitrary);

	getchar();
}
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4831
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Schrompf »

Wow. Sehr cool, dass Du Dir die Zeit genommen hast. Hoffentlich nehmen die sich auch die Zeit.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Danke! Im Fall des nächsten Bugs kam ich kaum drumherum: Unsere Software auf der Arbeit funktionierte perfekt, als sie mit Visual Studio 2015 kompiliert wurde. Aber mit 2017 produziert sie nur Müll, und damit war das Update für uns erstmal erledigt.

Ich habe heute endlich binär die CPP-Dateien auf die Ursache durchsucht, indem ich immer für Gruppen von CPPs die Optimierung abgeschaltet habe. Als ich es auf eine CPP eingegrenzt hatte, bin ich die Funktionen mit #pragma optimize("", off) durchgegangen.

Ergebnis: https://developercommunity.visualstudio ... n-val.html

Dieser Bug ist deutlich stabiler als der letzte. Ich denke nicht, dass sie verwandt sind, weil andere Vorbedingungen gelten (erfordert kein struct).

Wie immer: Upvote, falls ihr mir helfen wollt.

Übrigens: Damit ist ein Drittel der Code Generation Bugs mit SSE (sechs an der Zahl) von mir gemeldet worden. Das lässt zwei Folgerungen zu:
  • Niemand außer mir setzt __vectorcall ein.
  • Entweder nutzt niemand DirectXMath, oder es stellt niedrigere Anforderungen an den Optimizer.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Oh Gott, Loads & Stores zusammenfassen.

Ich möchte drei benachbarte Bytes r, g, b in ein int laden. Ganz alltäglich. Der Einfachheit halber pfeifen wir auf Endianness.

Naiv:

  int bgr = r | (g << 8) | (b << 16);

Katastrophal naive Befehlsfolge:

  movzx  eax,byte ptr [rdx+1]
  movzx  ecx,byte ptr [rdx+2]
  shl    ecx,8
  or     ecx,eax
  movzx  eax,byte ptr [rdx]
  shl    ecx,8
  or     ecx,eax


… also Schuss in den Ofen, wie immer. Erzwingen wir einen 16-b-Load:

  int bgr = *reinterpret_cast<short *>(&r) | (b << 16);

Perfekte Befehlsfolge:

  movzx  eax,word ptr [rdx]
  movzx  ecx,byte ptr [rdx+2]
  shl    ecx,10h
  or     ecx,eax


… dummerweise nicht portabel, da GCC bei reinterpret_cast in einen Aliasing-Schreikrampf verfällt. (Oder doch nicht, weil char immer aliasen darf?!) Die portable Lösung ist memcpy():

  short gr;
  memcpy(&gr, &r, 2);
  int bgr = gr | (b << 16);


Versteht zwar niemand mehr, aber immernoch perfekte Befehlsfolge! :)

Hey, wenn Visual C++ memcpy() so gut optimiert … warum dann nicht direkt alle drei Bytes optimieren lassen?!

  int bgr = 0;
  memcpy(&bgr, &r, 3);


… ganz einfach: Weil Visual C++ dann alles auf den Stack spillt, obwohl es optimierte 16+8-Loads durchführt.

  movzx  eax,word ptr [rdx]
  and    dword ptr [rsp+40h],0
  mov    word ptr [rsp+40h],ax
  mov    al,byte ptr [rdx+2]
  mov    byte ptr [rsp+42h],al
  mov    eax,dword ptr [rsp+40h]


Sechs Speicherzugriffe für drei Bytes – sportlich!

… jetzt wisst ihr bescheid, falls ihr das mal braucht.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Alle memmove()-Aufrufe durch memcpy() ersetzt – deutlich größeres Programm.

Visual C++ kann z.B. nicht erkennen, dass memmove() aus einem globalen Array in eine lokale Variable nicht aliasen kann und dadurch memcpy() gleicht. Schreibt man dann von Hand memcpy() hin, greift plötzlich der Optimizer und ersetzt den Funktionsaufruf durch mov-Befehle entsprechender Größen.

Torvalds-mäßig einfach überall memmove() zu nutzen und sich darauf zu verlassen, dass es der Compiler schon richten wird, klappt also nicht.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Visual C++ 2015 hatte einen schlimmen constexpr-Array-Bug. Es schien sowas zu sein wie „wenn das constexpr-Array Zeiger auf andere constexpr-Arrays enthält, wird das Alignment abgefuckt“ und sorgte dafür, dass in entsprechenden Arrays Müll landete.

Ich finde gerade keinen Bug Report, aber in 2017.6 ist es behoben. Falls ihr auf 2015 festsitzt, testet die Stellen mit constexpr-Arrays also besonders gut.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Krishty hat geschrieben:Update von Visual Studio 15.5.5 auf 15.6.

[…]

optimize for speed: return ~0; erzeugt nun statt OR EAX, -1 (drei Bytes) MOV EAX, -1 (fünf Bytes).
Ich habe einen starken Verdacht, was für diese Veränderung ausschlaggebend war: Artificial Mind hatte doch letztes Jahr einen Artikel über Branchless Binary Search verlinkt. In dem war die Binärsuche mit GCC mehr als doppelt so schnell wie mit Visual C++. Die Ursache war:
The highlighted instruction “or r9, -1” on 4-th line is a cunning way of putting -1 into register: it takes only 4 bytes of machine code, while the obvious “mov r9, -1” takes 7 bytes of machine code. It is very similar to the “xor eax, eax” hack for zeroing a register, which every CPU understands today and handles during register renaming. Unfortunately, there is no special handling of instruction “or r9, -1” in Broadwell or other x86 architectures, so false dependency is created: CPU assumes that the new value of r9 register depends on its previous value, which is not set before that in the function. […] This explains why MSVC version is so much slower than that of GCC.
… und sie haben sich tatsächlich drum gekümmert!

Ich werde mal einen Kommentar schreiben, dass er die Tests wiederholen soll.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Ich dekoriere gerade viel mit __declspec(noalias) – eigentlich eher zufällig, weil ich ein paar Clang/GCC-Warnungen wegkriegen möchte. (Dort entspricht es __attribute__((const)).

__declspec(noalias) hat anscheinend keine Wirkung für Funktionen, deren Quelltext vorliegt. Dafür zeigt es tatsächlich Wirkung mit externen Funktionen: Vor und nach dem Funktionsaufruf werden weniger Daten gespeichert und neu geladen. (Visual C++ müsste sonst annehmen, dass der externe Aufruf alle globalen Daten modifiziert und alles neu laden.)

Ich bin noch nicht ganz sicher, ob ich __declspec(noalias) auf sowas wie GetSysColor() oder GetClientRect() anwenden darf. Nach Microsofts Dokumentation:
noalias means that a function call does not modify or reference visible global state […].
[…] The visible global state is the set of all data that is not defined or referenced outside of the compilation scope, and their address is not taken. The compilation scope is all source files (/LTCG (Link-time Code Generation) builds) or a single source file (non-/LTCG build).
Das „modify“ trifft auf WinAPI-Aufrufe nicht zu, das „reference“ schon. Allerdings ist der referenzierte Speicher nicht Teil meines Programms und ändert sich nur über WinAPI-Aufrufe, die nicht noalias definiert sind.
noalias means that a function call […] only modifies the memory pointed to directly by pointer parameters (first-level indirections).
If a function is annotated as noalias, the optimizer can assume that, in addition to the parameters themselves, only first-level indirections of pointer parameters are referenced or modified inside the function.
Das trifft auf WinAPI-Aufrufe nicht zu, da sie z.B. interne Datenstrukturen und globale Variablen abfragen. Die sind aber nicht Teil des „Compilation Scope“ oben und die Dokumentation lässt offen, ob das nur für selbiges gilt.

Ich baue es jetzt erstmal für WinAPI & Co. ein, messe die Verbesserung, und prüfe, ob was kaputtgeht.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Der erste Code Generation Bug ist behoben: https://developercommunity.visualstudio ... s-mix.html

Ich schätze, dass der Fix im Herbst ausgeliefert werden wird.

————

__m128 anzeigen ist wohl nicht wichtig genug ¯\_(ツ)_/¯

https://developercommunity.visualstudio ... meter.html

————
Krishty hat geschrieben:
This explains why MSVC version is so much slower than that of GCC.
… und sie haben sich tatsächlich drum gekümmert!
Ich werde mal einen Kommentar schreiben, dass er die Tests wiederholen soll.
Der Autor hat mir bestätigt, dass der Hinweis von ihm kam: https://developercommunity.visualstudio ... -whic.html

Vielleicht sollte ich zu meinem Debugger-Bug schlicht schreiben, dass GDB __m128 doppelt so gut anzeigen kann wie Visual Studio?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von dot »

Ich hab auch mal wieder was: Da freut man sich so auf guaranteed copy elision und wenn man es dann endlich verwenden will, dann passiert sowas: https://developercommunity.visualstudio ... -user.html :(
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Ich liebe es, wie subtil du sie darauf hinweist, dass ihre Werbung Bullshit ist :)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von dot »

:mrgreen:
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von dot »

Das ging ja wieder mal fix :D

Sieht aus, dass es sich offenbar wirklich auszahlt den Fehler ordentlich zu isolieren. Der andere, der vermutlich den selben Bug schon vor einem Monat reported hat, ist immer noch "Under Investigation"...
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Krishty hat geschrieben:Der erste Code Generation Bug ist behoben: https://developercommunity.visualstudio ... s-mix.html

Ich schätze, dass der Fix im Herbst ausgeliefert werden wird.
Wow – der Fix ist seit gestern im Visual Studio Preview. Hut ab, das ist wirklich viel schneller als ich erwartet habe.

Mein zweiter Code Generation Bug ist auch markiert als Fixed – pending release, da rechne ich aber dann wirklich mit Release im Herbst.

Andererseits passiert auch immer wieder sowas wie dem armen Eric Lengyel: https://developercommunity.visualstudio ... n-bug.html
Bug gemeldet; sein Beispiel-Code wird gefixt, aber an anderer Stelle taucht er noch immer auf. (Wie mein CV-Funktions-Bug.)

Jetzt heult er auf Twitter statt ZFX’ Jammer-Thread vollzuspammen wie ein richtiger Mann.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Visual Studio 2017.7.1 ist raus, und damit auch eine Aktualisierung der Compiler-Toolchain.



Nur x86-32: Alle Epiloge sind kleiner

Die Rückkehr aus einer Funktion hat Visual C++ früher mit

  mov esp, ebp
  pop ebp
  ret


realisiert (Stack wiederherstellen und beenden). Nun wird

  leave
  ret


benutzt. Selbe Wirkung, aber zwei Bytes weniger. Ich messe damit 0,5 % kürzeren Code.



Heuristik für Anordnung der Ausführungsblöcke geändert

Compiler gliedern Funktionen in unteilbare Blöcke, die immer geschlossen ausgeführt werden (ohne Unterbrechnung durch if oder else). Im Kompilat landen sie dann in anderer Reihenfolge als im Quelltext. Das erlaubt, gemeinsame Befehle zusammenzufassen oder lokale Variablen zu teilen, sogar wenn man in logisch unzusammenhängenden Code-Teilen ist.

Die Heuristik dafür wurde in 2017.7 geändert. Ich kann nicht genau sagen, was anders ist, aber der Code ist nun insgesamt kürzer obwohl mehr Register genutzt werden.



memmove() ist nun Intrinsic

Bis Visual Studio 2017.6 waren memcpy() und memset() intrinsic, aber memmove() nicht. Nun schon. Unter x64 wird es nun minimal weniger geinlinet. Davon ab hat es aber nur syntaktische Auswirkungen, falls ihr es selber schreibt.



Nur x86-32, nur Optimierung auf Größe: Anderes Alignment für Read-Only Data Nicht-referenzierte Daten werden nicht mehr richtig gelöscht

Irgendwas wurde am Alignment des Read-only Data-Abschnitts (.data) geändert. Der Abschnitt ist nun deutlich größer als vorher. Das wiegt alle anderen Größengewinne doppelt wieder auf, und unter’m Strich steht man schlechter dar als mit 2017.6. Nachdem ich geprüft habe, dass nicht versehentlich ein neues fettes Symbol reingerutscht ist, hab ich’s nicht weiter analysiert. Nachtrag: Nun konnte ich’s doch nicht lassen, und das Bild ist deutlicher geworden:
  • ein Testprogramm ist logisch 40 B größer geworden und physisch 64
  • es enthält genau vier Strings mehr als vorher, in den Größen 11/11/10/8 B
  • diese Strings werden ausschließlich in solchen Abfragen verwendet: if(0 == memcmp(text, "string!", 8))
  • in allen betroffenen Abfragen ruft der Compiler nicht wirklich memcmp() auf, sondern führt zwei 32-Bit-Vergleiche durch (plus, wo nötig, einen 16-Bit- und 8-Bit-Vergleich)
  • er vergleicht aber nicht mit dem globalen String "string!", sondern zerlegt ihn in zwei 32-Bit-Immediates (plus, wo nötig, 16-Bit- und 8-Bit-Intermediate) (schnellerer & kompakterer Code)
  • die String-Literale werden also nicht mehr benötigt und sollten wegoptimiert werden
  • … und bis gestern hat das auch wunderbar geklappt – aber jetzt landen die Strings vereinzelt als Leichen in der EXE
  • das reproduziert nicht sauber (habe hier vier Leichen auf ca. 30 optimierte String-Vergleiche) … wird ein schöner Repro am Wochenende!
Optimierung auf Geschwindigkeit ist nicht betroffen. x86-64 auch nicht. /Os (auf Größe optimieren) wird mit jedem Compiler-Update schlechter. Es sieht aus, als würde das Team einfach keine Regressionstests dafür nutzen.



x86-32: Irgendein Absturz ist reingerutscht

Mein Flugsimulator kompiliert nicht mehr: An internal error has occurred in the compiler. Das wird mich nun erstmal beschäftigen.
lol, alle temporären Dateien UND die Ausgaben früherer Builds löschen – geht wieder. Ich bin einfach verflucht.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Ich habe einen neuen Schalter entdeckt: /kernel. Hauptsächliche Wirkung: Keine Exceptions, keine Run-time Type Information, kein new oder delete. Also alles, was ich bisher über andere Schalter erzwingen musste.

… und da endet es dann auch. Zum einen ist SSE verboten, und da wird es unpraktisch. Zum anderen ist der einzige Unterschied in der Code-Erzeugung, den ich feststellen konnte, vorsichtigeres Inlining.

… aber schön, wenn man einen Treiber programmiert und sicher gehen möchte, dass nicht versehentlich Exceptions drin gelandet sind.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
NytroX
Establishment
Beiträge: 358
Registriert: 03.10.2003, 12:47

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von NytroX »

Vielleicht hab ich falsch geschaut, aber ich dachte SSE+SSE2 sind nur bei x86 nicht möglich.
Unter x64 sollte es doch gehen (SSE und SSE2, aber kein AVX)?

Ich hätte jetzt einfach vermutet, dass das daran liegt, dass es keine garantierte Prüfung vorher gibt (je nachdem, an welcher Stelle man im Kernel rummacht).
Und jeder x64 Prozessor unterstützt auch SSE und SSE2; x86 Prozessoren aber nicht unbedingt.

[rant]
Aber wer nutzt schon noch x86? Ich bin ja dafür, dass man den alten Quatsch mal los wird. :mrgreen:
Selbst mein Handy und sogar der PI in meiner Heizung laufen unter 64bit... :lol:
[/rant]
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Stimmt schon; unter x86-64 ist SSE auch im Kernel erlaubt. Gehört dort zur Spezifikation.
Ich hätte jetzt einfach vermutet, dass das daran liegt, dass es keine garantierte Prüfung vorher gibt (je nachdem, an welcher Stelle man im Kernel rummacht).
Jein. Windows hat Mindestanforderungen an SSE, die vor der Installation überprüft werden. (Siehe Known Issue #3, wenn sie das vergessen: https://support.microsoft.com/en-us/hel ... -kb4088881) Man kann sich also 100 % sicher sein, dass man auf Windows 10 jederzeit SSE2 hat. Auf Vista ebenfalls. Auf XP und 7 nicht.

Jede Befehlserweiterung à SSE oder AVX muss immer auch vom Betriebssystem unterstützt werden. Das ist keine Willkür von Microsoft, sondern liegt daran, dass das Betriebssystem ja den Inhalt der zusätzlichen SSE- und AVX-Register speichern und wiederherstellen muss, wenn der Scheduler einen Context Switch durchführt oder eine Ausnahme ausgelöst wird – sonst bekommst du mitten in der Ausführung oder im Exception Handler plötzlich die Registerinhalte von einem anderen Thread/Prozess. Achtung Hörensagen: Ich hatte mal gehört, dass Context Switches im Kernel andere Datenstrukturen nutzen als im User Mode (allein schon, weil dort z.B. auch Debug-Register zur Verfügung stehen). Falls dort die SSE-Register nicht vorhanden sind (Performance?), wäre das eine Erklärung.

Randbemerkung: Darum bloß nicht via CPUID auf SSE testen, sondern via IsProcessorFeaturePresent(). Dass die CPU SSE unterstützt bringt dir absolut gar nichts, wenn alle 12 ms der Register-Inhalt weg ist. Das OS muss mitspielen.

NytroX hat geschrieben:[rant]Aber wer nutzt schon noch x86? Ich bin ja dafür, dass man den alten Quatsch mal los wird. :mrgreen:
Selbst mein Handy und sogar der PI in meiner Heizung laufen unter 64bit... :lol:[/rant]
Das dachte ich mir auch. Nach dem Release meines STL-Viewers hat es genau sechs Stunden gedauert, bis jemand nach einer 32-Bit-Version gefragt hat. Die Download-Zahlen bewegen sich etwa gleichauf mit der 64-Bit-Version.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von dot »

15.7 update...and here we go again: https://developercommunity.visualstudio ... t-pas.html :)

Das Lustige an diesem Bug: Passiert nur im nicht optimierten Build...
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von dot »

Krishty hat geschrieben:Achtung Hörensagen: Ich hatte mal gehört, dass Context Switches im Kernel andere Datenstrukturen nutzen als im User Mode (allein schon, weil dort z.B. auch Debug-Register zur Verfügung stehen). Falls dort die SSE-Register nicht vorhanden sind (Performance?), wäre das eine Erklärung.
Ja, Performance ist afaik der Grund dafür. Das Spielzeug OS in der Betriebssysteme Übung auf der Uni damals hat sogar komplett auf jeglichen Floating-Point-Support im Kernel-Mode verzichtet, um den Overhead von Context Switches im Kernel-Mode zu minimieren.
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

dot hat geschrieben:15.7 update...and here we go again: https://developercommunity.visualstudio ... t-pas.html :)

Das Lustige an diesem Bug: Passiert nur im nicht optimierten Build...
Upvoted. Lol!
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Mein Problem mit der Formatierung von String-Literalen in der IDE soll nun behoben sein und auf Freigabe warten.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Weil ich gerade wieder horrende Gewinne dabei habe, Funktionen __forceinline zu markieren, die nur einmal aufgerufen werden: Theoretisch wirbt Visual C++’ Optimizer mit single-call site inlining, aber praktisch funktioniert es nicht.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von dot »

Here goes another: https://developercommunity.visualstudio ... ariab.html ... :(

Wieder mal einer dieser Bugs wo die Umstände so spezifisch sind, dass man gar nicht wissen will, wie die Implementierung darunter aussehen muss, damit sowas zustande kommt...
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von dot »

lol, 18 h, ich denke, das ist neuer Rekord... :D
Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Schneller geschlossen als ich abstimmen konnte – wow. Das war höchstwahrscheinlich schon intern behoben.

Dummerweise müssen wir jetzt bestimmt ein halbes Jahr drauf warten, weil 2017.8 keine Verbesserungen an der Compiler-Toolchain mitbringt.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von dot »

Benutzeravatar
Krishty
Establishment
Beiträge: 8227
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Krishty »

Sehr schön; upvoted …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4831
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Sammelthread zu Visual C++’ Compiler

Beitrag von Schrompf »

Und auch schon wieder gefixt. Krishty muss für seine deutlich länger warten.... bringst Du dort regelmäßig Kuchen vorbei? :-)
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Antworten