Wie kann verhindert werden, dass gcc einige Anweisungen in C optimiert?

107

Um eine Seite schmutzig zu machen (Einschalten des schmutzigen Bits im Seitentabelleneintrag), berühre ich die ersten Bytes der Seite wie folgt:

pageptr[0] = pageptr[0];

In der Praxis ignoriert gcc die Aussage jedoch durch Eliminierung des toten Speichers. Um zu verhindern, dass gcc es optimiert, schreibe ich die Anweisung wie folgt neu:

volatile int tmp;
tmp = pageptr[0];
pageptr[0] = tmp;

Es scheint, dass der Trick funktioniert, aber etwas hässlich. Ich würde gerne wissen, ob es Direktiven oder Syntax gibt, die den gleichen Effekt haben. Und ich möchte keine -O0Flagge verwenden, da dies auch eine große Leistungsstrafe mit sich bringt.

ZelluX
quelle
8
@Mark -O0 stoppt die Optimierung, verlangsamt aber auch die Programmleistung. Ich möchte nur die Optimierung dieses Code-Snippets verhindern: P
ZelluX
Ich möchte hinzufügen, dass in der Vergangenheit selbst die Verwendung -O0die "Optimierung" von totem Code nicht verhindert hat. Wenn GCC beispielsweise feststellt, dass Code keinen Effekt hat, wird er einfach entfernt. AFAIK das ist schon eine Etappe -O0... Aber das ist nur meine Erfahrung
Smoothware

Antworten:

91

Das Deaktivieren der Optimierung behebt das Problem, ist jedoch nicht erforderlich. Eine sicherere Alternative besteht darin, es für den Compiler illegal zu machen, den Speicher mithilfe des Typqualifizierers zu optimieren volatile.

// Assuming pageptr is unsigned char * already...
unsigned char *pageptr = ...;
((unsigned char volatile *)pageptr)[0] = pageptr[0];

Das volatileTypqualifikationsmerkmal weist den Compiler an, die Speicher und Ladevorgänge streng zu speichern. Ein Zweck von volatilebesteht darin, den Compiler darüber zu informieren, dass der Speicherzugriff Nebenwirkungen hat und daher beibehalten werden muss. In diesem Fall hat der Speicher den Nebeneffekt, dass ein Seitenfehler verursacht wird, und Sie möchten, dass der Compiler den Seitenfehler beibehält.

Auf diese Weise kann der umgebende Code weiterhin optimiert werden, und Ihr Code kann auf andere Compiler übertragen werden, die die GCCs #pragmaoder die __attribute__Syntax nicht verstehen .

Dietrich Epp
quelle
2
Ich würde sagen, dies ist dem Deaktivieren von Optimierungen vorzuziehen. Mit dieser Methode können Sie weiterhin von anderen Optimierungen profitieren.
Ben S
3
Die Lösung von Dietrich Epp funktioniert unter dem ARM4.1-Compiler nicht . Selbst die Lösung von ZelluX funktioniert nicht. Eine alternative Methode, um dies für ARM4.1 zum Laufen zu bringen, ist die ZelluX-Lösung. Machen Sie ' temp ' zu einer globalen flüchtigen Variablen .
Oculus Dexter
1
Das ist ziemlich schlecht für den Compiler.
Alexey Frunze
1
@Shocker: GCC kann die Variable weiterhin optimieren, ohne den tatsächlichen Speicherzugriff zu optimieren. Das sind verschiedene Themen.
Dietrich Epp
2
@jww: Diese Verwendung passt zu dem, was in diesem Blog-Beitrag beschrieben wird. volatilebedeutet, dass der Speicherzugriff wie geschrieben erfolgen muss, was genau das ist, was wir wollen. Mit anderen Worten, wir haben sorgfältig darüber nachgedacht, und es bedeutet, was wir denken, dass es bedeutet.
Dietrich Epp
184

Sie können verwenden

#pragma GCC push_options
#pragma GCC optimize ("O0")

your code

#pragma GCC pop_options

Optimierungen seit GCC deaktivieren 4.4.

Weitere Informationen finden Sie in der GCC-Dokumentation.

Pflug
quelle
3
Es ist jedoch anzumerken, dass dies nur für ganze Funktionen funktioniert, nicht für bestimmte Anweisungen: gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/… "Jede Funktion, die nach diesem Punkt definiert wird, ist wie ein Attribut (() Für diese Funktion wurde optimize ("STRING"))) angegeben. "
Ciro Santilli 法轮功 冠状 病 六四 事件 26
134

Anstatt die neuen Pragmas zu verwenden, können Sie sie auch __attribute__((optimize("O0")))für Ihre Bedürfnisse verwenden. Dies hat den Vorteil, dass nur eine einzelne Funktion und nicht alle in derselben Datei definierten Funktionen angewendet werden.

Anwendungsbeispiel:

void __attribute__((optimize("O0"))) foo(unsigned char data) {
    // unmodifiable compiler code
}
FRob
quelle
3
Was ist, wenn ich keine -OlevelOption verwende, aber die einzelnen Optionen verwendet habe, die separat aktiviert werden? (In meinem Fall kann ich nicht feststellen, welche individuelle Optimierungsoption den Code bricht) .
user2284570