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


von Peter (Gast)


Lesenswert?

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

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

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?

von Jemand (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


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
von nfet (Gast)


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.

von Peter (Gast)


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:
1
GPIOA->BSRR = 0x00cf0000;
2
GPIOD->BSRR = 0x03000000;
3
GPIOA->MODER &= DATA_MODER_MASK_A;
4
GPIOD->MODER &= DATA_MODER_MASK_D;

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

von Peter (Gast)


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!

von (prx) A. K. (prx)


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.

von Peter (Gast)


Lesenswert?

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

Getriggert wird die Funktion vom EXTI1-Interrupt.

von Bauform B. (bauformb)


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?

von Jemand (Gast)


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.
von Peter (Gast)


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.

von Peter (Gast)


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.

von Jemand (Gast)


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

von (prx) A. K. (prx)


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.

von Peter (Gast)


Lesenswert?

Jemand schrieb:
> /Undefined Behavior/

Achso :-)

Aber was soll da konkret undefined sein?

von (prx) A. K. (prx)


Lesenswert?

Peter schrieb:
> Aber was soll da konkret undefined sein?

Das war Spekulation, keine Erkenntnis aus dem Code.

von Peter (Gast)


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?

von (prx) A. K. (prx)


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
von Peter (Gast)


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. :-)

von (prx) A. K. (prx)


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
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.