Forum: Compiler & IDEs Switch Case compiler übersetzung in asm. fehlerhaft


von alex (Gast)


Lesenswert?

Hallo Community,
Wieso kompiliert AVR GCC(AVR Studio 5) meine Switch Case Anweisung(ca. 
16 cases) nicht in eine Mehrfachverzweigung (Sprungtabelle) sondern in 
lauter cpi,breq ?
Wie kann ich den Compiler davon überzeugen eine Mehrfachverzweigung mit 
ijmp zu nehmen?


disassembler Ausschnitt:
1
00000121  LDS R24,0x01A2    Load direct from data space 
2
00000123  MOV R24,R24    Copy register 
3
00000124  LDI R25,0x00    Load immediate 
4
00000125  CPI R24,0x08    Compare with immediate 
5
00000126  CPC R25,R1    Compare with carry 
6
00000127  BRNE PC+0x02    Branch if not equal

Ausschnitt aus meinem C- Code
1
switch (TWICSM_cnt)            //
2
{
3
4
  case Wii_NeWayInit_6_1_CMD:
5
  /***** 6/1) I2C- Multiplexer(PCA9548) auf Kanal 0 umschalten *****/
6
  if (!(CHECKBIT(PCA9548_State,PCA9548_ch0_sel))) // 
7
  {
8
  TWI_Start_Transceiver_With_Data(send_me,2);    // Multiplexer auf Kanal 0 umstellen
9
  TWICSM_next_task(Wii_NeWayInit_6_2_CMD);      // Verkettete Aufgabenfolge
10
  }
11
  else
12
  {
13
    TWICSM_next_task(Wii_NeWayInit_6_3_CMD);    // Multiplexer Umschaltvorgang überspringen. Fortsetzen mit "New Way Init1".
14
  }
15
  break;
16
  
17
  case Wii_NeWayInit_6_2_CMD:            // Prüfen ob Daten an den Multiplexer übertragen werden konnten.
18
  if (0==TWI_Transceiver_Busy())          // TWI Sendevorgang abgeschlossen?
19
  {

von Lars R. (larsr)


Lesenswert?

Hallo Alex,

Ich bin mir ziemlich sicher, dass die Übersetzung nicht fehlerhaft ist. 
Der Compiler halt halt lediglich eine andere Wahl getroffen, deinen Code 
in Maschinensprache umzusetzen, als du es dir erhofft hast.


Viele Grüße,

Lars

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ich sehe nicht was daran falsch sein soll.

Ist Optimierung an?

Ändert sich was mit -mcall-prologues?

von Cyblord -. (cyblord)


Lesenswert?

Manche Leute haben echt ne verquere Ansicht zum Begriff "fehlerhaft". 
Fällt darunter jetzt schon alles was dem eigenen Geschmack nicht 
entspricht?

von alex (Gast)


Lesenswert?

@ Johann L.
ich finde es nicht richtig, wenn statt einer einfachen Sprungleiste, ca. 
60 Zeilen bestehend aus cpi,cpc,breq + rjmps entstehen. Dies wirkt sich 
negativ als auf die codedichte, so auch auf die CPU-Zeit aus.
Mit Optimierungen kenne ich mich nicht aus. In den meisten Fällen sind 
diese ausgeschaltet(none) oder -s, wenn code gespart wird. Beide 
Einstellungen haben in diesen Fall keine Auswirkung auf die 
realisierung(kompilierung) der switch case Anweisung.

von Noname (Gast)


Lesenswert?

Naja. So ernst darf man das nicht nehmen. Als Anfänger wählt man schon 
mal das falsche Wort oder nimmt seine eigenen Annahmen darüber was 
"richtig" ist wichtiger als es angemessen ist.

Ich mag mich darin irren, das der TO ein Anfänger ist, aber dann würde 
mich interessieren, nach welchen Maßstäben er feststellt, das hier ein 
Fehler vorliegt bzw. welche Annahmen bzgl. einer "richtigen" Übersetzung 
er hier für korrekt hält.

Die Tatsache alleine, das im Quellcode ein switch vorkommt rechtfertigt 
jedenfalls nicht die Annahme das dies in eine Sprungtabelle umgesetzt 
werden muss um optimalen oder "richtigen" Code zu erzeugen.

Bitte erkläre Dich mal etwas ausführlicher, TO. Entweder lernen wir was 
draus oder Du.

von Noname (Gast)


Lesenswert?

Inzwischen hast Du Johann geantwortet und ein weiteres Detail genannt, 
das es Dich annehmen lässt das eine Sprungtabelle hier das "richtige" 
ist.

Nun ist die Anzahl der cases alleine auch kein Maßstab dafür. Wenn 
beispielsweise die cases keine oder nicht genug aufeinanderfolgenden 
Werte betreffen kann diese breq doch besser sein.

von alex (Gast)


Lesenswert?

@Noname (Gast)
Den größten Teil meines Wissens habe ich diesen Forum zu verdanken.
Im Artikel Mehrfachverzweigungen ( 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Mehrfachverzweigung 
) steht, dass switch case –Anweisungen durch Sprungleisten realisiert 
werden, wodurch bei mir die Erwartung entstand im disassembler auch 
solche vorzufinden.
Besteht den eine Möglichkeit den Compiler auf Sprungleisten umzustellen?

von Noname (Gast)


Lesenswert?

>Im Artikel Mehrfachverzweigungen (...) steht, dass switch case >–Anweisungen 
durch Sprungleisten realisiert
>werden, ...

Ganz genau sooo, steht das aber da nicht. ;-)

Vielmehr wurde das auf bestimmte Fälle eingegrenzt:
>Oft liegen die einzelnen Vergleichswerte nebeneinander (z. B. 7..15), ...
>In so einem Fall kann man mittels einer Sprungtabelle das Programm >verkürzen, 
beschleunigen

Das habe ich eben oben erwähnt.

Die Frage ist ob so ein Fall bei Dir vorliegt.

>Besteht den eine Möglichkeit den Compiler auf Sprungleisten umzustellen?
Das macht keinen Sinn. Es hängt eben, wiegesagt, von einigen Faktoren 
ab.

von Noname (Gast)


Lesenswert?

Es wäre eine ganz nützliche Übung das mal selbst in Assembler zu 
schreiben.

Was kommt dabei heraus:

A) 0, 1, 2, 3, 4,....
B) 17, 18, 19, 20, ...
C) 45, 68, 112, 10024,...
D) 0, 1, 2, 3, 4, 16, 17, 18, 19

