Ich bin mehrfach darauf hingewiesen worden, dass Zugriffe auf volatile
-Objekte nicht wegoptimiert werden können, aber es scheint mir, als ob dieser Abschnitt, der in den C89, C99 und C11 Standards enthalten ist, anders rät:
... Eine tatsächliche Implementierung braucht einen Teil eines Ausdrucks nicht zu bewerten, wenn er daraus ableiten kann, dass sein Wert nicht verwendet wird und keine erforderlichen Nebenwirkungen erzeugt werden (einschließlich der durch Aufruf einer Funktion oder Zugriff auf ein flüchtiges Objekt) / p>
Wenn ich richtig verstehe, besagt dieser Satz, dass eine tatsächliche Implementierung einen Teil eines Ausdrucks optimieren kann, wenn diese beiden Anforderungen erfüllt sind:
Es scheint mir, dass viele Leute die Bedeutung von "included" mit der Bedeutung von "exclusive" verwechseln.
Ist es für einen Compiler möglich, zwischen einem Nebeneffekt zu unterscheiden, der "benötigt" ist, und einem Nebeneffekt, der nicht ist? Wenn Timing als notwendiger Nebeneffekt betrachtet wird, warum dürfen Compiler dann Null-Operationen wie do_nothing();
oder int unused_variable = 0;
? Optimieren?
Wenn ein Compiler folgern kann, dass eine Funktion nichts tut (zB void do_nothing() { }
), ist es dann möglich, dass der Compiler eine Rechtfertigung hat, Aufrufe an diese Funktion zu optimieren?
Wenn ein Compiler daraus schließen kann, dass ein volatile
-Objekt keinem wichtigen Element zugeordnet ist (dh vielleicht ist es /dev/null
zugeordnet, um eine Null-Operation zu bilden), dann ist es möglich, dass der Compiler auch eine Rechtfertigung hat um diese nicht entscheidende Nebenwirkung zu optimieren?
Wenn ein Compiler Optimierungen durchführen kann, um unnötigen Code wie Aufrufe von do_nothing()
in einem Prozess namens "tote Code-Eliminierung" zu eliminieren (was ziemlich allgemein üblich ist), warum kann der Compiler auch flüchtige Schreibvorgänge nicht eliminieren ein Nullgerät?
Wie ich weiß, kann entweder der Compiler Aufrufe für Funktionen oder flüchtige Zugriffe optimieren oder der Compiler kann nicht wegen 5.1.2.3p4 wegoptimieren.
Ich denke, das "inclusive any" bezieht sich auf die "benötigten Nebenwirkungen", während Sie es scheinbar als "Teil eines Ausdrucks" zu lesen scheinen.
Die Absicht war also zu sagen:
... Eine tatsächliche Implementierung muss einen Teil eines Ausdrucks nicht bewerten, wenn er daraus ableiten kann, dass sein Wert nicht verwendet wird und keine erforderlichen Nebenwirkungen erzeugt werden.
Beispiele für benötigte Nebenwirkungen sind:
- Benötigte Nebenwirkungen durch eine Funktion, die dieser Ausdruck aufruft
- Zugriffe auf volatile Variablen
Der Begriff benötigte Nebenwirkung ist nicht im Standard definiert. Section / 4 versucht auch nicht, es zu definieren - es versucht (und nicht sehr erfolgreich), Beispiele zu liefern.
Ich denke, die einzig sinnvolle Interpretation besteht darin, sie als beobachtbares Verhalten zu verstehen, das durch 5.1.2.3/6 definiert ist. Es wäre also viel einfacher zu schreiben:
Eine tatsächliche Implementierung muss einen Teil eines Ausdrucks nicht bewerten, wenn er daraus schließen kann, dass sein Wert nicht verwendet wird und kein beobachtbares Verhalten verursacht wird.
Ihre Fragen in der Bearbeitung werden von 5.1.2.3/6 beantwortet, manchmal auch als as-if-Regel bekannt, die ich hier zitieren werde:
Die geringsten Anforderungen an eine konforme Implementierung sind:
- Zugriffe auf flüchtige Objekte werden streng nach den Regeln der abstrakten Maschine ausgewertet.
- Bei Programmbeendigung müssen alle in Dateien geschriebenen Daten identisch sein mit dem Ergebnis, das die Ausführung des Programms nach der abstrakten Semantik ergeben hätte.
- Die Eingabe- und Ausgabedynamik interaktiver Geräte muss gemäß 7.21.3 erfolgen. Die Absicht dieser Anforderungen ist, dass ungepufferte oder zeilengepufferte Ausgaben so schnell wie möglich erscheinen, um sicherzustellen, dass Aufforderungsmeldungen tatsächlich vor einem Programm erscheinen, das auf eine Eingabe wartet.
Dies ist das beobachtbare Verhalten des Programms.
Beantworten der spezifischen Fragen in der Bearbeitung:
Ist es für einen Compiler möglich, zwischen einem Nebeneffekt zu unterscheiden, der "benötigt" ist, und einem Nebeneffekt, der nicht ist? Wenn Timing als notwendiger Nebeneffekt betrachtet wird, warum dürfen Compiler Null-Operationen wie do_nothing () optimieren; oder int unbenutzte_Variable = 0;?
Timing ist kein Nebeneffekt. Eine "benötigte" Nebenwirkung bedeutet hier vermutlich eine, die beobachtbares Verhalten verursacht.
Wenn ein Compiler folgern kann, dass eine Funktion nichts tut (z. B. void do_nothing () {}), ist es dann möglich, dass der Compiler eine Rechtfertigung hat, Aufrufe an diese Funktion zu optimieren?
Ja, diese können optimiert werden, weil sie kein beobachtbares Verhalten verursachen.
Wenn ein Compiler in der Lage ist, abzuleiten, dass ein flüchtiges Objekt keinem entscheidenden Element zugeordnet ist (dh vielleicht ist es / dev / null zugeordnet, um eine Null-Operation zu bilden), ist es möglich, dass der Compiler auch eine Berechtigung dafür hat diese nicht entscheidende Nebenwirkung optimieren?
Nein, weil Zugriffe auf flüchtige Objekte als beobachtbares Verhalten definiert sind.
Wenn ein Compiler Optimierungen durchführen kann, um unnötigen Code wie Aufrufe von do_nothing () in einem Prozess namens "tote Code-Eliminierung" zu eliminieren (was ziemlich allgemein üblich ist), warum kann dann der Compiler nicht auch flüchtige Schreibvorgänge eliminieren ein Nullgerät?
Weil flüchtige Zugriffe als beobachtbares Verhalten definiert sind und leere Funktionen nicht.
Ich glaube das:
(einschließlich alle, die durch den Aufruf einer Funktion oder den Zugriff auf ein flüchtiges Element verursacht werden) Objekt)
soll als
gelesen werden(einschließlich:
- irgendwelche Nebenwirkungen, die durch den Aufruf einer Funktion verursacht werden; oder
- Zugriff auf eine flüchtige Variable)
Dieses Lesen ist sinnvoll, da der Zugriff auf eine flüchtige Variable ein Nebeneffekt ist .
Tags und Links c c99 language-lawyer volatile c11