Is it just me, or …
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
Habe die beiden nicht mehr installiert … probier es aus und poste hier :)
Re: Is it just me, or …
Würde ich gerne machen, aber wie weis ich nicht ;)
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
Code: Alles auswählen
// Compile with /Ox /Ob2, link with /LTCG
#include <iostream>
struct Vector {
float A, B, C, D;
Vector(float A, float B, float C, float D)
: A(A), B(B), C(C), D(D) { }
Vector operator + (Vector const & Summand) {
return Vector(A + Summand.A, B + Summand.B, C + Summand.C, D + Summand.D);
}
~Vector() { }
};
int main() {
float A, B, C, D;
::std::cin >> A >> B >> C >> D;
Vector const Result = Vector(A, B, C, D) + Vector(0.0f, 1.0f, 2.0f, 3.0f);
::std::cout << Result.A << Result.B << Result.C << Result.D;
return 0;
}Re: Is it just me, or …
Okay, also so wie Du beschrieben hast (alle Compiler- und Linkereinstellung so gemacht), Code kopiert.
Also:
1) VS2005: dort taucht ein "call Vector::operator+ (401000h) " auf.
Ich poste mal das ganzen Disassembly
1) VS2008: dort taucht ein "call Vector::operator+ (401000h) " auf.
Ich poste mal wieden das ganzen Disassembly
Und nun habe ich den leeren Destructor rausgeschmissen und es steht auch kein " call Vector::operator+" mehr.
Kommt mir auch kürzer vor :)
Also demnach existiert dieses Problem schon seit VS2005...
Also:
1) VS2005: dort taucht ein "call Vector::operator+ (401000h) " auf.
Ich poste mal das ganzen Disassembly
Code: Alles auswählen
int main() {
00401030 push ebp
00401031 mov ebp,esp
00401033 and esp,0FFFFFFF8h
00401036 sub esp,40h
float A, B, C, D;
::std::cin >> A >> B >> C >> D;
00401039 lea eax,[esp+0Ch]
0040103D push eax
0040103E lea ecx,[esp+0Ch]
00401042 push ecx
00401043 mov ecx,dword ptr [__imp_std::cin (402040h)]
00401049 lea edx,[esp+0Ch]
0040104D push edx
0040104E lea eax,[esp+0Ch]
00401052 push eax
00401053 call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (402044h)]
00401059 mov ecx,eax
0040105B call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (402044h)]
00401061 mov ecx,eax
00401063 call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (402044h)]
00401069 mov ecx,eax
0040106B call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (402044h)]
Vector const Result = Vector(A, B, C, D) + Vector(0.0f, 1.0f, 2.0f, 3.0f);
00401071 fldz
00401073 fstp dword ptr [esp+10h]
00401077 lea ecx,[esp+10h]
0040107B fld1
0040107D lea eax,[esp+30h]
00401081 fstp dword ptr [esp+14h]
00401085 lea edx,[esp+20h]
00401089 fld dword ptr [__real@40000000 (402118h)]
0040108F fstp dword ptr [esp+18h]
00401093 fld dword ptr [__real@40400000 (402114h)]
00401099 fstp dword ptr [esp+1Ch]
0040109D fld dword ptr [esp]
004010A0 fstp dword ptr [esp+20h]
004010A4 fld dword ptr [esp+4]
004010A8 fstp dword ptr [esp+24h]
004010AC fld dword ptr [esp+8]
004010B0 fstp dword ptr [esp+28h]
004010B4 fld dword ptr [esp+0Ch]
004010B8 fstp dword ptr [esp+2Ch]
004010BC call Vector::operator+ (401000h)
::std::cout << Result.A << Result.B << Result.C << Result.D;
004010C1 fld dword ptr [esp+3Ch]
004010C5 mov ecx,dword ptr [__imp_std::cout (40203Ch)]
004010CB sub esp,10h
004010CE fstp dword ptr [esp+0Ch]
004010D2 fld dword ptr [esp+48h]
004010D6 fstp dword ptr [esp+8]
004010DA fld dword ptr [esp+44h]
004010DE fstp dword ptr [esp+4]
004010E2 fld dword ptr [esp+40h]
004010E6 fstp dword ptr [esp]
004010E9 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)]
004010EF mov ecx,eax
004010F1 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)]
004010F7 mov ecx,eax
004010F9 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)]
004010FF mov ecx,eax
00401101 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)]
return 0;
00401107 xor eax,eax
}
Ich poste mal wieden das ganzen Disassembly
Code: Alles auswählen
int main() {
01131030 push ebp
01131031 mov ebp,esp
01131033 and esp,0FFFFFFF8h
01131036 sub esp,40h
float A, B, C, D;
::std::cin >> A >> B >> C >> D;
01131039 lea eax,[esp+0Ch]
0113103D push eax
0113103E lea ecx,[esp+0Ch]
01131042 push ecx
01131043 mov ecx,dword ptr [__imp_std::cin (1132040h)]
01131049 lea edx,[esp+0Ch]
0113104D push edx
0113104E lea eax,[esp+0Ch]
01131052 push eax
01131053 call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (1132038h)]
01131059 mov ecx,eax
0113105B call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (1132038h)]
01131061 mov ecx,eax
01131063 call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (1132038h)]
01131069 mov ecx,eax
0113106B call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (1132038h)]
Vector const Result = Vector(A, B, C, D) + Vector(0.0f, 1.0f, 2.0f, 3.0f);
01131071 fldz
01131073 fstp dword ptr [esp+10h]
01131077 lea ecx,[esp+10h]
0113107B fld1
0113107D lea eax,[esp+30h]
01131081 fstp dword ptr [esp+14h]
01131085 lea edx,[esp+20h]
01131089 fld dword ptr [__real@40000000 (1132118h)]
0113108F fstp dword ptr [esp+18h]
01131093 fld dword ptr [__real@40400000 (1132114h)]
01131099 fstp dword ptr [esp+1Ch]
0113109D fld dword ptr [esp]
011310A0 fstp dword ptr [esp+20h]
011310A4 fld dword ptr [esp+4]
011310A8 fstp dword ptr [esp+24h]
011310AC fld dword ptr [esp+8]
011310B0 fstp dword ptr [esp+28h]
011310B4 fld dword ptr [esp+0Ch]
011310B8 fstp dword ptr [esp+2Ch]
011310BC call Vector::operator+ (1131000h)
::std::cout << Result.A << Result.B << Result.C << Result.D;
011310C1 fld dword ptr [esp+3Ch]
011310C5 mov ecx,dword ptr [__imp_std::cout (1132044h)]
011310CB sub esp,10h
011310CE fstp dword ptr [esp+0Ch]
011310D2 fld dword ptr [esp+48h]
011310D6 fstp dword ptr [esp+8]
011310DA fld dword ptr [esp+44h]
011310DE fstp dword ptr [esp+4]
011310E2 fld dword ptr [esp+40h]
011310E6 fstp dword ptr [esp]
011310E9 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (113203Ch)]
011310EF mov ecx,eax
011310F1 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (113203Ch)]
011310F7 mov ecx,eax
011310F9 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (113203Ch)]
011310FF mov ecx,eax
01131101 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (113203Ch)]
return 0;
01131107 xor eax,eax
}
Kommt mir auch kürzer vor :)
Also demnach existiert dieses Problem schon seit VS2005...
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
Super. Damit wäre das reproduziert :) Falls du bei MSDN Connect bist, kannst du das Ticket ja bestätigen/uppen.
Re: Is it just me, or …
Destructor nun auskommentiert.
Disassembly VS 2005:
Disassembly VS 2008:
Disassembly VS 2005:
Code: Alles auswählen
int main() {
00401000 sub esp,20h
float A, B, C, D;
::std::cin >> A >> B >> C >> D;
00401003 lea eax,[esp+0Ch]
00401007 push eax
00401008 lea ecx,[esp+0Ch]
0040100C push ecx
0040100D mov ecx,dword ptr [__imp_std::cin (402040h)]
00401013 lea edx,[esp+0Ch]
00401017 push edx
00401018 lea eax,[esp+0Ch]
0040101C push eax
0040101D call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (402044h)]
00401023 mov ecx,eax
00401025 call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (402044h)]
0040102B mov ecx,eax
0040102D call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (402044h)]
00401033 mov ecx,eax
00401035 call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (402044h)]
Vector const Result = Vector(A, B, C, D) + Vector(0.0f, 1.0f, 2.0f, 3.0f);
0040103B fld dword ptr [esp]
0040103E fadd qword ptr [__real@0000000000000000 (402130h)]
::std::cout << Result.A << Result.B << Result.C << Result.D;
00401044 mov ecx,dword ptr [__imp_std::cout (40203Ch)]
0040104A sub esp,10h
0040104D fstp dword ptr [esp+20h]
00401051 fld dword ptr [esp+14h]
00401055 fadd qword ptr [__real@3ff0000000000000 (402128h)]
0040105B fstp dword ptr [esp+24h]
0040105F fld dword ptr [esp+18h]
00401063 fadd qword ptr [__real@4000000000000000 (402120h)]
00401069 fstp dword ptr [esp+28h]
0040106D fld dword ptr [esp+1Ch]
00401071 fadd qword ptr [__real@4008000000000000 (402118h)]
00401077 fstp dword ptr [esp+2Ch]
0040107B fld dword ptr [esp+2Ch]
0040107F fstp dword ptr [esp+0Ch]
00401083 fld dword ptr [esp+28h]
00401087 fstp dword ptr [esp+8]
0040108B fld dword ptr [esp+24h]
0040108F fstp dword ptr [esp+4]
00401093 fld dword ptr [esp+20h]
00401097 fstp dword ptr [esp]
0040109A call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)]
004010A0 mov ecx,eax
004010A2 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)]
004010A8 mov ecx,eax
004010AA call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)]
004010B0 mov ecx,eax
004010B2 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)]
return 0;
004010B8 xor eax,eax
}
Code: Alles auswählen
int main() {
00181000 sub esp,20h
float A, B, C, D;
::std::cin >> A >> B >> C >> D;
00181003 lea eax,[esp+0Ch]
00181007 push eax
00181008 lea ecx,[esp+0Ch]
0018100C push ecx
0018100D mov ecx,dword ptr [__imp_std::cin (182040h)]
00181013 lea edx,[esp+0Ch]
00181017 push edx
00181018 lea eax,[esp+0Ch]
0018101C push eax
0018101D call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (182038h)]
00181023 mov ecx,eax
00181025 call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (182038h)]
0018102B mov ecx,eax
0018102D call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (182038h)]
00181033 mov ecx,eax
00181035 call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (182038h)]
Vector const Result = Vector(A, B, C, D) + Vector(0.0f, 1.0f, 2.0f, 3.0f);
0018103B fld dword ptr [esp]
0018103E fadd qword ptr [__real@0000000000000000 (182130h)]
::std::cout << Result.A << Result.B << Result.C << Result.D;
00181044 mov ecx,dword ptr [__imp_std::cout (182044h)]
0018104A sub esp,10h
0018104D fstp dword ptr [esp+20h]
00181051 fld dword ptr [esp+14h]
00181055 fadd qword ptr [__real@3ff0000000000000 (182128h)]
0018105B fstp dword ptr [esp+24h]
0018105F fld dword ptr [esp+18h]
00181063 fadd qword ptr [__real@4000000000000000 (182120h)]
00181069 fstp dword ptr [esp+28h]
0018106D fld dword ptr [esp+1Ch]
00181071 fadd qword ptr [__real@4008000000000000 (182118h)]
00181077 fstp dword ptr [esp+2Ch]
0018107B fld dword ptr [esp+2Ch]
0018107F fstp dword ptr [esp+0Ch]
00181083 fld dword ptr [esp+28h]
00181087 fstp dword ptr [esp+8]
0018108B fld dword ptr [esp+24h]
0018108F fstp dword ptr [esp+4]
00181093 fld dword ptr [esp+20h]
00181097 fstp dword ptr [esp]
0018109A call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (18203Ch)]
001810A0 mov ecx,eax
001810A2 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (18203Ch)]
001810A8 mov ecx,eax
001810AA call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (18203Ch)]
001810B0 mov ecx,eax
001810B2 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (18203Ch)]
return 0;
001810B8 xor eax,eax
}
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
Mal ein kleines Update:
Bei MS konnte der Bug zuerst nicht reproduziert werden. Ich musste nochmal ran und habe dann herausgefunden, dass Exception-Handling aktiviert sein muss, damit das Verhalten auftritt …
… weiter vorne im Thread habe ich mich ja schon darüber aufgeregt, dass Funktionen, die try-Blöcke enthalten, nicht geinlined werden können. Aus dieser Zeit – besser gesagt aus der Beschreibung der Warnung C4717 – hatte ich noch im Hinterkopf, dass Funktionen nicht geinlined werden können, wenn ihre Rückgabewerte unwindable sind – also im Fall einer Exception ein Destruktor aufgerufen werden müsste.
Ich schätze die Situation so ein, dass der Compiler in dem Code-Beispiel Vector als unwindable klassifiziert, sobald man einen Destruktor – wenn auch nur einen leeren – definiert, und es deshalb ablehnt, Vector::operator + () zu inlinen.
Das alles wäre nicht merkwürdig, wenn der Compiler nicht normalerweise großartige Arbeit bei solchen Klassifizierungen leisten würde. Dass all die Mechanismen, die sonst bestimmen ob eine Funktion wegoptimiert werden kann und ob sie Exception-Handling benötigt, bei einem manuell definierten Destruktor versagen ist vielleicht keinen Bug-Report mehr wert, aber zumindest einen Verbesserungsvorschlag. Jetzt warte ich aber erstmal ab, was das VC-Team dazu sagt, vielleicht bin ich ja auch auf dem Holzweg.
Bei MS konnte der Bug zuerst nicht reproduziert werden. Ich musste nochmal ran und habe dann herausgefunden, dass Exception-Handling aktiviert sein muss, damit das Verhalten auftritt …
… weiter vorne im Thread habe ich mich ja schon darüber aufgeregt, dass Funktionen, die try-Blöcke enthalten, nicht geinlined werden können. Aus dieser Zeit – besser gesagt aus der Beschreibung der Warnung C4717 – hatte ich noch im Hinterkopf, dass Funktionen nicht geinlined werden können, wenn ihre Rückgabewerte unwindable sind – also im Fall einer Exception ein Destruktor aufgerufen werden müsste.
Ich schätze die Situation so ein, dass der Compiler in dem Code-Beispiel Vector als unwindable klassifiziert, sobald man einen Destruktor – wenn auch nur einen leeren – definiert, und es deshalb ablehnt, Vector::operator + () zu inlinen.
Das alles wäre nicht merkwürdig, wenn der Compiler nicht normalerweise großartige Arbeit bei solchen Klassifizierungen leisten würde. Dass all die Mechanismen, die sonst bestimmen ob eine Funktion wegoptimiert werden kann und ob sie Exception-Handling benötigt, bei einem manuell definierten Destruktor versagen ist vielleicht keinen Bug-Report mehr wert, aber zumindest einen Verbesserungsvorschlag. Jetzt warte ich aber erstmal ab, was das VC-Team dazu sagt, vielleicht bin ich ja auch auf dem Holzweg.
Re: Is it just me, or …
Hier mal wieder etwas aus der Abteilung "merkwürdiges Verhalten": http://ompf.org/forum/viewtopic.php?t=1744&p=19145
Und wir sehen: Ohne __forceinline wird der Code geinlined und die überflüssigen Konstruktoren werden verworfen …
Und wir sehen: Ohne __forceinline wird der Code geinlined und die überflüssigen Konstruktoren werden verworfen …
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
Interessant … was es nicht alles gibt. Ich schätze, der Initializer des Arrays wird nur aus bestimmten Stellen rausoptimiert … ich werde direkt mal prüfen, ob ich irgendwo uninitialisierte Arrays habe.
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
Hmmm, der Compiler scheint auch nicht daraufhin zu optimieren, dass durch Datentypgrenzen bestimmte Vergleiche konstant sind:Hier wird der Compiler beide Vergleiche durchführen, obwohl der zweite Vergleich durch das char-Intervall von [-128, 127] immer true liefert.
Immer, wenn eine Bereichsgrenze auf 0, 127, 32767 oder 2^31-1 liegt, kann man durch den richtigen Datentypen einen Vergleich sparen. Leider muss man das scheinbar manuell machen. Oder gibt es einen guten Grund, warum der Compiler das nicht optimiert?
Code: Alles auswählen
bool CheckCharacter(char x) { // default char signed
return (48 <= x) && (127 >= x);
}Immer, wenn eine Bereichsgrenze auf 0, 127, 32767 oder 2^31-1 liegt, kann man durch den richtigen Datentypen einen Vergleich sparen. Leider muss man das scheinbar manuell machen. Oder gibt es einen guten Grund, warum der Compiler das nicht optimiert?
- TGGC
- Establishment
- Beiträge: 569
- Registriert: 15.05.2009, 18:14
- Benutzertext: Ich _bin_ es.
- Alter Benutzername: TGGC
- Echter Name: Ich _bin_ es.
- Wohnort: Mainz
- Kontaktdaten:
Re: Is it just me, or …
Nein, der zweite Vergleich ist nicht immer wahr, sondern nur wenn x >= 127 ist. f'`8kKrishty hat geschrieben:Hmmm, der Compiler scheint auch nicht daraufhin zu optimieren, dass durch Datentypgrenzen bestimmte Vergleiche konstant sind:Hier wird der Compiler beide Vergleiche durchführen, obwohl der zweite Vergleich durch das char-Intervall von [-128, 127] immer true liefert.Code: Alles auswählen
bool CheckCharacter(char x) { // default char signed return (48 <= x) && (127 >= x); }
Immer, wenn eine Bereichsgrenze auf 0, 127, 32767 oder 2^31-1 liegt, kann man durch den richtigen Datentypen einen Vergleich sparen. Leider muss man das scheinbar manuell machen. Oder gibt es einen guten Grund, warum der Compiler das nicht optimiert?
Gruß, TGGC (der kostenlose DMC Download)
-
Alexander Kornrumpf
- Moderator
- Beiträge: 2198
- Registriert: 25.02.2009, 13:37
Re: Is it just me, or …
TGGC: Du hast die richtung des Vergleichs umgedreht.
Krishty: Mal ne ganz platte Vermutung: Es kommt extrem selten vor dass jemand einen integralwert mit einer konstanten an der Grenze des Wertebereichs vergleicht und lohnt sich daher nicht.
Krishty: Mal ne ganz platte Vermutung: Es kommt extrem selten vor dass jemand einen integralwert mit einer konstanten an der Grenze des Wertebereichs vergleicht und lohnt sich daher nicht.
- Schrompf
- Moderator
- Beiträge: 5397
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Is it just me, or …
Nein, TGGC hat schon recht: "127 >= x" bedeutet eben "größer oder gleich". Und char kann nunmal einen Wert von 127 annehmen. Die Bedingung ist also nicht zwangsweise falsch.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
-
Alexander Kornrumpf
- Moderator
- Beiträge: 2198
- Registriert: 25.02.2009, 13:37
Re: Is it just me, or …
Thomas:
Krishty: 127 >= x oder auch x <=127
TGGC: x >= 127
ist schon ein Unterschied.
P.S. Genau deswegen ist konstanten nach vorne schreiben unituitiv.
P.P.S. Was soll überhaupt das dämliche = dort? 128 > x hätte es doch auch getan. Vielleicht kapiert der compiler das sogar besser.
Krishty: 127 >= x oder auch x <=127
TGGC: x >= 127
ist schon ein Unterschied.
P.S. Genau deswegen ist konstanten nach vorne schreiben unituitiv.
P.P.S. Was soll überhaupt das dämliche = dort? 128 > x hätte es doch auch getan. Vielleicht kapiert der compiler das sogar besser.
- Schrompf
- Moderator
- Beiträge: 5397
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Is it just me, or …
Oh stimmt, hab mich von der verworrenen Schreibweise verwirren lassen.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Re: Is it just me, or …
Vielleicht sollte man aufhoeren, MS VC als DEN Compiler zu sehen ;) Selbst der betagte gcc 4.3.3 bekommt es gebacken.
- Schrompf
- Moderator
- Beiträge: 5397
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Is it just me, or …
Och naja... VC++ mag nicht DER Compiler sein, aber solange Visual Studio DEN Debugger hat, wird es kaum eine Diskussion geben :-)
Ich verfolge die gelegentlich auftauchenden Diskussionen über Compilerqualitäten... und soweit ich das beurteilen kann, produziert der GCC wirklich den besseren Code, teilweise drastisch schneller. Das tut allerdings auch der Intel-Compiler. Der AMD-Compiler taucht aus mir unerfindlichen Gründen bislang in keiner Diskussion auf. Der VC-Compiler hat allerdings einen großen Vorteil: er kompiliert schneller. Nach meinen subjektiven Einschätzungen durchaus Faktor 3 bis 5 schneller als der GCC.
Ich verfolge die gelegentlich auftauchenden Diskussionen über Compilerqualitäten... und soweit ich das beurteilen kann, produziert der GCC wirklich den besseren Code, teilweise drastisch schneller. Das tut allerdings auch der Intel-Compiler. Der AMD-Compiler taucht aus mir unerfindlichen Gründen bislang in keiner Diskussion auf. Der VC-Compiler hat allerdings einen großen Vorteil: er kompiliert schneller. Nach meinen subjektiven Einschätzungen durchaus Faktor 3 bis 5 schneller als der GCC.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
In dem Augenblick, in dem ich 128 hinschriebe, würden beide Operanden als signed short behandelt, weil 128 zu groß für char ist.Alexander Kornrumpf hat geschrieben:P.P.S. Was soll überhaupt das dämliche = dort? 128 > x hätte es doch auch getan. Vielleicht kapiert der compiler das sogar besser.
Ich habe vor ein paar Monaten mal versucht, auf GCC umzusteigen … und so viel besser als VC ist der auch nicht. Den ersten Bug hatte ich – kein Witz – in der ersten Programmzeile: GCC #defined __cplusplus einfach zu 1 statt zum Datum des Sprachstandards. Von da an ging es dann weiter mit __builtins, die nicht existieren obwohl das komplette Internet das Gegenteil behauptet, einer Standardbibliothek wo die Hälfte (so ziemlich alles mit wchar_t) noch nicht implementiert ist und endet dann mit dem herrlichen online-Support, der schlicht und einfach nicht existiert (darüber, ob sie __cplusplus nun endlich standardkonform machen, flamen sie seit sieben Jahren). Irgendwie ist es da bequemer, von Zeit zu Zeit das VC-Kompilat gegenzutesten und hier und da von Hand zu optimieren. Und was Schrompf sagt kommt auch noch dazu.Jörg hat geschrieben:Vielleicht sollte man aufhoeren, MS VC als DEN Compiler zu sehen ;) Selbst der betagte gcc 4.3.3 bekommt es gebacken.
Nichtsdestotrotz benutze ich GCC einmal im Monat, um meinen Code zu parsen – fehlerhaften Template-Code oder nicht standardkonforme Syntaxkonstrukte findet er bedeutend häufiger als VC, das z.B. die Spezialisierung von Templates im class-Scope erlaubt. Wichtig insbesondere seit ich in VC nicht mehr die Language Extensions deaktivieren will, weil ich dann die C++0x-Features einbüßen würde.
Re: Is it just me, or …
So war's nicht gemeint, ging mir eher darum, dass man solche Dinge ja schnell mit einem "Zweitcompiler" beliebiger Wahl gegentesten kann. Wollte keinesfalls den Thread in einem Flamewar münden lassen. Und offensichtliche Unzulänglichkeiten sollte man natuerlich in einem Feature-Request formulieren, egal fuer welchen Compiler.
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
Alles klar. Während der Stunde, die ich jetzt brauche um MinGW C++0x-tauglich zu machen, könnt ihr ja mal darüber nachdenken, warum VC ein Placement-new durch Move-Constructor mit einem nullptr-Check versieht:Kurz: Bevor die int verschoben wird, wird getestet, ob das Ziel nullptr ist. Falls das der Fall ist, wird die Bewegung einfach übersprungen (es dient also nicht dazu, einen Fehler zu melden oder so). Weder die Implementierung vom Placement-new noch von ::std::move tun irgendwas. Wo kommt dieser völlig überflüssige Check her und warum wird er nicht wegoptimiert? Das ist eine innere Schleife, raubt mir ein Register und macht mir die Funktion in der Summe zu lang, um geinlined zu werden.
Edit: Selbst, wenn ich per __assume(nullptr < &Array[Index]); direkt vor dem new den trust-me-on-this-one-Modus erzwinge – er testet weiter. Wtf?!?
Code: Alles auswählen
new (&Array[Index]) int(::std::move(Array[Index-1]));
xor ebx, ebx
lea eax,[edx+ecx*4]
cmp eax,ebx
je 0F21260h
mov edi,dword ptr [eax-4]
mov dword ptr [eax],edi
dec ecx // 0F21260h
Edit: Selbst, wenn ich per __assume(nullptr < &Array[Index]); direkt vor dem new den trust-me-on-this-one-Modus erzwinge – er testet weiter. Wtf?!?
Zuletzt geändert von Krishty am 13.06.2010, 20:34, insgesamt 1-mal geändert.
-
Alexander Kornrumpf
- Moderator
- Beiträge: 2198
- Registriert: 25.02.2009, 13:37
Re: Is it just me, or …
Was mich ehrlich gesagt in der These bestätigt, dass das ein bekloppter(das wäre zu zeigen) Randfall(das ist nun per Definition unstrittig) ist.In dem Augenblick, in dem ich 128 hinschriebe, würden beide Operanden als signed short behandelt, weil 128 zu groß für char ist.
Mal ehrlich, wieviele real-life Situationen fallen dir ein, in denen der Programmierer zwar denkt: "Mensch, bloß keine 128 schreiben, das passt nicht in char", aber dann nicht auch denkt "Hmm, Moment mal, der Vergleich an sich ist ja sinnlos", und das selbst wegoptimiert.
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
Meine derzeitige Real-Life-Situation ist ein Parser:Du darfst den zweiten Vergleich dort nicht weglassen, weil die Existenz eines Vorzeichens in char implementation-defined ist. Der Compiler hingegen darf es schon, weil er im Gegensatz zu dir erkennen kann ob das Programmverhalten dadurch beeinträchtigt würde oder nicht.
Eine Mögliche Alternative wäre natürlich das explizite return (0x20 <= static_cast<signed char>(x));, da hast du Recht. Aber der Compiler soll ja gerade das optimieren, was ich nicht selber optimiere weil ich zu faul, schöngeistig oder dumm bin, darin liegt doch der Sinn eines Optimizers … und nachdem ich gestern gesehen habe, wie er eine Verzweigung aus Zuweisungen und bitweisen Manipulationen zu einem komplett sprungfreien Bithaufen optimiert hat, hätte ich sowas Einfaches eigentlich schon erwartet.
Code: Alles auswählen
bool IsNonControlASCII(char x) {
return (0x20 <= x) && (0x7F >= x);
}Eine Mögliche Alternative wäre natürlich das explizite return (0x20 <= static_cast<signed char>(x));, da hast du Recht. Aber der Compiler soll ja gerade das optimieren, was ich nicht selber optimiere weil ich zu faul, schöngeistig oder dumm bin, darin liegt doch der Sinn eines Optimizers … und nachdem ich gestern gesehen habe, wie er eine Verzweigung aus Zuweisungen und bitweisen Manipulationen zu einem komplett sprungfreien Bithaufen optimiert hat, hätte ich sowas Einfaches eigentlich schon erwartet.
-
Alexander Kornrumpf
- Moderator
- Beiträge: 2198
- Registriert: 25.02.2009, 13:37
Re: Is it just me, or …
Point taken.
Allerdings hoffe ich auf den Tag wo ASCII an sich ein "bekloppter Randfall" wird. Es ist eine Zumutung wie oft man auch heute noch Encodingproblemen begegnet.
Allerdings hoffe ich auf den Tag wo ASCII an sich ein "bekloppter Randfall" wird. Es ist eine Zumutung wie oft man auch heute noch Encodingproblemen begegnet.
- TGGC
- Establishment
- Beiträge: 569
- Registriert: 15.05.2009, 18:14
- Benutzertext: Ich _bin_ es.
- Alter Benutzername: TGGC
- Echter Name: Ich _bin_ es.
- Wohnort: Mainz
- Kontaktdaten:
Re: Is it just me, or …
mea culpa. Bin wohl auf das gleiche wie Schromp reingefallen. f'`8k
Gruß, TGGC (der kostenlose DMC Download)
Gruß, TGGC (der kostenlose DMC Download)
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
Bevor sie den Zeichensatz reformieren, sollten sie sich endlich mal auf vernünftige Line-Endings einigen ;)Alexander Kornrumpf hat geschrieben:Allerdings hoffe ich auf den Tag wo ASCII an sich ein "bekloppter Randfall" wird. Es ist eine Zumutung wie oft man auch heute noch Encodingproblemen begegnet.
Zurück zu dem Movement-Bug: Der Fehler scheint immer mit Placement-new aufzutreten, Move-Semantics haben nichts damit zu tun. Interessanterweise testet auch GCC 4.3.3 – allerdings nicht (wie VC 2010) die Zieladresse, sondern die Quelladresse. Aber genau wie VC springt er im Fall eines Nullzeigers einfach über die Konstruktion hinweg – kein Error-Handling, nichts. Da es beide Compiler tun, glaube ich nicht unbedingt an einen Fehler.
Hat jemand eine Idee, warum nach Placement-new und vor der Konstruktion absichtlich auf nullptr getestet werden sollte?
Hier mal ein Test:
Code: Alles auswählen
struct NonTrivialType {
int x;
NonTrivialType() : x(0) { }
NonTrivialType(NonTrivialType const & Ref) : x(Ref.x) { }
};
…
NonTrivialType * Array = new NonTrivialType[2];
new (&Array[0]) NonTrivialType(Array[1]);Code: Alles auswählen
13F6E12DF test r11,r11
13F6E12E2 je 13F6E12EBh
13F6E12E4 mov eax,dword ptr [r11+4]
13F6E12E8 mov dword ptr [r11],eax
13F6E12EB …Code: Alles auswählen
13F6E12E4 mov eax,dword ptr [r11+4]
13F6E12E8 mov dword ptr [r11],eaxRe: Is it just me, or …
Ich muss mich korrigieren, auch gcc testet das Ziel. Habe mit den Array-Indizees gespielt und bin durcheinander gekommen. placement-new muss wohl garantieren, auch im 0-Fall keine Exception zu werfen....ist natuerlich aergerlich, wenn man diesen per-se ausschliessen kann.
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
Okay, Update:
Der C++-Standard sagt: Ist new mit throw() deklariert (wirft also keine Exceptions) und gibt nullptr zurück, darf keine Initialisierung stattfinden. Das gilt auch für das throw()-deklarierte Placement-new – dort liegt wahrscheinlich der Ursprung des Tests. Soweit, so gut.
Problematisch ist allerdings, dass der Compiler den Test nicht wegoptimiert, wenn die Adresse des Placements definitiv nicht nullptr ist … und das im Fall von VC sogar, wenn man es per __assume() zu erzwingen versucht. Das ist ein Bug im Optimizer.
Für GCC gibt es bereits einen entsprechenden Bug-Report, der 2005 gefiled wurde und immernoch offen ist. Für VC habe ich ihn gerade abgeschickt.
Der C++-Standard sagt: Ist new mit throw() deklariert (wirft also keine Exceptions) und gibt nullptr zurück, darf keine Initialisierung stattfinden. Das gilt auch für das throw()-deklarierte Placement-new – dort liegt wahrscheinlich der Ursprung des Tests. Soweit, so gut.
Problematisch ist allerdings, dass der Compiler den Test nicht wegoptimiert, wenn die Adresse des Placements definitiv nicht nullptr ist … und das im Fall von VC sogar, wenn man es per __assume() zu erzwingen versucht. Das ist ein Bug im Optimizer.
Für GCC gibt es bereits einen entsprechenden Bug-Report, der 2005 gefiled wurde und immernoch offen ist. Für VC habe ich ihn gerade abgeschickt.
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
VCs Optimizer arbeitet auch ganz toll, wenn man eine float als int reinterpretieren möchte. Falls ihr mal so eine Funktion schreibt: Übergebt nicht float, sondern float const & – sonst wird die Gleitkommazahl aus einem SSE-Register auf den Stack geschoben, von dort zurück ins SSE-Register geladen, wieder zurück auf den Stack geschrieben, dann in ein Integer-Register geladen und erst dann weiterverarbeitet. Am besten pfeift ihr auch auf Aliasing und macht dann einfach return reinterpret_cast<int const &> – damit scheint der Compiler am besten zurecht zu kommen.
Übrigens sind Integer-Vergleiche locker 10 % schneller als Gleitkommavergleiche – wenn ihr also massiv auf Basis von Gleitkommazahlen brancht, konvertiert ihr Bitmuster zu Integers im Zweierkomplement und vergleicht die.
Übrigens sind Integer-Vergleiche locker 10 % schneller als Gleitkommavergleiche – wenn ihr also massiv auf Basis von Gleitkommazahlen brancht, konvertiert ihr Bitmuster zu Integers im Zweierkomplement und vergleicht die.
- Krishty
- Establishment
- Beiträge: 8413
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Is it just me, or …
Jeden Tag was Neues, Adam …
Hier gejammert und wenig später reproduziert: Der Linker entfernt unreferenzierte Compile-Time-constant-Arrays mal so, mal so aus der Exe. In meinem Programm hat er sie nur wegoptimiert, wenn sie in Zeigern lagen; beim Reproduzieren für den Bug-Report hat er sie nur entfernt, wenn sie in Arrays lagen.
Man kann sich also scheinbar nicht darauf verlassen, dass alles unreferenzierte Zeug rausfliegt – und es auch nicht wirklich erzwingen. Sollte das mal zum Problem werden (bei wirklich großen Datenmengen), sollte man sich vielleicht überlegen, ob man nicht per Präprozessor steuert, von welchen Symbolen der Compiler überhaupt weiß.
Hier gejammert und wenig später reproduziert: Der Linker entfernt unreferenzierte Compile-Time-constant-Arrays mal so, mal so aus der Exe. In meinem Programm hat er sie nur wegoptimiert, wenn sie in Zeigern lagen; beim Reproduzieren für den Bug-Report hat er sie nur entfernt, wenn sie in Arrays lagen.
Man kann sich also scheinbar nicht darauf verlassen, dass alles unreferenzierte Zeug rausfliegt – und es auch nicht wirklich erzwingen. Sollte das mal zum Problem werden (bei wirklich großen Datenmengen), sollte man sich vielleicht überlegen, ob man nicht per Präprozessor steuert, von welchen Symbolen der Compiler überhaupt weiß.
- kimmi
- Moderator
- Beiträge: 1416
- Registriert: 26.02.2009, 09:42
- Echter Name: Kim Kulling
- Wohnort: Luebeck
- Kontaktdaten:
Re: Is it just me, or …
Oder man checkt seinen Code mit so etwas wie Lint bzw. einem g++, der einem Warnungen für nicht referenzierte Symbole ausspuckt.
Gruß Kimmi
Gruß Kimmi