clang vs gcc - Optimierung einschließlich Operator neu

7

Ich habe dieses einfache Beispiel, gegen das ich getestet habe, und mir ist aufgefallen, dass gcc-Optimierungen (-O3) nicht so gut sind wie klingende, wenn operator new beteiligt ist. Ich frage mich, was könnte das Problem sein und wenn es möglich ist, gcc zu zwingen, mehr optimierten Code irgendwie zu produzieren?

%Vor%

Beispiel oben ist nur eine einfache Version des Codes, den ich am Anfang getestet habe, aber es zeigt immer noch den Unterschied zwischen gcc / clang. Ich habe auch den Assembler-Code überprüft und es gibt keinen großen Unterschied in der Größe, aber definitiv in der Leistung. Auf der anderen Seite macht calling etwas, was nicht erlaubt ist?

    
Kris 04.09.2014, 14:43
quelle

3 Antworten

13

Wenn wir diesen Code in godbolt einbinden, können wir sehen, dass clang den Code darauf hin optimiert:

%Vor%

, während gcc diese Optimierung nicht durchführt. Die Frage ist also eine gültige Optimierung? Folgt dies dem as-if rule , das im Entwurf des C ++ - Standards vermerkt ist Abschnitt 1.9 Programmausführung was sagt ( Hervorhebung meins ):

  

Die semantischen Beschreibungen in dieser Internationalen Norm definieren a   parametrisierte nichtdeterministische abstrakte Maschine. Diese Internationale   Standard stellt keine Anforderungen an die Konformitätsstruktur   Implementierungen. Insbesondere müssen sie nicht kopieren oder emulieren   Struktur der abstrakten Maschine. Vielmehr konforme Implementierungen   sind erforderlich, um (nur) das beobachtbare Verhalten des Abstrakten nachzuahmen   Maschine wie unten erklärt. 5

wo die Anmerkung 5 sagt:

  

Diese Bestimmung wird manchmal als "Als-ob" -Regel bezeichnet, weil ein   die Umsetzung ist frei, jede Anforderung davon zu ignorieren   International Standard, solange das Ergebnis ist als ob die Anforderung   wurde gehorcht, soweit sich aus dem Observablen ergibt   Verhalten des Programms. Zum Beispiel ein tatsächlicher Implementierungsbedarf   Bewerte einen Teil eines Ausdrucks nicht, wenn er folgern kann, dass sein Wert ist   nicht verwendet und keine Nebenwirkungen, die das beobachtbare Verhalten beeinflussen   das Programm wird produziert.

Da new eine Ausnahme auslösen könnte, die ein beobachtbares Verhalten hätte, da dies den Rückgabewert des Programms verändern würde.

R.MartinhoFernandes argumentiert, dass es Implementierungsdetails sind, wann eine Ausnahme ausgelöst werden soll und daher clang entscheiden könnte, dass dieses Szenario keine Ausnahme verursachen würde und daher der Aufruf von new nicht gegen as-if rule verstoßen würde. Das scheint mir ein vernünftiges Argument zu sein.

aber als T.C. weist darauf hin:

  

Ein Ersatz globaler Operator neu könnte in einer anderen Übersetzungseinheit definiert worden sein

Casey lieferte ein Beispiel, das zeigt, dass auch dann, wenn clang sieht, dass es einen Ersatz gibt, diese Optimierung trotzdem ausgeführt wird, obwohl es Nebenwirkungen gibt. Das scheint also eine übermäßig aggressive Optimierung zu sein.

Hinweis: Speicherlecks sind kein undefiniertes Verhalten .

    
Shafik Yaghmour 04.09.2014, 15:47
quelle
9

Der Grund dafür ist, dass es keine Regel gibt, wie viel Speicher eine Maschine haben darf, noch bietet die Sprache eine Möglichkeit, die Menge an zugewiesenem oder freiem Speicher zu untersuchen (obwohl POSIX mallinfo definiert). Hier simulieren wir Ihr Programm auf einer abstrakten Maschine mit unendlicher Speichermaschine, wo die Zuweisung kontinuierlich gelingt. Oder zumindest unendlicher Speicher für die Zwecke der Zuweisungen in dieser Schleife, aber nicht konsistent für ein ganzes Programm. Jedenfalls sind mir zwei gute Einwände bekannt.

Überlegen Sie zuerst, ob es Malloc anstelle von Operator New war. Die C99-Spezifikation besagt:

  

Die malloc-Funktion weist Speicherplatz für ein Objekt zu, dessen Größe durch die Größe angegeben wird und dessen Wert nicht definiert ist. Die malloc-Funktion gibt entweder einen Nullzeiger oder einen Zeiger auf den zugewiesenen Speicherplatz zurück.

Das Kompilieren von malloc (), um immer erfolgreich zu sein, scheint dieser Spezifikation zu entsprechen. Aber was ist, wenn Sie es öfter aufrufen, als wir tatsächlich einen Zeiger für die Schleife erstellen können und diese nur dann verlassen, wenn sie versagt? Ein möglicher Ausweg besteht darin, zu beachten, dass es in der abstrakten Maschinendefinition keine Regel gibt, dass ein 64-Bit-Zeiger nur 2 64 mögliche Werte enthalten kann, nur dass es keine Möglichkeit gibt, Werte außerhalb davon zu konstruieren Angebot. Es scheint, dass die Implementierung solche Dinge nach Belieben erzeugen kann. Ich persönlich finde diese Antwort unbefriedigend.

Denken Sie daran, dass wir auch Dinge wie "T *t1 = new T; T *t2 = (T*)rand();" optimieren, indem wir annehmen, dass t1 möglicherweise nicht alias t2 ist. Es spielt keine Rolle, ob Rand die richtige Adresse ausgewählt hat oder ob Sie über den gesamten Adressraum iteriert haben. Sobald wir zeigen, dass die Adresse von t1 nicht in t2 einfloss, sollten wir daraus schließen können, dass sie sich auf verschiedene Objekte beziehen. Während ich möchte, dass der Standard funktioniert, und so arbeiten Compiler, ist mir keine Standardisierung bekannt, um diese Position zu unterstützen. Dies wird wahrscheinlich das Thema eines zukünftigen Papiers werden.

Zweitens ist der Operator new nicht malloc, sondern eine ersetzbare Funktion. Wie in der Antwort von Casey angedeutet, beabsichtigen wir, die Regeln in N3664 (obwohl ich glaube nicht, dass Clang neue Ausdrücke anders behandelt als explizite Aufrufe an den Operator new). Shafik wies darauf hin, dass dies die Kausalität zu verletzen scheint, aber N3664 begann sein Leben als N3433 , und ich bin mir ziemlich sicher, dass wir die Optimierung zuerst geschrieben haben und das Papier danach trotzdem geschrieben haben.

    
Nick Lewycky 07.09.2014 09:49
quelle
3

Es scheint, dass clang die Speicherzuweisungen gemäß den geänderten Regeln in N3664 Clarifying Memory Allocation , die in C ++ 14 integriert wurde. N3664 ermöglicht es, die Anzahl der Aufrufe von Zuweisungs- / Freigabe-Funktionen zu verringern, indem Zuordnungen zusammengeführt oder Zuordnungen ganz eliminiert werden.

    
Casey 04.09.2014 16:20
quelle