Die ganz abgef... hier, wie P. Dannegger, oder vielleicht ich fangen 
dann auch noch an, die Zeit die in den Fällen B und D nötig ist um 
mittels Subtraktion den Wert auf die Tabelle auszurichten mit ausführung 
mittels breq-Kette zu vergleichen. Und wenn das Fernsehprogramm schlecht 
ist oder das Ganze bezahlt wird noch festzustellen, ob es gewisse 
Häufigkeitsverteilungen gibt, die jeweils die eine oder andere Methode 
oder Mischungen daraus ratsam machen.

Also so ganz trivial und mit einer einzigen Aussage zu erschlagen ist 
das ganze nicht.

von alex (Gast)


Lesenswert?

@Noname
Diese Codeschnipsel beinhaltet die einzelnen cases:
1
/***** Nunchuck1 Init *****/
2
#define     Wii_NeWayInit_6_1_CMD   0x01    // 
3
#define     Wii_NeWayInit_6_2_CMD   0x02    // 
4
#define     Wii_NeWayInit_6_3_CMD   0x03    // 
5
#define     Wii_NeWayInit_6_4_CMD   0x04    // 
6
#define     Wii_NeWayInit_6_5_CMD   0x05    //
7
#define     Wii_NeWayInit_6_6_CMD   0x06    //
8
/*****  ID- Anfrage *****/
9
#define     Wii_IdReq_4_1_CMD       0x07    //
10
#define     Wii_IdReq_4_2_CMD       0x08    //
11
#define     Wii_IdReq_4_3_CMD       0x09    //
12
#define     Wii_IdReq_4_4_CMD       0x0A    //
13
/***** Parameter Anfrage *****/
14
#define     Wii_Ptr_Set_6_1_CMD    0x0B    //  
15
#define     Wii_Ptr_Set_6_2_CMD    0x0C    // 
16
#define     Wii_Ptr_Set_6_3_CMD    0x0D    //  
17
#define     Wii_Ptr_Set_6_4_CMD    0x0E    //  
18
#define     Wii_Ptr_Set_6_5_CMD    0x0F    //  
19
#define     Wii_Ptr_Set_6_6_CMD    0x10    //

Alle cases sind aufeinanderfolgend angeordnet, deshalb kann ich's nicht 
verstehen, wieso cpi,breq sinnvoller sein soll.

von (prx) A. K. (prx)


Lesenswert?

Hättest du mal ein übersetzbares Beispiel, wo es falsch ist, und die 
Version vom GCC? Mit dem avr-gcc 4.5.3, der hier grad rumliegt, ist eher 
die umgekehrte Richtung interessant, d.h. er produziert ineffiziente 
Tables, obwohl so ziemlich jede Alternative besser wäre.

von (prx) A. K. (prx)


Lesenswert?

Noname schrieb:

>>Besteht den eine Möglichkeit den Compiler auf Sprungleisten umzustellen?

> Das macht keinen Sinn. Es hängt eben, wiegesagt, von einigen Faktoren
> ab.

Doch, das könnte schon möglich sein. So gibt es mindestens einen 
Schalter für die umgekehrte Richtung, nämlich -fno-jump-tables. 
Ausserdem gibt per --param definierbare Parameter wie 
"case-values-threshold", mit denen sich die interne Heuristik zur 
Entscheidung der Codegenerierung möglicherweise beeinflussen lässt.

von Noname (Gast)


Lesenswert?

Aha. So ist das.

Und das sind alle Werte?

Ist für den Compiler erkennbar, das dies alle überhaupt auftretenden 
Werte sind?

Mir fällt auf, das im Assemblercode ein 16-Bit Vergleich gemacht wird.
Was hat TWICSM_cnt für einen Datentyp?

Wie gross ist das grösste Codestück in den Cases?

von alex (Gast)


Lesenswert?

Noname schrieb:
> Also so ganz trivial und mit einer einzigen Aussage zu erschlagen ist
> das ganze nicht.

Schade :-(
Ich finde diese Compilierungs- Geschichte ziemlich doof, weil meine 
Zielanwendung auf Energie sparen ausgelegt ist, wobei jeder Zyklus als 
Luxusgut eingestuft wird.  Der MC sollte ja schlussendlich möglichst 
lange im Sleepmode verweilen, statt sich mit ultralangen cpi,breqs – 
sich herumprügeln.
Besser hätte ich nie mit assembler bekanntschaft gemacht :-)

von Noname (Gast)


Lesenswert?

A. K. schrieb:
>> Das macht keinen Sinn. Es hängt eben, wiegesagt, von einigen Faktoren
>> ab.
>Doch, das könnte schon möglich sein. So gibt es mindestens einen
>Schalter für die umgekehrte Richtung, nämlich -fno-jump-tables.
>Ausserdem gibt per --param definierbare Parameter wie
>"case-values-threshold", mit denen sich die interne Heuristik zur
>Entscheidung der Codegenerierung möglicherweise beeinflussen lässt.

Ja. Richtig. Da habe ich mich ein wenig weit aus dem Fenster gelehnt.
Ich habe auch so eben daran gedacht, das der gcc in einigen Fällen nicht 
gerade optimalen avr code erzeugt.

von C-Tarzan (Gast)


Lesenswert?

Solange das komplette Listing des TO nicht vorliegt, kann man nur im 
Trüben fischen. Jegliche Aussagen bezüglich des Kompilats sind reine 
Spekulation. warum ein Compiler etwas macht, läßt sich nur aus dem 
GESAMTEN Kontext bewerten.

