Ich muß 64Bit rechnen und das geht ja mit dem AVR-GCC nur äußerst
bescheiden, es werden riesige und langsame Codemonster erzeugt.
Ich habe daher versucht, die Funktionen in Assembler zu schreiben,
scheitere aber schon an der Addition.
Für 8Bit und 16Bit Zahlen ist alles o.k., aber bei 32Bit und 64Bit macht
er nur noch Schrott.
Der 1. Operand wird weggeschmissen und der 2. mit sich selbst addiert.
Im Anhang das Listing.
@ Peter Dannegger (peda)
>Ich muß 64Bit rechnen und das geht ja mit dem AVR-GCC nur äußerst>bescheiden, es werden riesige und langsame Codemonster erzeugt.
Wohl leider wahr :-(
>Geht inline Assembler prinzipiell nur mit 16Bit Variablen?
AFAIK nein. Aber nach der Beschreibung in der Doku der libc ist das
schon ne kleine Wissenschaft für sich.
MFG
Falk
Nützlicher wäre es, du würdest die entsprechenden Routinen für die
libgcc.S beisteuern... wobei die Addition ja noch inline im Compiler
erfolgt und offenbar auch nicht schlechter als deine ist, davon
abgesehen, dass sie funktioniert. ;-)
Du hast einfach einen Denkfehler: beide Operanden sind input-Operanden,
und einer von beiden gleichzeitig output-Operand. Du hast aber nur
einen als input und einen als output deklariert. Damit steht es dem
Compiler frei, für beide Operanden die gleiche location zu wählen.
Jörg Wunsch wrote:
> Nützlicher wäre es, du würdest die entsprechenden Routinen für die> libgcc.S beisteuern...
Kann ich gerne machen, weiß bloß nicht wo man das hinposten muß (ginge
hier?).
Die Routinen sind ja einfach.
> wobei die Addition ja noch inline im Compiler> erfolgt und offenbar auch nicht schlechter als deine ist, davon> abgesehen, dass sie funktioniert. ;-)
Die für 64Bit ist richtig groß (168 Words), daher hatte ich sie nicht
mit gepostet, um das Listing nicht unnötig aufzublähen.
Zu erwarten sind eigentlich max 9 Words (1*ADD, 7*ADC, 1* RET).
Was er in meinem Code unnnütz pusht und moved, entzieht sich völlig
meinem Verständnis.
> Du hast einfach einen Denkfehler: beide Operanden sind input-Operanden,> und einer von beiden gleichzeitig output-Operand. Du hast aber nur> einen als input und einen als output deklariert. Damit steht es dem> Compiler frei, für beide Operanden die gleiche location zu wählen.
Könnte das dann so richtig sein?
1
unsignedlongadd32(unsignedlonga,unsignedlongb)
2
{
3
__asm____volatile__(
4
"add %A0, %A1""\n\t"
5
"adc %B0, %B1""\n\t"
6
"adc %C0, %C1""\n\t"
7
"adc %D0, %D1"
8
:"=r"(a),"=r"(b)
9
:"r"(a)
10
);
11
returna;
12
}
Bei 32Bit funktionierts, ist sogar kürzer als der Bibliothekscode.
Bei 64Bit macht er allerdings unnützte pushs/moves, die den 1.Opernaden
zerstören, d.h. es kommt wieder nur 2*Operand2 heraus.
Peter
Wie man im Listing sieht, geht 64Bit prinzipiell nicht, die Parameter
%E0..%H0, %E1..%H1 werden nicht als die oberen 4 Bytes expandiert.
Man könnte die Register direkt hinschreiben, aber dann gibts ne Warnung,
daß kein Returnwert existiert.
Anbei mal die 4 Grundrechenarten in Assembler geschrieben.
Leider habe ich überhaupt keine Ahnung, wie man die nun in die libgcc.S
einbindet.
Wenn mir jemand vielleicht helfen könnte?
Die Größenunterschiede (in Bytes) sind ja riesig:
Peter Dannegger wrote:
> Wie man im Listing sieht, geht 64Bit prinzipiell nicht, die Parameter> %E0..%H0, %E1..%H1 werden nicht als die oberen 4 Bytes expandiert.
Ja, da wirst du Recht haben. :-(
Dieser Patch im GCC müsste das ändern, aber ich bin kein GCC-Experte:
> Anbei mal die 4 Grundrechenarten in Assembler geschrieben. Leider> habe ich überhaupt keine Ahnung, wie man die nun in die libgcc.S> einbindet.
Das kannst du dir in der libgcc.S anlesen. Allerdings denke ich, dass
zumindest Addition und Subtraktion besser im Compiler selbst
aufgehoben sind, statt dass man da Bibliotheksfunktionen aufruft. Bei
der Multiplikation bin ich mir nicht so sicher (könnte davon abhängen,
ob ein Hardware-Multiplizierer da ist), die Division ist sicherlich
als Funktion besser aufgehoben.
Es müssten dafür neue Code-Templates in gcc/config/avr/avr.md
eingebaut werden, die die 64-bit-Operationen implementieren. Diese
würden dann übrigens auch die Präfixbuchstaben E bis H mit benutzen,
d. h. obiger Patch wäre die Voraussetzung dafür. (Wem der inline-
Assembler schon immer kryptisch vorkam, das ist der Grund: das ist
eigentlich eine komplett interne Compilersyntax und -semantik, die da
nach außen geführt wird. Dafür kann er eben praktisch auch alles das,
was der Compiler intern selbst kann.)
Die derzeitigen 64-bit-Operationen werden meines Wissens vom
generischen Compilercode komplett synthetisiert, indem er die
vorhandenen low-level 32-bit-Operationen miteinander verkettet. Das
erklärt auch, warum dabei solch umständlicher Code generiert wird.