mikrocontroller.net

Forum: Compiler & IDEs arm-none-eabi-gcc unterschlägt ein case 0 im switch?!


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In meinem Code habe ich eine Switch-Anweisungen:
switch (value >> 13) {
case 0: ...; break;
case 1: ...; break;
case 2: ...; break;
case 3: ...; break;
case 4: ...; break;
case 5: /* fall-thorugh */
case 6: /* fall-thorugh */
case 7: ...; break;
}  // kein default

Nun übersetzt arm-none-eabi-gcc das in
        asrs    r2, r3, #13         ; value in r3
        str     r3, [r4, #3856]
        subs    r2, r2, #1          ; kein Fall 0?!
        cmp     r2, #6              ; **
        bhi     .L1507
        tbh     [pc, r2, lsl #1]
.L1509:
        .2byte  (.L1508-.L1509)/2   ; nur 7 statt 8 Fälle
        .2byte  (.L1510-.L1509)/2
        .2byte  (.L1511-.L1509)/2
        .2byte  (.L1512-.L1509)/2
        .2byte  (.L1513-.L1509)/2   ; 3x identisch wg.
        .2byte  (.L1513-.L1509)/2   ; fall-through
        .2byte  (.L1513-.L1509)/2
        .p2align 1
.L1512:
        ...

Wo ist der Fall 0 abgeblieben? Auch weiter oben im Code gibt es keine 
Behandlung falls value == 0.

Ein weiteres Problem ist, dass value >> 13 durch die Programmlogik nicht 
größer als 7 werden kann und die Prüfung (**) überflüssig ist. Aber 
selbst wenn ich (value >> 13) auf ein enum {_0, ..., _7} caste, bleibt 
die Prüfung (**) im Code. Wie mache ich es richtig?

Autor: Jemand (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es hilft, wenn du nicht die ganzen interessanten Teile von deinem Code 
entfernst.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mal vorausgesetzt, der Asm-Code hat überhaupt etwas mit dem gezeigten 
Quellcode-Abriss zu tun: Kann es sein, dass sich aus dem übrigen Code 
ergibt, dass 0 nicht vorkommen kann?

: Bearbeitet durch User
Autor: nfet (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wo die 0 geblieben ist kann ich dir anhand des gezeigten auch nicht 
sagen. Die Prüfung wirst du aber fürchte nicht weg bekommen. Auf enums 
optimieren die mir bekannten Compiler leider (noch) nicht.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jemand schrieb:
> Es hilft, wenn du nicht die ganzen interessanten Teile von deinem Code
> entfernst.

Naja, da passiert fast immer das gleiche: Es wird ein Wert berechnet. 
Die Ausnahme ist tatsächlich case 0, wo das hier passiert:
GPIOA->BSRR = 0x00cf0000;
GPIOD->BSRR = 0x03000000;
GPIOA->MODER &= DATA_MODER_MASK_A;
GPIOD->MODER &= DATA_MODER_MASK_D;

Und ja, der C-Code paßt zum Asm-Code.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Mal vorausgesetzt, der Asm-Code hat überhaupt etwas mit dem gezeigten
> Quellcode-Abriss zu tun: Kann es sein, dass sich aus dem übrigen Code
> ergibt, dass 0 nicht vorkommen kann?

Doch, kommt regelmäßig vor!

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
>> Es hilft, wenn du nicht die ganzen interessanten Teile von deinem Code
>> entfernst.
>
> Naja, da passiert fast immer das gleiche: Es wird ein Wert berechnet.
> Die Ausnahme ist tatsächlich case 0, wo das hier passiert:

Nicht der Code im Switch ist interessant, sondern der davor.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Nicht der Code im Switch ist interessant, sondern der davor.
value = GPIOB->IDR;
retrigger_flag = 0;

Getriggert wird die Funktion vom EXTI1-Interrupt.

Autor: Bauform B. (bauformb)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Könnte es sein, dass der gcc doch gemerkt hat, dass nur 0 bis 7 
vorkommen können und der case 0 bei .L1507 behandelt wird?

Autor: Jemand (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Nicht der Code im Switch ist interessant, sondern der davor.

Der bei case 0: ist auch interessant. Wenn da UB vorkommt, kann der auch 
einfach so flöten gehen.

Beitrag #5849653 wurde vom Autor gelöscht.
Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bauform B. schrieb:
> Könnte es sein, dass der gcc doch gemerkt hat, dass nur 0 bis 7
> vorkommen können und der case 0 bei .L1507 behandelt wird?

Nur weil die Werte zwischen 0 und 7 liegen, heißt das ja nicht das 0 - 1 
== 7 ist. Der Sprung nach .L1507 kann nur genommen werden, wenn der 
ursprüngliche Wert größer als 7 war.

Der 0-Fall ist mit dem r2 = r2-1 verschwunden.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jemand schrieb:
> Der bei case 0: ist auch interessant. Wenn da UB vorkommt, kann der auch
> einfach so flöten gehen.

Entschuldige, UB? Unterbrechung, also Interrupt?

Durch die Programmlogik kann während der Ausführung der Funktion 
eigentlich kein weiterer IR ausgelöst werden.

Autor: Jemand (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
> Entschuldige, UB? Unterbrechung, also Interrupt?
>
> Durch die Programmlogik kann während der Ausführung der Funktion
> eigentlich kein weiterer IR ausgelöst werden.

Undefined Behavior

Autor: A. K. (prx)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
Peter schrieb:
> Nur weil die Werte zwischen 0 und 7 liegen, heißt das ja nicht das 0 - 1
> == 7 ist.

0-1 = 0xFFFFFFFF und das ist grösser als 6. Da der Compiler weiss, dass 
ein 16 Bit IDR >> 13 nur den Wertebereich 0..7 hat, passt es. GCC 
versucht den möglichen Wertebereich von Daten zu erfassen, um daraus 
Optimierungen abzuleiten.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jemand schrieb:
> /Undefined Behavior/

Achso :-)

Aber was soll da konkret undefined sein?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
> Aber was soll da konkret undefined sein?

Das war Spekulation, keine Erkenntnis aus dem Code.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> 0-1 = 0xFFFFFFFF und das ist grösser als 6. Da der Compiler weiss, dass
> ein 16 Bit IDR >> 13 nur den Wertebereich 0..7 hat, passt es. GCC
> versucht den möglichen Wertebereich von Daten zu erfassen, um daraus
> Optimierungen abzuleiten.

Ja, na klar, Du hast völlig recht, ist ja ein unsigned-Vergleich!

Bei .L1507 steht der Code von Fall 0. Herzlichen Dank für den Tip!

Aber wieso das jetzt eine Optimierung sein soll?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
> Aber wieso das jetzt eine Optimierung sein soll?

Wenn der bekannte Wertebereich exakt mit der Anzahl Fällen 
übereinstimmt, geht es besser. Es schien wohl nicht lohnend, nur dafür 
ein separates Schema im GCC vorzusehen.

: Bearbeitet durch User
Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Bei exakt 2^N Fällen geht es geringfügig besser. Es schien wohl nicht
> lohnend, nur dafür ein separates Schema im GCC vorzusehen.

Ähm, es sind 2^3 Fälle. :-)

Autor: A. K. (prx)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Die Codegenerierung von Switch-Statements enthält einige Grundschemata, 
wie das in Code umgesetzt wird. Also ob als Tabelle, Baum, inkrementelle 
Subtraktion, ... Anhand von Analysen u.A. der Werteverteilung wird eines 
der Schemata ausgewählt. Das wird dann eben schematisch umgesetzt und 
muss nicht immer das absolute Optimum darstellen.

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.