Forum: Compiler & IDEs extended assembler gcc Tricore Register fail


von squierrel (Gast)


Lesenswert?

Hallo,
folgender TRICORE Extended inline Assembler:
1
__asm("mov %%d4, %0" : : "d" (parameter)); /* C variable parameter */

Produziert:
1
mov  %d15, -1
2
mov  %d4, %d15

Nur das auf d15 noch Daten vom Compiler abgelegt sind, welche noch 
gebraucht werden. Wie schreibe ich das richtig?
Ich dachte, wenn es zu so einer zusätzlichen Register Nutzung im 
Extended Assembler kommt, wird das entsprechende Register automatisch 
gesichert?


Stecke nicht so ganz in dem Intermixing drin … wenn ich mal Assembler 
mache, dann in der Regel direkt in einer Assembler Datei.

Danke schon mal für jedwede Aufklärung!

von squierrel (Gast)


Lesenswert?

Oder ist das ein gcc Fehler? Gab es nicht auch mal beim AVR gcc das 
Problem, dass r0 nicht wieder genullt wurde obwohl in der Clobber Liste 
definiert?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

squierrel schrieb:
> Hallo,
> folgender TRICORE Extended inline Assembler:
>
1
__asm("mov %%d4, %0" : : "d" (parameter)); /* C variable 
2
> parameter */
>
> Produziert:
>
1
mov  %d15, -1
2
> mov  %d4, %d15

Nö, das asm produziert nur eine Instruktion, nämlich "mov %d4, ...". 
Die -1 in D15 wird aus irgend einem anderen Grund geladen; der Grund ist 
aus dem unvollständigen Beispiel jedoch nicht ersichtlich.  Welche 
Instruktionen vom asm erzeugt werden und welche nicht ist im .s-File 
ersichtlich, erzeigt z.B. oer -save-temps.

> Nur das auf d15 noch Daten vom Compiler abgelegt sind, welche noch
> gebraucht werden. Wie schreibe ich das richtig?

Auf D15 wird nur lesend zugegriffen, es muss also nicht gesichert 
werden: Nach dem asm enthält es immer noch -1 bzw 255.  Dass D4 
verändert wird muss dem Compiler hingegen mitgeteilt werden, entweder 
durch Verwenden eines benanntes Register oder indem D4 zu den Clobbers 
hinzugenommen wird.

> Ich dachte, wenn es zu so einer zusätzlichen Register Nutzung im
> Extended Assembler kommt, wird das entsprechende Register automatisch
> gesichert?

Ich verstehe nicht was mit "zusätzlicher" Registernutzung gemeint ist. 
Alle Register müssen entweder durch Constraints oder Clobbers 
beschrieben sein oder sie müssen fixed sein, d.h. nicht vom 
Register-Allokator verwaltet.

squierrel schrieb:
> Oder ist das ein gcc Fehler?

Mit 99.999% Wahrscheinlichkeit: Nein.  Aufgrund des unvollständigen 
Testfalls ist keine Aussage möglich.

> Gab es nicht auch mal beim AVR gcc das Problem, dass r0 nicht
> wieder genullt wurde obwohl in der Clobber Liste definiert?

R0 und R1 sind bei avr-gcc Fixed Register, d.h. sie werden implizit 
verwendet und nicht vom Register-Allokator verwaltet.  Es ist also 
kein Problem des Compilers sondern ergibt sich aus dem ABI:

http://gcc.gnu.org/wiki/avr-gcc#Register_Layout

von squierrel (Gast)


Lesenswert?

Hallo,
danke schon mal fürs draufschauen.
Folgendermaßen sieht der Code im Preprocessed File aus:
1
 s_pS = (ST *)hC;
2
{ __asm("mfcr %d4,0xFE04"); __asm("syscall 0x3"); __asm("disable"); __asm("mtcr 0xFE04,%d4"); __asm("mov %d4, 0"); __asm("mov.a %%a3,%0" : :"d" (&s_p->pContext->contextFrame.LowerCtx)); __asm("mov.a %%a6,%0" : :"d" (&s_p->pContext->contextFrame.UpperCtx)); __asm("stucx [%a6]0"); __asm("stlcx [%a3]0"); __asm("mov.d %d1,%a11" ); __asm("jl 4"); __asm("mov.d %d2,%a11" ); __asm("add %d2,%d2,12"); __asm("st.w [%a3]4,%d2"); __asm("mov.a %a11,%d1" ); __asm("st.w [%0], %%d4"::"a"(&iResult) ); __asm("mfcr %d1,0xFE04"); __asm("syscall 0x3"); __asm("enable"); __asm("mtcr 0xFE04,%d1"); };
und der *.s Code:
1
.uleb128 0x6e
2
  .ascii  "RESTORE_CONTEXT(context,parameter) { __asm(\"mfcr %d"
3
  .ascii  "2,0xFE04\"); __asm(\"syscall 0x3\"); __asm(\"disable\"); __a"
4
  .ascii  "sm(\"mtcr 0xFE04,%d2\"); __asm(\"svlcx\"); __asm(\"rslcx\");"
5
  .ascii  " __asm(\"mov.a %%a3,%0\" : :\"d\" (&context.LowerCtx)); __as"
6
  .ascii  "m(\"mov.a %%a6,%0\" : :\"d\" (&context.UpperCtx)); __asm(\"l"
7
  .ascii  "dlcx [%a3]0\"); __asm(\"lducx [%a6]0\"); __asm(\"mov %%d4, %"
8
  .ascii  "0\" : : \"d\" (parameter)); __asm(\"ld.w %d2,[%a6]0\""

Der Schnipsel ist nicht von mir muss ich noch dazusagen, … und war nur 
ein schnell gehackter Code von einem Zulieferer, der mit weiteren 
Fehlern für die Verwendung hier behaftet ist. Alle anderen Probleme die 
Auftreten sind mir klar, aber das mit dem mov %d15, -1 verwunder mich 
doch. Die C-Variablen Namen habe ich abgeändert, damit der Zulieferer 
nicht erkennbar ist.

Jetzt noch der Assembler Code aus dem objectfile:
1
  80:  49 60 40 09   lducx [%a6]0
2
  84:  82 ff         mov %d15,-1
3
  86:  02 f4         mov %d4,%d15
4
  88:  54 62         ld.w %d2,[%a6]

von squierrel (Gast)


Lesenswert?

… sorry, einmal mit den Files durcheinandergeraten Korrektur folgt!

von squierrel (Gast)


Lesenswert?

Das korrekte *.s welches jetzt auch oben zu den Ausgaben passt.
1
#APP
2
  # 118 "R:/TestBranch/Components_Integration/Xyz/Module/Test/CtxTimer/Test_Ctx.c" 1
3
  mov.a %a6,%d15
4
  # 0 "" 2
5
  # 118 "R:/TestBranch/Components_Integration/Xyz/Module/Test/CtxTimer/Test_Ctx.c" 1
6
  ldlcx [%a3]0
7
  # 0 "" 2
8
  # 118 "R:/TestBranch/Components_Integration/Xyz/Module/Test/CtxTimer/Test_Ctx.c" 1
9
  lducx [%a6]0
10
  # 0 "" 2
11
#NO_APP
12
  mov  %d15, -1
13
#APP
14
  # 118 "R:/TestBranch/Components_Integration/Xyz/Module/Test/CtxTimer/Test_Ctx.c" 1
15
  mov %d4, %d15
16
  # 0 "" 2
17
  # 118 "R:/TestBranch/Components_Integration/Xyz/Module/Test/CtxTimer/Test_Ctx.c" 1
18
  ld.w %d2,[%a6]0

von squierrel (Gast)


Lesenswert?

Ich denke ich weiß woran es liegt.
Wenn ich zeitlich etwas Zeit habe poste ich mal noch die Auflösung.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

squierrel schrieb:
> Das korrekte *.s welches jetzt auch oben zu den Ausgaben passt.

Passt immer noch nicht zum gezeigten asm, das z.B. kein LDLCX enthält. 
Aber egal, das nicht gezeigte asm enthält wahrscheinlich nicht weniger 
Fehler als das obige.  Als da wären:

Problem #1: Das asm muss als ein asm Statement formuliert werden, denn 
ansonsten kann der Compiler beliebig viele Instruktionen zwischen die 
einzelnen asm bauen wie er eben braucht. Ein Beispiel für eine solche 
eingestreute Instruktion ist "mov %d15,-1": Der Compiler beendet die 
vorherigen asms mit #NO_APP, fügt dann Instruktion(en) ein und fährt 
dann mit #APP fort.

Problem #2: Effekt der asm auf Register oder Speicher wird nicht 
beschrieben. Zum Beispiel zerstört "mov.a %%a6,%0" den Inhalt von A6. 
Falls der Compiler einen Wert in dem Register hält wird dieser zerstört. 
I.d.R. sollte dem Compiler die Wahl der Register überlassen werden, also 
z.B:
1
int tmp;
2
__asm volatile ("stlcx [%1]0"    "\n\t"
3
                "..."            "\n\t"
4
                "mov.d %0,%a11"  "\n\t"
5
                "add %0,%0,12"   "\n\t"
6
                "st.w [%1]4,%0"
7
                : "=&d" (tmp)
8
                : "a" (&s_p->pContext->contextFrame.LowerCtx)
9
                : "memory");
Falls wie hier eine ABI mit bestimmten Registern involviert ist, kann 
man benannte lokale Register verwenden oder man muss die Register zu den 
Clobbers hinzunehmen:
1
int tmp register asm ("d2");
2
__asm volatile ("stlcx [%%a6]0"   "\n\t"
3
                "..."             "\n\t"
4
                "mov.d %0,%a11"   "\n\t"
5
                "add %0,%0,12"    "\n\t"
6
                "st.w [%%a6]4,%0"
7
                : "=d" (tmp) :: "a6", "memory");

Problem #3: Speicher wird verändert, daher muss "memory" zu den 
Clobbers.

Problem #4: Das asm ist volatile, siehe mein Beispiel.

Problem #5: Es wird der Kontext der Funktion geändert, evtl. muss die 
Funktion, in dem der Code verwendet wird, also Attribut "noinline" 
bekommen (und evtl. das Modul -fno-inline-functions-unsed-once).  Bei 
Inlining wird ansonsten auf den Kontext des Callers bezogen.

Problem #6: Um Wartbarkeit und Lesbarkeit zu verbessern, SFR-Bezeichner 
wie $PSW verwenden statt 0xFE04.

von squierrel (Gast)


Lesenswert?

Hallo Johann,
hätte ich doch nochmal reingeschaut, dass mit den SFR Bezeichnern war 
jetzt noch meine letzte Nachträgliche Änderung.
Den alten Code habe ich komplett entsorgt.

Aber noch Danke fürs reinschauen.

So, etwas wirr zusammengeschrieben:
Das d15 Problem kam daher, das von Funktion x mal eben in Funktion y 
gesprungen wurde. Was aus meinen Schnipseln so nicht wirklich zu 
erkennen war. In Funktion sagen wir y wurde d15 natürlich nicht 
verwendet und mit -1 für Funktion x verfälscht. Das ist alles im Test 
passiert. Im Standardablauf existiert das Verhalten so nur im Fehlerfall 
(mit dem Funktionswechsel) … macht die Sache jetzt nicht unbedingt 
besser. Zudem wird im Original d15 nicht verwendet -> normalerweise hat 
alles richtig funktioniert und es hat sich niemand mehr darum gekümmert.

Aber schön das dieser Zulieferer Hack (finale korrekte Implementierung 
war klar unsere Aufgabe), so lange unentdeckt im Code geschlummert hat.

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.