arm-none-eabi-gcc unterschlägt ein case 0 im switch?!

Gast #5849606
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?
Gast #5849633
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.
Gast #5849635
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.
Beitrag #5849653 wurde von einem Moderator gelöscht.
Gast #5849656
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.
Gast #5849663
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.
Gast #5849676
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?
#5849691
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren