Discussion:
OT: gcc 4.1.1 buggy (Optimierungsstufe 3)
(zu alt für eine Antwort)
Robert Hartmann
2006-10-16 05:41:13 UTC
Hallo zusammen,

ja, ich weiß dass es in dieser Gruppe um die Sprache C
geht und nicht um Compilerspezifika.
Allerdings glaube ich, dass ein kurzer Hinweis,
dass die Optimierungsstufe 3 beim gcc 4.1.1 fehlerhaft ist,
genügend Leser interessieren könnte.

Für den Bug-Report muss ich noch meinen Text

http://www.tu-clausthal.de/~ifrh/gcc_4-1-1_bug_im_optimierer.pdf

ins Englische übersetzen und evtl. noch etwas an der Formulierung basteln.

Gruß Robert
Stefan Reuther
2006-10-16 06:15:37 UTC
Post by Robert Hartmann
dass die Optimierungsstufe 3 beim gcc 4.1.1 fehlerhaft ist,
genügend Leser interessieren könnte.
http://www.tu-clausthal.de/~ifrh/gcc_4-1-1_bug_im_optimierer.pdf
Wenn ich das richtig sehe, hat der Compiler die Funktion
void test_global_schleife1() {
int i;
for (int i = 0, a_global = 0; i < 10; ++i)
a_global += i*i;
}
(hat das einen Grund, warum du in dem PDF cut&paste deaktiviert hast?),
welche a_global aufwändig auf 285 setzt, durch den Assemblercode für
a_global = 285
ersetzt. Und in der ISR hat er mal zwei unabhängige Instruktionen
vertauscht.

Wo ist jetzt das Problem?


Stefan
Robert Hartmann
2006-10-17 06:38:18 UTC
Moin moin,
Post by Stefan Reuther
Post by Robert Hartmann
dass die Optimierungsstufe 3 beim gcc 4.1.1 fehlerhaft ist,
genügend Leser interessieren könnte.
http://www.tu-clausthal.de/~ifrh/gcc_4-1-1_bug_im_optimierer.pdf
Wenn ich das richtig sehe, hat der Compiler die Funktion
void test_global_schleife1() {
int i;
for (int i = 0, a_global = 0; i < 10; ++i)
a_global += i*i;
}
(hat das einen Grund, warum du in dem PDF cut&paste deaktiviert hast?),
(Naja, irgendwie schon :-) Ich, hab vergessen es zu erlauben.)
Post by Stefan Reuther
welche a_global aufwändig auf 285 setzt, durch den Assemblercode für
a_global = 285
Ok, wenn man annehmen möchte, dass Interrupts laufende Funktionen
nicht unterbrechen dürfen, ist es egal.
Nun sollten aber Interrupts gerade auch laufende Funktionen
unterbrechen, und dann kann es durchaus wichtig sein, dass
eine globale Variable tatsächlich "schrittweise" vergrößert
wird z.B. um innerhalb der ISR herauszufinden,
bei welchem Schleifendurchlauf der Interrupt "auslöste".
Wenn nun die ISR nicht nur lesend auf die globale Variable
zugreifen soll, sondern auch schreibend, macht es einen
noch viel größeren Unterschied, ob die Schleife nach Beendigung
der ISR mit dem neuen Wert weiter arbeiten muss oder ob sie
nicht weiter arbeiten kann, da das Schleifenergebnis als fixe
Zahl optimiert wurde.

(Zumindest könnte man auf so ein Verhalten in der Dokumentation
hinweisen, dass man entsprechende Teile eben nicht optimieren
lässt. Fehlende Information empfinde ich auch als buggy.)


Gruß Robert
Heinrich Schramm
2006-10-17 07:06:53 UTC
Post by Robert Hartmann
Nun sollten aber Interrupts gerade auch laufende Funktionen
unterbrechen, und dann kann es durchaus wichtig sein, dass
eine globale Variable tatsächlich "schrittweise" vergrößert
wird z.B. um innerhalb der ISR herauszufinden,
bei welchem Schleifendurchlauf der Interrupt "auslöste".
Wenn nun die ISR nicht nur lesend auf die globale Variable
zugreifen soll, sondern auch schreibend, macht es einen
noch viel größeren Unterschied, [...]
Warum deklarierst du die globale Variable nicht als "volatile"?