von Noname (Gast)


Lesenswert?

Ja. Weiteres erübrigt sich auch meiner Meinung nach, solange man keinen 
compilierbaren Code hat bei dem das auftritt.

von Noname (Gast)


Lesenswert?

Meine Güte. Habe mich heute schon wieder so über den IAR für ARM 
geärgert das ich gcc schon wieder schöner finde, als er ist. Ersterer 
macht Sprungtabllen wo immer es ein freies Byte gibt. :-)

von alex (Gast)


Lesenswert?

Noname schrieb:
> Mir fällt auf, das im Assemblercode ein 16-Bit Vergleich gemacht wird.
> Was hat TWICSM_cnt für einen Datentyp?

Deine Feststellung ist richtig! der macht die ganze Zeit 16-Bit 
Vergleiche, wobei im R25 eine 0 steht, weshalb auch 8-Bit Vergleiche 
(cpi) ausreichen würden. Der Counter ist vom Typ uint8_t.

Das ist ein Case mit den meisten Codezeilen:
1
  /***** Wii Controller ID Pointer Set *****/
2
case Wii_IdReq_4_1_CMD:              // ID Pointeradresse 0xFA setzen
3
  memcpy_P(tmparray,WiiInDev_IdPtr_Set,2);      // Kopiere von Flash -> SRAM
4
  TWI_Start_Transceiver_With_Data(tmparray,2);    // 
5
  TWICSM_next_task(Wii_IdReq_4_2_CMD);        // Nächste Aufgabe
6
   break;
7
   
8
   case Wii_IdReq_4_2_CMD:              // Status Auswertung
9
  if (0==TWI_Transceiver_Busy())            // TWI Sendevorgang abgeschlossen?
10
  {  
11
    if (TWI_MTX_DATA_ACK==TWI_Get_State_Info())    // TWI Sendestatus anfordern
12
    {
13
      TWICSM_next_task(Wii_IdReq_4_3_CMD);  // Nächste Init
14
    }
15
    else
16
    {
17
      WiiCTRL_error_cnts.ID_Point_set++;          // Fehler Protokolierungszähler +1
18
      if ( WiiCTRL_error_cnts.ID_Point_set >= Wii_InDev_IDPtrSet_err_max)
19
      {
20
        TWICSM_delete_task(Wii_IdReq_4_1_CMD);  // Aufgabe beenden
21
      }
22
      else
23
      {
24
        TWICSM_next_task(Wii_IdReq_4_1_CMD);  // Sendevorgang wiederhole
25
      }
26
    }  
27
  }   
28
   break;

von Noname (Gast)


Lesenswert?

Hm. Interessant.

"Counter" finde ich ein wenig irritieren. Die defines sehen ja so aus 
als wenn da was empfangen wird. Das könnte bedeuten, das der Compiler 
nicht erkennen kann, das nur ein subset von uint8_t benutzt wird.
Das implizite Verwenden von 16 Bit ist allerdings wirklich ein Problem.

Es sind ja noch Punkte offen.
1. Welche gcc version verwendest Du?
2. Kannst Du bitte mal kompilierbaren Code posten der das Problem zeigt? 
Am besten ein komplettes AVR-Projekt.
3. Poste bitte die Kommandozeile für den Aufruf von gcc.
4. Kann der Compiler erkennen das es sich hier um ein Subset von uint8_t 
handelt? Wenn ja, wie?

Ich esse erstmal was.
Mahlzeit.

von (prx) A. K. (prx)


Lesenswert?

alex schrieb:
> Das ist ein Case mit den meisten Codezeilen:

Es ist völlig unwichtig, wieviele Zeilen hinter den einzelnen case 
labels stehen. Sehr wichtig hingegen ist der komplette Rahmen des switch 
Statements, also der Typ der Variablen und alle Werte der case labels, 
bitte numerisch. Den Code darin kannst du weglassen.

von Noname (Gast)


Lesenswert?

A. K. schrieb:

