Forum: Compiler & IDEs Inline ASM constrains


von Moritz G. (mbydq2)


Lesenswert?

Ich habe viel Zeit darauf verwandt, die Inline Assembler constrains, zu 
versuchen zu verstehen.
Ich bin zu dem Schluss gekommen, dass viele Quellen ungenügend bis 
falsch sind.
Ich konnte dennoch genug verstehen um ein paar Fragen zu formulieren:

Muss man eine Variable mehr als einmal nennen, wenn sie sowohl Eingabe 
als auch Ausgabe ist, oder reicht ein '+'? (Vermutung: Einmal reicht.)

Sind alle Eingaben read-only, auch wenn sie sich mit '0' ,'1' , ... auf 
ein Ausgaberegister beziehen? (Vermutung: Ja, der Bezug bedeutet dem 
Compiler eine Kopie anzufertigen.)

Muss man alle Ausgaben die nicht auch Eingaben sind, mit einem '=' 
versehen, kann es also kein alleinstehendes "r" als Ausgabe-constraint 
geben? (Vermutung: Das '=' wird nur gebraucht, wenn man sich bei den 
Eingaben auf das selbe Register bezieht, der Compiler beschwert sich 
aber nicht, wenn man dies später unterläßt und das '=' dennoch angibt.)

Beziehen sich die modifier ('+', '=', ...) auf die Variable oder das 
Register? (Vermutung: Auf die Variable.)

Wo ist der Unterschied zwischen
1)
1
:"=r"(var1):"0"(var1)
und
2)
1
:"+r"(var1):"0"(var1)
? (Vermutung:
Es sind beide falsch und müssten:
1.
1
:"=r(var1):"0"(var2)
2.
1
:"+r"(var1)
heißen.)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Moritz G. schrieb:

> Ich bin zu dem Schluss gekommen, dass viele Quellen ungenügend bis
> falsch sind.

Die Constraints kommen ursprünglich aus der Maschinenbeschreibung von 
GCC, siehe Internals:
    http://gcc.gnu.org/onlinedocs/gccint/Modifiers.html#Modifiers

Die Beschreibung
    http://www.rn-wissen.de/index.php/Inline-Assembler_in_avr-gcc#Operanden_und_Constraints

sollte auch korrekt sein, ansonsten bitte sagen, was inkorrekt ist.

> Muss man eine Variable mehr als einmal nennen, wenn sie sowohl Eingabe
> als auch Ausgabe ist, oder reicht ein '+'?

Entweder '+' oder die Variable muss bei den Output- und den 
Input-Operanden genannt werden

> Sind alle Eingaben read-only, auch wenn sie sich mit '0' ,'1' , ... auf
> ein Ausgaberegister beziehen?

Ja.

Diese Constraints dienen dazu, In- und Output in gleiche Register zu 
legen. Das ist bei AVR oft nötig, weil er nur 2-Operanden-Befehle kennt:
1
asm ("add %0,%2"
2
     : "=r" (summe)
3
     : "0" (addend1), "r" (addend2))

> Muss man alle Ausgaben, die nicht auch Eingaben sind, mit einem '='
> versehen, kann es also kein alleinstehendes "r" als Ausgabe-constraint
> geben?

Nein, und der Compiler wird dann auch meckern.

> Beziehen sich die modifier ('+', '=', ...) auf die Variable oder das
> Register?

Auf beide, denn die Variable ist mit dem Register "verknüpft" — 
zumindest zu diesem Zeitpunkt; das kann sich im Coververlauf allerdings 
ändern.

> Wo ist der Unterschied zwischen
> 1)
1
:"=r"(var1) : "0"(var1)
> und
> 2)
1
:"+r"(var1) : "0"(var1)

2) würde ich unterlassen da var1 2× als Output auftaucht. Stattdessen:
3)
1
"+r" (var1)

> 1.
1
:"=r(var1) : "0"(var2)
> 2.
1
:"+r"(var1)

Beide sind ok, sagen aber was anderes. 2. ist gleichbedeutend mit
1
"=r" (var1) : "0" (var1)

Im Zweifelsfalle in die mit -fdump-rtl-asmcons-details erzeugte 
Compilerdump schauen; da ist "+r" durch "=r":"0" ersetzt.

von Moritz G. (mbydq2)


Lesenswert?

Johann L. schrieb:

Danke für die schnelle Antwort.

> Die Constraints kommen ursprünglich aus der Maschinenbeschreibung von
> GCC, siehe Internals:
>     http://gcc.gnu.org/onlinedocs/gccint/Modifiers.htm...
> Die Beschreibung
>     http://www.rn-wissen.de/index.php/Inline-Assembler...
> sollte auch korrekt sein, ansonsten bitte sagen, was inkorrekt ist.

Ich kenne beide Seiten. Zur Korrektheit kann ich z.Z. leider nichts 
beitragen.

>> Muss man eine Variable mehr als einmal nennen, wenn sie sowohl Eingabe
>> als auch Ausgabe ist, oder reicht ein '+'?
> Entweder '+' oder die Variable muss bei den Output- und den
> Input-Operanden genannt werden
> Im Zweifelsfalle in die mit -fdump-rtl-asmcons-details erzeugte
> Compilerdump schauen; da ist "+r" durch "=r":"0" ersetzt.

Es sind also ohne Ausnahme  Zwang  guten Grund zwei Schreibweisen für 
das Selbe? (Ich hasse so etwas.)

>> Muss man alle Ausgaben, die nicht auch Eingaben sind, mit einem '='
>> versehen, kann es also kein alleinstehendes "r" als Ausgabe-constraint
>> geben?
> Nein, und der Compiler wird dann auch meckern.

Verstehe ich nicht. (wieso dann "nein"?)
Ich habe folgende Theorie:

:"=r"(var1):"r"(var2)
hier könnte der Compiler beide variablen zu einem Register machen. Aus:
"befehl %0,%1" würde quasi "befehl %0,%0".

:"r"(var1):"r"(var2)
hier darf nicht das selbe Register verwandt werden, weil %0 
überschrieben werden könnte bevor %1 zum letzten mal gelesen wurde:
mov %0,%1
lsl %0
eor %0,%1

Es macht also eine Unterschied ob man "=r" oder "r" schreibt. Würde man 
immer '=' schreiben müssen, wäre es redundant.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Moritz G. schrieb:
>>> Muss man eine Variable mehr als einmal nennen, wenn sie sowohl Eingabe
>>> als auch Ausgabe ist, oder reicht ein '+'?
>> Entweder '+' oder die Variable muss bei den Output- und den
>> Input-Operanden genannt werden
>> Im Zweifelsfalle in die mit -fdump-rtl-asmcons-details erzeugte
>> Compilerdump schauen; da ist "+r" durch "=r":"0" ersetzt.
>
> Es sind also ohne Ausnahme / Zwang / guten Grund zwei Schreibweisen für
> das Selbe? (Ich hasse so etwas.)

Zeig mir die Programmiersprache, die nur eine einzige Darstellungsweise 
für eine Aufgabe zulässt.

Zudem werden beide Ausdrucksweisen benötogt und keine kann die andere 
vollständig ersetzte — zumindest was die GCC-Interna angeht:
1
"+r" (op)
wird verwendet, wenn Operand op sowohl Ein- als auch Ausgabe ist man 
aber nur einen Operanden hat. In dem Falle ist es folglich nicht 
möglich, op zweiman hinzuschreiben (im Gegensatz zu C/Inline-Assembler)
1
"=r" (op0) : "0" (op1)
Hier können sich op0 und op1 unterscheiden, zB kann op0 ein 16-Bit Wert 
sein und op1 ein 8-Bit Wert. In dem Falle werden op0 und op1 ins gleiche 
Register allokiert. Zumindest für little-Endian wie AVR, auf big-Endians 
sieht das anders aus.

>>> Muss man alle Ausgaben, die nicht auch Eingaben sind, mit einem '='
>>> versehen, kann es also kein alleinstehendes "r" als Ausgabe-constraint
>>> geben?
>> Nein, und der Compiler wird dann auch meckern.
>
> Verstehe ich nicht. (wieso dann "nein"?)

Nein, man kann kein alleinstehended "r" als Ausgabe-Contraint 
vewrwenden. Vielleicht in einen Fragesatz nur eine Frage packen ;-)

> Ich habe folgende Theorie:
>
> : "=r" (var1) : "r" (var2)
> hier könnte der Compiler beide variablen zu einem Register machen. Aus:
> "befehl %0,%1" würde quasi "befehl %0,%0".

Jepp. %0,%1 bedeutet nicht, daß %0 und %1 in unterschiedliche Register 
zu liegen kommen.

> : "r" (var1) : "r" (var2)
> hier darf nicht das selbe Register verwandt werden, weil %0
> überschrieben werden könnte bevor %1 zum letzten mal gelesen wurde:

Wie oben erklärt ist diese Schreibweise nicht möglich und führt zu einer 
Fehlermeldung.

Wenn var1 verändert wird, bevor var2 komplett ausgewertet wurde, sind 
die korrekten Constraints
1
: "=&r" (var1)
2
: "r" (var2)
Für var1 wird dann auf jeden Fall ein "frisches" Register verwendet.

Beachte, daß der COmpiler den Inine-Assembler nur als einen Klumpen Text 
bekommt. Er geht davon aus, daß dieser Klumpen Text sich verhält wie 
ein Stück Code, das zu einem Zeitpunkt ausgeführt wird.
So etwas wie eine sequenzielle Abfolge der einzelnen 
Zeilen/Befehle/Zeichen/Direktiven/Was-auch-immer in
dem Klumpen gibt es nicht.

von Moritz G. (mbydq2)


Lesenswert?

Johann L. schrieb:

>>>> Muss man alle Ausgaben, die nicht auch Eingaben sind, mit einem '='
>>>> versehen, kann es also kein alleinstehendes "r" als Ausgabe-constraint
>>>> geben?
>>> Nein, und der Compiler wird dann auch meckern.
>> Verstehe ich nicht. (wieso dann "nein"?)
> Nein, man kann kein alleinstehended "r" als Ausgabe-Contraint
> vewrwenden. Vielleicht in einen Fragesatz nur eine Frage packen ;-)

Also auf beides ein: Ja.

>> : "r" (var1) : "r" (var2)
>> hier darf nicht das selbe Register verwandt werden, weil %0
>> überschrieben werden könnte bevor %1 zum letzten mal gelesen wurde:
> Wie oben erklärt ist diese Schreibweise nicht möglich und führt zu einer
> Fehlermeldung.
> Wenn var1 verändert wird, bevor var2 komplett ausgewertet wurde, sind
> die korrekten Constraints
1
: "=&r" (var1)
2
: "r" (var2)
> Für var1 wird dann auf jeden Fall ein "frisches" Register verwendet.

_ Danke!

von Moritz G. (mbydq2)


Lesenswert?

Ich möchte es nochmal für mich und andere nach mir (es soll Leute geben 
die Foren so nutzen) zusammenfassen:

Bei den Ausgaben ist immer ein =, +, & zu setzen.
'=' Die Variable dient nur der Ausgabe, das Register kann zur Eingabe 
verwandt werden.
'+' Die Variable und ihr Register ist sowohl Ausgabe als auch Eingabe.
'&' Die Variable dient nur der Ausgabe, das Register darf nicht zur 
Eingabe verwandt werden.
Keine Eingabevariable wird verändert, soll ein Register für die Eingabe 
einer Variablen und die Ausgabe einer anderen verwandt werden, muss in 
der Eingabesektion mit einer Ziffer auf die betreffende Ausgabe Bezug 
genommen werden.
Es ist lediglich guter Stil jede Variable nur einmal zu nennen.

Suchbegriffe: vergabebeschränkung atmel übergabe early clobber

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Moritz G. schrieb:
> Ich möchte es nochmal für mich und andere nach mir (es soll Leute geben
> die Foren so nutzen) zusammenfassen:
>
> Bei den Ausgaben ist immer ein =, +, & zu setzen.

& ist nicht immer zu setzen, nur falls nötig. Ausserdem gibe es nur 3 
gültige Varianten: "=", "+" und "=&".

> '=' Die Variable dient nur der Ausgabe, das Register kann zur Eingabe
> verwandt werden.

Ja. Auf die Variable wird nur schreibend zugegriffen.

> '+' Die Variable und ihr Register ist sowohl Ausgabe als auch Eingabe.

Auch ok.

> '&' Die Variable dient nur der Ausgabe, das Register darf nicht zur
> Eingabe verwandt werden.

"=&", siehe oben

> Keine Eingabevariable wird verändert, soll ein Register für die Eingabe
> einer Variablen und die Ausgabe einer anderen verwandt werden, muss in
> der Eingabesektion mit einer Ziffer auf die betreffende Ausgabe Bezug
> genommen werden.

"Input-Operanden". "Section/Sektion" mein in der Regel was anderes.

> Es ist lediglich guter Stil jede Variable nur einmal zu nennen.

Ja nach Code muss eine Variable mehrfach genannt werden, etwa
1
asm ("mov %0,%1"
2
           : "=l" (data8)
3
           : "d" (data8));

> Suchbegriffe: vergabebeschränkung atmel übergabe early clobber

GCC Inline-Assembler Constraints. "Vergabebeschränkung" versteht kein 
Mensch.

...und was hat Atmel damit am Hut??

von Moritz G. (mbydq2)


Lesenswert?

Johann L. schrieb:
> & ist nicht immer zu setzen, nur falls nötig. Ausserdem gibe es nur 3
> gültige Varianten: "=", "+" und "=&".

Ah, schöne Zusammenfassung.

> ...und was hat Atmel damit am Hut??

Eigentlich nichts, aber unsere Beispiele beziehen sich auf die AVR-ISA 
von dieser Firma. Sollte jemand also "atmel avr mikrocontroller gcc 
constraint inline assembler" bei Google eingeben, kommt er dennoch hier 
her.

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.