Gruß Heiner
Robert Hartmann
2006-10-17 08:33:44 UTC
Hallo,
Post by Heinrich Schramm
Post by Robert Hartmann
Nun sollten aber Interrupts gerade auch laufende Funktionen
[...]
Post by Heinrich Schramm
Warum deklarierst du die globale Variable nicht als "volatile"?
mhm ... wenn ich mir das so überlege ... keine Ahnung.

Mit "volatile" unterscheiden sich die Optimierungsstufen 1 bis 2
nicht wirklich von der Version ohne "volatile".

Bei der Optimierungsstufe 3 existiert allerdings ein großer
Unterschied. Die Schleife wird komplett entrollt und jedes
Zwischenergebnis wird direkt an die globale Variable übertragen.

Danke für den Hinweis :-)
Also war der Bug eher einer in meinem Test-Code ...
Fein, hab also wieder etwas gelernt.
Und ich kann mein Test-Ergebnis noch um einen Vergleich erweitern -
prima :-)

Gruß Robert
Stefan Reuther
2006-10-17 07:25:13 UTC
TaX,
Post by Robert Hartmann
Post by Stefan Reuther
welche a_global aufwändig auf 285 setzt, durch den Assemblercode für
a_global = 285
Ok, wenn man annehmen möchte, dass Interrupts laufende Funktionen
nicht unterbrechen dürfen, ist es egal.
Nun sollten aber Interrupts gerade auch laufende Funktionen
unterbrechen, und dann kann es durchaus wichtig sein, dass
eine globale Variable tatsächlich "schrittweise" vergrößert
wird z.B. um innerhalb der ISR herauszufinden,
bei welchem Schleifendurchlauf der Interrupt "auslöste".
Dann machst du die Variable volatile. Wenn sie nicht den Typ
'sig_atomic_t' hat, ist zwar immer noch im Rahmen des C-Standards
nicht definiert, was genau passiert, alle mir bekannten Compiler
sind dahingehend aber "unmagisch" und erzeugen, falls möglich,
den gewünschten Speicherzugriffsbefehl.

Müsste der Compiler das bei jeder Variable annehmen, könnte er
den überwiegenden Teil der Optimierungen gar nicht durchführen.
Post by Robert Hartmann
Wenn nun die ISR nicht nur lesend auf die globale Variable
zugreifen soll, sondern auch schreibend, macht es einen
noch viel größeren Unterschied, ob die Schleife nach Beendigung
der ISR mit dem neuen Wert weiter arbeiten muss oder ob sie
nicht weiter arbeiten kann, da das Schleifenergebnis als fixe
Zahl optimiert wurde.
(Zumindest könnte man auf so ein Verhalten in der Dokumentation
hinweisen, dass man entsprechende Teile eben nicht optimieren
lässt. Fehlende Information empfinde ich auch als buggy.)
'volatile' ist C-Basiswissen. Wer ISRs programmieren will, sollte
das schon kennen. Mit dem Stichwort findet man in der Infodatei
auch ein paar Optionen für Workarounds, um Code, der nicht mit einem
optimierenden Compiler rechnet, durchzubringen.


Stefan
Sven Köhler
2006-10-23 22:19:55 UTC
Post by Robert Hartmann
Post by Stefan Reuther
Post by Robert Hartmann
dass die Optimierungsstufe 3 beim gcc 4.1.1 fehlerhaft ist,
genügend Leser interessieren könnte.
http://www.tu-clausthal.de/~ifrh/gcc_4-1-1_bug_im_optimierer.pdf
Wenn ich das richtig sehe, hat der Compiler die Funktion
void test_global_schleife1() {
int i;
for (int i = 0, a_global = 0; i < 10; ++i)
a_global += i*i;
}
(hat das einen Grund, warum du in dem PDF cut&paste deaktiviert hast?),
(Naja, irgendwie schon :-) Ich, hab vergessen es zu erlauben.)
Post by Stefan Reuther
welche a_global aufwändig auf 285 setzt, durch den Assemblercode für
a_global = 285
Ok, wenn man annehmen möchte, dass Interrupts laufende Funktionen
nicht unterbrechen dürfen, ist es egal.
Nun sollten aber Interrupts gerade auch laufende Funktionen
unterbrechen, und dann kann es durchaus wichtig sein, dass
eine globale Variable tatsächlich "schrittweise" vergrößert
wird z.B. um innerhalb der ISR herauszufinden,
bei welchem Schleifendurchlauf der Interrupt "auslöste".
Also ich sehe es so:

du willst mit dem "-O3" bewirken, dass die Schleife so schnell wie
möglich abgearbeitet wird! Das wird sie ...

Du stellst dich auf den Standpunkt, dass ein "Interrupt" die Funktion
unterbrechen können sollte - kann er ja auch, aber leider nur vor und
nach der Schleife, da sie zu einer Anweisung optimiert wurde und somit
quasi "unendlich schnell" abgearbeitet wird.

Wenn du "sinnvoll" Zeit verschwenden willst, dann bedarf es in jedem
Fall mehr: Zeit messen, einfach sleep() aufrufen oder sowas ...

Das kann dann nicht mehr "wegoptimiert" werden.
Robert Hartmann
2006-10-17 07:16:49 UTC
Post by Stefan Reuther
Wenn ich das richtig sehe, hat der Compiler die Funktion
void test_global_schleife1() {
welche a_global aufwändig auf 285 setzt, durch den Assemblercode für
a_global = 285
Jepp, bei dem MIPS 4kc und auch beim PowerPC 405 hast du recht.
Beim ARM 7 wurde die Schleife durch den Wert 284 ersetzt, um dann
einmal inkrementiert zu werden, damit es auch 285 ist.
Diese Art der Optimierung ist schon sehr seltsam.

Wenn der Optimierer offensichtlich schon weiß,
dass da 285 rauskommen soll, warum macht er es für ARM 7 nicht
genauso wie beim PowerPC oder beim MIPS? *grübel*

Abgesehen davon ist und bleibt das Zusammenspiel mit ISR
zweifelhaft, wahrscheinlich gerade weil die ISR-Programmierung
ungerne beachtet wird ...

Gruß Robert
Michael Engert
2006-10-23 22:13:18 UTC
Post by Robert Hartmann
Jepp, bei dem MIPS 4kc und auch beim PowerPC 405 hast du recht.
Beim ARM 7 wurde die Schleife durch den Wert 284 ersetzt, um dann
einmal inkrementiert zu werden, damit es auch 285 ist.
Diese Art der Optimierung ist schon sehr seltsam.
Wenn der Optimierer offensichtlich schon weiß,
dass da 285 rauskommen soll, warum macht er es für ARM 7 nicht
genauso wie beim PowerPC oder beim MIPS? *grübel*
Je nachdem, mit welchem Assembler-Befehl der Wert in die Variable geladen
wird, werden die Prozessorflags gesetzt oder auch nicht. Wenn sie nicht
gesetzt werden, sorgt die Inkrementierung dafür, daß das passiert. Welchen
Befehl man auf welcher Architektur verwendet, hängt von der Größe und der
Ausführungsgeschwindigkeit der einzelnen zur Auswahl stehenden Befehle ab.

Servus, Michi.
--
Michael Engert, Muenchen ***@engert.org
Rainer Weikusat
2006-10-24 09:02:52 UTC
Post by Michael Engert
Post by Robert Hartmann
Jepp, bei dem MIPS 4kc und auch beim PowerPC 405 hast du recht.
Beim ARM 7 wurde die Schleife durch den Wert 284 ersetzt, um dann
einmal inkrementiert zu werden, damit es auch 285 ist.
Diese Art der Optimierung ist schon sehr seltsam.
Wenn der Optimierer offensichtlich schon weiß,
dass da 285 rauskommen soll, warum macht er es für ARM 7 nicht
genauso wie beim PowerPC oder beim MIPS? *grübel*
Je nachdem, mit welchem Assembler-Befehl der Wert in die Variable geladen
wird, werden die Prozessorflags gesetzt oder auch nicht. Wenn sie nicht
gesetzt werden, sorgt die Inkrementierung dafür, daß das passiert. Welchen
Befehl man auf welcher Architektur verwendet, hängt von der Größe und der
Ausführungsgeschwindigkeit der einzelnen zur Auswahl stehenden Befehle ab.
Bis auf x86 sind das alles RISC-CPUs, dh alle Befehle haben dieselbe
Groesse (genau weiss ich das nur fuer ARM, aber es waere ueblich),
naemlich ein Maschinenwort. 'Ausfuehrungsgeschwindigkeit der Befehle'
gibt es fuer ARM allgemein nicht, weil das nur eine CPU-Spezifikation
ist, deren konkrete Implementierung Lizenznehmer von ARM
Ltd. bestimmen. Im uebrigen ist das fuer CPUs mit pipeline bei weitem
nicht so simpel.
Jens Müller
2006-10-27 07:20:40 UTC
Post by Rainer Weikusat
'Ausfuehrungsgeschwindigkeit der Befehle'
gibt es fuer ARM allgemein nicht, weil das nur eine CPU-Spezifikation
ist, deren konkrete Implementierung Lizenznehmer von ARM
Ltd. bestimmen.
Öhm - lizensieren die nicht nicht nur die Spezifikation, sondern ganze
Cores?
Rainer Weikusat
2006-10-27 08:40:15 UTC
Post by Jens Müller
Post by Rainer Weikusat
'Ausfuehrungsgeschwindigkeit der Befehle'
gibt es fuer ARM allgemein nicht, weil das nur eine CPU-Spezifikation
ist, deren konkrete Implementierung Lizenznehmer von ARM
Ltd. bestimmen.
Öhm - lizensieren die nicht nicht nur die Spezifikation, sondern ganze
Cores?
Sie tun beides. Aber ein 'ARM-Prozessor' ist trotzdem einer, der
(unter entsprechener Lizenz) irgendeine der ARM-CPU-Spezifikation
erfuellt. Und die sind, gerade auch in 'optimierungsrelevanten'
Details dann doch sehr unterschiedlich (konkret habe ich zZt mit zwei
ARM9-Implementierungen zu tun).

Juergen Ilse
2006-10-16 12:56:26 UTC
Hallo,
Post by Robert Hartmann
ja, ich weiß dass es in dieser Gruppe um die Sprache C
geht und nicht um Compilerspezifika.
Allerdings glaube ich, dass ein kurzer Hinweis,
dass die Optimierungsstufe 3 beim gcc 4.1.1 fehlerhaft ist,
genügend Leser interessieren könnte.
Das "wegoptimieren von Funktionen, die gemaess ihrer Spezifikation keine
Nebenwirkungen haben" ist kein Fehler. Das aendern der Reihenfolge von
Funktionsaufrufen ist dem Compiler ebenfalls erlaubt, solange das Ergebnis
noch dem entspricht, was der Standard spezifiziert. Das Schluesselwort
"register" muss auch keine sichtbare auswirkung auf den Code haben. Die
Unterstuetzung von Moeglichkeiten, "Interrupt-Funktionen" in C zu schreiben,
wird ebenfalls von C-Standard nicht garantiert. Ich sehe also erst einmal
nichts, was man von deinen Feststellungen wirklich als Fehler des Compilers
bezeichnen koennte, denn nichts von deinen speziellen Erwartungen bzgl. des
generierten Codes wird vom C-Standard garantiert.
Post by Robert Hartmann
Für den Bug-Report muss ich noch meinen Text
http://www.tu-clausthal.de/~ifrh/gcc_4-1-1_bug_im_optimierer.pdf
ins Englische übersetzen und evtl. noch etwas an der Formulierung basteln.
Schreib doch mal, was du bzgl. dieses Bugreports von den Entwicklern
zu hoeren bekommst, das waere bestimmt amuesant ...

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Robert Hartmann
2006-10-17 06:38:09 UTC
Moin moin,
Post by Juergen Ilse
Hallo,
Die Unterstuetzung von Moeglichkeiten, "Interrupt-Funktionen" in C zu schreiben,
wird ebenfalls von C-Standard nicht garantiert.
Leider richtig, warum auch immer ISR-Programmierung nicht in den
C-Standard aufgenommen wurde. Wo doch gerade die Interruptbehandlung
in der hardwarenahen Programmierung recht wichtig ist.
Und nur wenige werden mir hoffentlich widersprechen, wenn ich sage,
dass C eine doch sehr hardwarenahe Sprache ist.
(Gut, da kann man den Compiler-Bauern nichts vorwerfen.)

Und dass eine Funktion, die eine globale Variable, welche dann in der
ISR benutzt werden soll, verändert, anders optimiert wurde als ich mir
das gewünscht hätte, ist nur insofern buggy, dass im optimierten Code
nicht herausgefunden werden kann, in welchem Schleifendurchlauf
der Interrupt auslöste. Aber wenn es wichtig ist, dass man es können
muss, sollte man schon gesagt bekommen, dass man dann nicht optimieren darf.
Besonders ist es wichtig, wenn nun die ISR nicht nur lesend auf die
globale Variable zugreifen soll sondern auch schreibend.
Dann macht es einen noch viel größeren Unterschied, ob die Schleife
nach Beendigung der ISR mit dem neuen Wert weiter arbeiten muss oder
ob sie nicht weiter arbeiten kann, da das Schleifenergebnis als fixe
Zahl optimiert wurde.

Auch ein Hinweis, dass gerade auch Prozessoren, die im
Embedded Bereich oder in Echtzeitsystemen eingesetzt werden,
ISR-mäßig nicht unterstützt werden, könnte man schon gerne sehen ...
(Nur weil es in der Doku nicht steht, heißt es ja nicht, dass es nicht
geht.)

[...]
Post by Juergen Ilse
Schreib doch mal, was du bzgl. dieses Bugreports von den Entwicklern
zu hoeren bekommst, das waere bestimmt amuesant ...
Ich freue mich immer, wenn ich zur Erheiterung anderer beitragen kann :-)

Robert
Rainer Weikusat
2006-10-17 09:19:49 UTC
Post by Robert Hartmann
Post by Juergen Ilse
Die Unterstuetzung von Moeglichkeiten, "Interrupt-Funktionen" in C zu schreiben,
wird ebenfalls von C-Standard nicht garantiert.
Leider richtig, warum auch immer ISR-Programmierung nicht in den
C-Standard aufgenommen wurde. Wo doch gerade die Interruptbehandlung
in der hardwarenahen Programmierung recht wichtig ist.
'Interruptbehandlung' ist fuer Leute mit numerischen Problemen, die
aus irgendeinem Grund kein Fortran benutzten (eventuell, weil es gar
nicht moeglich waere --- kenne ich mich nicht naeher mit aus)
vollkommen uninteressant (insbesondere, falls diese auch noch die
Angewohnheit haben, schon einfache Dinge so umstaendlich wie irgend
moeglich zu implementieren).
Post by Robert Hartmann
Und nur wenige werden mir hoffentlich widersprechen, wenn ich sage,
dass C eine doch sehr hardwarenahe Sprache ist.
Die Intention liegt jedenfalls eher auf 'hardwareunabhaengige
Sprache' und das 'hardwarenah' soll bloss einen Uebersetzung zu
'schnellem' Maschinencode ermoeglichen.
Post by Robert Hartmann
Und dass eine Funktion, die eine globale Variable, welche dann in der
ISR benutzt werden soll, verändert, anders optimiert wurde als ich mir
das gewünscht hätte, ist nur insofern buggy, dass im optimierten Code
nicht herausgefunden werden kann, in welchem Schleifendurchlauf
der Interrupt auslöste.
Der Code hat nach 'C' keine Seiteneffekte. Also darf er durch welchen
ersetzt werden, der dasselbe Ergebnis auf eine andere Weise ermittelt.
Claus Reibenstein
2006-10-17 16:46:55 UTC
Post by Robert Hartmann
Post by Juergen Ilse
Die Unterstuetzung von Moeglichkeiten, "Interrupt-Funktionen" in C zu schreiben,
wird ebenfalls von C-Standard nicht garantiert.
Leider richtig, warum auch immer ISR-Programmierung nicht in den
C-Standard aufgenommen wurde.
Weil Interrupts auf jedem System anders funktionieren und entsprechend
unterschiedlich gehandhabt werden müssen. Weil es selbst auf einem
System verschiedene Arten von Interrupts geben kann.
Post by Robert Hartmann
Und nur wenige werden mir hoffentlich widersprechen, wenn ich sage,
dass C eine doch sehr hardwarenahe Sprache ist.
Das ist richtig. Trotzdem ist sie noch weit von Assembler entfernt.
Nicht jedes Maschinenkommando hat eine Entsprechung in C.
Post by Robert Hartmann
Und dass eine Funktion, die eine globale Variable, welche dann in der
ISR benutzt werden soll, verändert, anders optimiert wurde als ich mir
das gewünscht hätte, ist nur insofern buggy, dass im optimierten Code
nicht herausgefunden werden kann, in welchem Schleifendurchlauf
der Interrupt auslöste.
Speziell für solche Fälle wurde volatile eingeführt. Damit sagt man dem
Optimizer, dass er davon bitte die Finger zu lassen hat.

Gruß. Claus