>Es ist völlig unwichtig, wieviele Zeilen hinter den einzelnen case
>labels stehen.

Meinst Du? Also die C-Zeilen sind wahrscheinlich weniger bedeutsam. Aber 
ich habe überlegt, ob es sein kann, das er es mit den 16-Bit jmps nicht 
mehr schafft aus dem switch herauszukommen und vielleicht deswegen das 
ganze verweigert. Könnte natürlich auch die long jumps nehmen. Aber will 
er oder kann er nicht?

Mag sein, das ich da falsch liege.

von Noname (Gast)


Lesenswert?

Was ist das eigentlich für ein AVR?

von (prx) A. K. (prx)


Lesenswert?

Die Gesamtdistanz kann vielleicht eine Rolle spielen, aber nur in der 
umgekehrten Richtung. Bei kurzen Distanzen werden Einzelvergleiche 
besser und schneller. Folglich kann es sein, dass dann Vergleiche 
gegenüber einer Tabelle gewinnen. Du hast aber schon die Vergleiche, 
trotz viel Code, willst aber eine Tabelle.

Wie sieht denn der komplete erzeugte compare-and-branch Code aus? Ist 
der linear, also compare-branch-compare-branch, oder ist das ein 
Entscheidungsbaum? So ein Baum kann nämlich recht effizient sein.

von Noname (Gast)


Lesenswert?

Hm. Na mal sehen ob wir kompletten Code zu sehen bekommen.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Ich habe gerade ein wenig herumgespielt: Es scheint so zu sein, dass der
GCC für AVRs mit mehr als 8 kiB Flash generell keine Sprungtabellen
generiert, unabhängig von der tatsächlichen Codegröße. 8 kiB ist die
Größe, wo mit RJMP gerade noch jede Stelle im Programmspeicher erreicht
werden kann. Ich habe mit GCC 4.5.3 getestet, neuere Versionen sind
gerade im Bau.

Edit 1: Bei 4.6.3 das gleiche Problem.
        4.7.0 dauert noch etwas, weil der wohl neuere Binutils braucht.

Edit 2: Bei 4.7.0 das gleiche Problem.

von (prx) A. K. (prx)


Lesenswert?

Kann ich grad nicht nachvollziehen. Trotz 4.5.3 (debian). Kommt immer 
der gleiche Table-Switch raus, egal welcher AVR.

von Noname (Gast)


Lesenswert?

Wahn... Hm. Postet mal Code und Optionen. Nicht das Ihr da Eier mit 
Glasaugen vergleicht.

von (prx) A. K. (prx)


Lesenswert?

War mein Fehler. Ungeeigneter Testcode und nicht genau genug hingesehen.

von Yalu X. (yalu) (Moderator)


Lesenswert?

-mshort-calls hilft — zumindest in dem von mir getesteten Fall — weiter.
Möglicherweise gibt es dann Einschränkungen, wenn die Switch-Anweisung
mehr als 8 kiB lang ist, aber so etwas sollte in gut strukturierten
Programmen kaum vorkommen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

alex schrieb:

> Das ist ein Case mit den meisten Codezeilen:

Damit kann man nix anfangen.

1) Die Frage zu -mcall-prologues steht immer noch im Raum.

2) Optimierung vielleicht doch auf "none"? Wir wissen es nicht.

3) Wenn du eine definitive Aussage willst, dann:

A) Was sind die Compilerschalter?
B) Was ist die Compilerversion?
C) Wo ist ein compilierbares Beispiel zum Nachvollziehen?

A, B und C erhält du, indem -v -save-temps zu den Compileroptionen 
zugegeben wird. A, B verrät die Kommandozeile und C wird also i-Datei 
erzeugt; es ist die präprozesierte C-Quelle (Text).

von (prx) A. K. (prx)


Lesenswert?

Ok, besserer Testcode, allerdings kurzer Code. -O2, 4.7.0.
1
int f(char i, int x, int y)
2
{
3
        switch (i) {
4
        case 1: return x+y;
5
        case 2: return x-y;
6
        case 3: return x&y;
7
        case 4: return x|y;
8
        case 5: return x^y;
9
        case 6: return x<<y;
10
        case 7: return x>>y;
11
        case 8: return x*y;
12
        case 9: return x/y;
13
        default: return 0;
14
        }
15
}

Für Mega8 gibts eine Jumptable, insgesamt 23 1-Wort Befehle. Laufzeit 20 
Takte. Bei mehr als 8KB würde sich das auf ca. 34 Worte und 23 Takte 
verlängern.

Für Mega128 gibts einen Entscheidungsbaum mit 20 1-Wort Befehlen. 
Laufzeit zwischen 3 und 12 Takten.

Also: Wer will hier wirklich einen Table-Switch?

PS: Anzahl Befehle und Laufzeit beziehen sich nur auf den switch code 
selbs, nicht auf den Code in den case labels.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?


von (prx) A. K. (prx)


Lesenswert?

Ich würde das Ergebnis von eben so interpretieren: Bei kurzen Sprüngen 
und grossen AVRs ist eine Jumptable nur bei grosser Anzahl von Fällen 
besser als ein Entscheidungsbaum. Sowohl in Länge als auch in Laufzeit. 
Und bis die fixe Laufzeit einer Jumptable kürzer wird als die mittlere 
Laufzeit eines Entscheidungsbaums (O(log(N)) muss die Anzahl Fälle schon 
recht extrem werden.

Ein wesentlich Anteil daran hat der Umstand, dass eine Jumptable bei 
AVRs einen recht heftigen fixen Oberhead hat, der Baum hingegen keinen.

von blub (Gast)


Lesenswert?

Johann L. schrieb:
> Davon rate ich ab.  Das Problem ist da:
> 
http://gcc.gnu.org/viewcvs/branches/gcc-4_7-branch/gcc/config/avr/avr.c?view=markup&pathrev=187343#l9455

Das musst du mir erklären, ich sehe da nur viiiiiel Code...

von Yalu X. (yalu) (Moderator)


Lesenswert?

Johann L. schrieb:
>> -mshort-calls
>
> Davon rate ich ab.  Das Problem ist da:
>
> http://gcc.gnu.org/viewcvs/branches/gcc-4_7-branch...

Das habe ich auch nicht ganz verstanden. In der von dir verlinkten
Codestelle wird, wenn ich das richtig verstehe, die Anzahl der Cases
festgelegt, ab der eine Sprungtabelle verwendet wird.

Aber wie spielt hier -mshort-calls hinein bzw. was kann schlimmstenfalls
passieren, wenn man diese Option benutzt?

Edit:

Wahrscheinlich sollte man bei großen Programmen -mcall-prologues
weglassen, weil der Prolog/Epilog bei -mshort-calls vermutlich mit einem
RCALL aufgerufen wird, der evtl. nicht weit genug reicht.

Aber versuchen kann man -mshort-calls ja immer. Falls dabei etwas schief
läuft, sollte doch der Linker meckern, und man kann die Option dann ja
immer noch zurücknehmen.

Oder gibt es noch weitere Probleme damit?

von (prx) A. K. (prx)


Lesenswert?

alex schrieb:

> Besteht den eine Möglichkeit den Compiler auf Sprungleisten umzustellen?

Es ist das Ziel eines guten Compilers, den im Sinn der gewählten 
Optimierungsstrategie bestmöglichen Code zu generieren. Wenn er zum 
Ergebnis kommt, dass ein compare/branch Schema effizienter ist als eine 
Sprungleiste, weshalb sollte er dann eine Sprungleiste erzeugen?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Johann L. schrieb:
>>> -mshort-calls
>>
>> Davon rate ich ab.  Das Problem ist da:
>> 
http://gcc.gnu.org/viewcvs/branches/gcc-4_7-branch/gcc/config/avr/avr.c?view=markup&pathrev=187343#l9455
>
> Das habe ich auch nicht ganz verstanden. In der von dir verlinkten
> Codestelle wird, wenn ich das richtig verstehe, die Anzahl der Cases
> festgelegt, ab der eine Sprungtabelle verwendet wird.

Es dauert ne Zeit bis sich die Anzeige zur verlinkten Codezeile 
vorgearbeitet hat:
 
1
static unsigned int
2
avr_case_values_threshold (void)
3
{
4
  return (!AVR_HAVE_JMP_CALL || TARGET_CALL_PROLOGUES) ? 8 : 17;
5
}

> Aber wie spielt hier -mshort-calls hinein
 
1
#define AVR_HAVE_JMP_CALL (avr_current_arch->have_jmp_call && !TARGET_SHORT_CALLS)

D.h in die Kostenberechnung gehen -mcall-prologues ein und obs ein JMP 
hat oder nicht.

Gibt's kein JMP oder ist -mshort-calls oder -mcall-prologues gesetzt, 
dann ist der Threshold 8, ansonsten 17.  Ab 4.7 stimmt der Threshold 
nicht mehr, u.a. wegen http://gcc.gnu.org/PR49903
für ältere Versionen wird sich der Autor was dabei gedacht haben, für 
neuere Versionen hat's der Autor verpennt. Mea culpa.

> bzw. was kann schlimmstenfalls passieren, wenn man diese
> Option benutzt? Aber versuchen kann man -mshort-calls ja immer.
> Falls dabei etwas schief läuft, sollte doch der Linker meckern,
> und man kann die Option dann ja immer noch zurücknehmen.

Ja, aber die meisten Anwender verstehen die Linkermeldung nicht, und
daß -mshort-calls ein Problem ist. Um JMP auf RJMP abzubilden falls
möglich sollte man Jump-Relaxing verwenden; allerdings geht das nicht in 
die Kostenberechnung des Compilers ein.

> Wahrscheinlich sollte man bei großen Programmen -mcall-prologues
> weglassen, weil der Prolog/Epilog bei -mshort-calls vermutlich mit
> einem RCALL aufgerufen wird, der evtl. nicht weit genug reicht.

Ob Call-Prologe günstig sind hängt auch von der Anwendung ab. In die 
Kosten für den Prolog geht JMP/RJMP mit den entsprechenden Kosten ein.

von Yalu X. (yalu) (Moderator)


Lesenswert?

@Johann L.

Danke für die Info!

Was mir aber in diesem Zusammenhang überhaupt noch nicht in den Kopf
geht: Warum wird der Case-Threshold von TARGET_CALL_PROLOGUES abhängig
gemacht? Das sind doch zwei völlig verschiedene Dinge.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Übrigens liefert obige Funktion nur die Vorbelegung für 
case-values-threshold. Dies Schräubchen kann zum Beispiel getrimmt 
werden per

--param case-values-threshold=8

o.ä. wobei der Default auf 0 steht, d.h. dann wird der Wert von obiger 
Funktion aus dem avr-gcc verwendet.

Bei Tabellen, die >= case-values-threshold sind, wird eine Sprungtabelle 
erzeugt und ansonsten ein if-else Binärbaum.


Yalu X. schrieb:

> Was mir aber in diesem Zusammenhang überhaupt noch nicht in den Kopf
> geht: Warum wird der Case-Threshold von TARGET_CALL_PROLOGUES abhängig
> gemacht? Das sind doch zwei völlig verschiedene Dinge.

4.6 erzeugt folgenden Code für eine Tabelle mit 17 Einträgen 1..17 und 
unsigned 8-Bit switch (R24):
1
  ldi r25,lo8(0)
2
  sbiw r24,1
3
  cpi r24,17
4
  cpc r25,__zero_reg__
5
  brsh .L23
6
  subi r24,lo8(-(gs(.L41)))
7
  sbci r25,hi8(-(gs(.L41)))
8
  movw r30,r24
9
  lsl r30
10
  rol r31
11
  lpm __tmp_reg__,Z+
12
  lpm r31,Z
13
  mov r30,__tmp_reg__
14
  ijmp

Und mit -mcall-prologues oder 4.7:
 
1
  ldi r25,lo8(0)
2
  sbiw r24,1
3
  cpi r24,17
4
  cpc r25,__zero_reg__
5
  brsh .L23
6
  subi r24,lo8(-(gs(.L41)))
7
  sbci r25,hi8(-(gs(.L41)))
8
  movw r30,r24
9
  jmp __tablejump2__

Warum im alten Compiler nicht immer das  __tablejump2__ aus der libgcc 
verwendet wurde weiß ich auch net. Jedenfalls geht call-prologues immer 
noch in die Kosten ein...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> -mshort-calls hilft — zumindest in dem von mir getesteten Fall — weiter.

Diese Option sollte es gar nicht geben.  Nun hat es auch noch ein
selten dämliches Rin^H^H^HEntwicklerchen geschafft, diese Option in
die GUI vom AVR Studio 5 zu verdrahten.  Die Folge ist, dass die
Leute diesen Mist auch wirklich auswählen und dann natürlich in
Linkerfehler rennen, wenn der Code doch ein bisschen größer wird.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Jörg Wunsch schrieb:
>> -mshort-calls hilft — zumindest in dem von mir getesteten Fall — weiter.
>
> Diese Option sollte es gar nicht geben.

Es ist natürlich i.Allg. nicht sehr sinnvoll, auch alle Unterprogramm-
aufrufe auf short umzustellen, wenn man eigentlich nur eine Switch-
Anweisung optimieren möchte. Da wäre es besser, wenn es eine Option
-mshort-jmptables gäbe, die nur die Switch-Anweisungen beeinflusst,
denn diese sind selten so lang, dass 12 Bit Sprungweite nicht ausrei-
chend wären.

Noch besser wäre es natürlich, wenn der Compiler selbst entscheiden
würde, ob in der Sprungtabelle 12-Bit-Sprünge (RJMP) ausreichen oder ob
es 22 Bits sein müssen (JMP). Bei If-Anweisungen ist er ja sogar in der
Lage, aus drei Alternativen (BRxx (6 Bit), RJMP (12 Bit) und JMP (22
Bit)) die jeweils beste auszuwählen. Nur bei den Jumptables gibt es
diese Unterscheidung wohl (noch) nicht.

> Nun hat es auch noch ein selten dämliches Rin^H^H^HEntwicklerchen
> geschafft, diese Option in die GUI vom AVR Studio 5 zu verdrahten.
> Die Folge ist, dass die Leute diesen Mist auch wirklich auswählen und
> dann natürlich in Linkerfehler rennen, wenn der Code doch ein bisschen
> größer wird.

Naja, wenn es dort wirklich als short-/calls/ angepriesen wird und nicht
als mögliche Optimierung wür Switch-Anweisungen, wird die Versuchung
nicht sehr groß sein, die Option zu aktivieren. Ich habe hier im Forum
jedenfalls noch keine Anfragen von Leuten gesehen, die sich deswegen
plötzlich über seltsame Linkermeldungen wundern.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Ich habe hier im Forum
> jedenfalls noch keine Anfragen von Leuten gesehen, die sich deswegen
> plötzlich über seltsame Linkermeldungen wundern.

Ich schon, zumindest bei avrfreaks.  GUI-Nutzer klicken auf alles,
von dem sie sich erhoffen, dass es ihnen irgendeine Hilfe sein
könnte. :-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Jörg Wunsch schrieb:
> Ich schon, zumindest bei avrfreaks.  GUI-Nutzer klicken auf alles,
> von dem sie sich erhoffen, dass es ihnen irgendeine Hilfe sein
> könnte. :-)

Ok, 1:0 für dich :)

Vielleicht sollte in das GUI ein Eignungstest eingebaut werden, der
immer dann aufgerufen wird, wenn die Option nicht innerhalb der letzten
paar Tage mindestens einmal erfolgreich verwendet wurde ;-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:

> Da wäre es besser, wenn es eine Option -mshort-jmptables gäbe

Johann L. schrieb:

> --param case-values-threshold=8

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.