Forum: Compiler & IDEs Achtung, Codeverschwendung bei 64Bit !


von Peter D. (peda)


Lesenswert?

Für ne Berechnung auf nem ATtiny26 benötige ich ne große Dynamik, aber 
float paßt ja nicht rein.

Da dachte ich, nimmste einfach long long (64Bit), dürfte ja nur doppelt 
soviel Code sein, wie long (32Bit).

Aber Pustekuchen, das ist total verschwenderisch programmiert (noch viel 
teurer als float).

Ne Division kostet etwa 5kB !!!

Also Finger weg von long long, wenns unter nem ATmega16 ist !


Nun wollte ich mir ne Divisionsfunktion in Assembler schreiben (35 Words 
= 70Byte), also 2 Parameter übergeben (r25..r18, r17..10 -> r25..18).

Aber wieder Pustekuchen, die Parameter werden gepusht, dann mein 
Assembler ausgeführt und dann die Parameter gepopt, also meine 
Berechnung weggeschmissen, schöne Scheiße.
Obendrein wird noch gemeckert, daß kein Returnwert da ist.

Ich bin mit meinem Latein am Ende :-(

Hat überhaupt schonmal jemand erfolgreich Assembler mit Parameter und 
Returnwert in ne Funktion integrieren können ?


Peter

von Günter R. (galileo14)


Lesenswert?

Hallo, Peter,

bei einem anderen Prozessor (Toshiba TLCS-900-Umgebung) habe ich es so 
gemacht: ich habe einen Funktionsrumpf in C geschrieben (gleiche 
Parameter und Rückgabe wie bei meiner späteren Assembler-Funktion, 
minimale Funktionalität in der Funktion), habe mir dann den 
Assembler-Code angeschaut, den der Compiler daraus macht (quasi 
abkopiert), und dann meine Funktionalität in die Assembler-Funktion 
eingebaut.

Bei den AVR's habe ich keine Erfahrung mit Assembler, aber es könnte 
hier ja genauso gehen?

Günter

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


Lesenswert?

Peter Dannegger wrote:

> Ne Division kostet etwa 5kB !!!

Das ist mehr oder weniger ein known issue.  Da werden nur die
generischen (in C geschriebenen) Funktionen der libgcc.a benutzt, für
64 bit gibt's keine handoptimierten Varianten.

Du kannst ja gern mithelfen, in Assembler kennst du dich aus, warum
schlägst du nicht mal einen Patch für die libgcc.a vor?  Einziger
Wermutstropfen: damit er von GNU akzeptiert wird, musst du deren
Lizenzabkommen unterschreiben (Abtretung der Rechte aus dem Copyright
an die FSF), ohne das akzeptieren sie keine Patches für den GCC, die
mehr als `trivial patches' sind.

(Bitte keine weitere Baustelle wie bei floating point schaffen, bei
der die avr-libc die Funktionen aus der libgcc.a ersetzt.  Das ist
Sch***e und führt dazu, dass entsprechende Bugreports bei GCC nicht
ernst genommen werden, auch dann, wenn sie eigentlich echte Bugs
sind.)

> Aber wieder Pustekuchen, die Parameter werden gepusht, dann mein
> Assembler ausgeführt und dann die Parameter gepopt, also meine
> Berechnung weggeschmissen, schöne Scheiße.
> Obendrein wird noch gemeckert, daß kein Returnwert da ist.

Dann hast du wohl irgendwas flasch deklariert, die Warnung passt ja
wohl gut zum Verhalten des Compilers, den Rückkehrwert dann auch zu
ignorieren.

> Hat überhaupt schonmal jemand erfolgreich Assembler mit Parameter
> und Returnwert in ne Funktion integrieren können ?

Na klar, macht die avr-libc haufenweise:

% find ~/src/avr-libc/lib* -name \*.c | wc -l
     61
% find ~/src/avr-libc/lib* -name \*.S | wc -l
    126

Doppelt so viele Assemblerquellen wie in C geschriebene.  Ich mag
jetzt nicht zählen, wie viele davon Werte zurückgeben, ist mir zu
müßig.
1
#include <stdint.h>
2
3
extern uint64_t myfunc(uint64_t, uint64_t);
4
5
uint64_t x, y, z;
6
7
void
8
dosomething(void)
9
{
10
        z = myfunc(x, y);
11
}
Daraus wird generiert:
1
.global dosomething
2
        .type   dosomething, @function
3
dosomething:
4
/* prologue: frame size=0 */
5
        push r2
6
        push r3
7
        push r4
8
        push r5
9
        push r6
10
        push r7
11
        push r8
12
        push r9
13
        push r10
14
        push r11
15
        push r12
16
        push r13
17
        push r14
18
        push r15
19
        push r16
20
        push r17
21
/* prologue end (size=16) */
22
        lds r18,y
23
        lds r19,y+1
24
        lds r20,y+2
25
        lds r21,y+3
26
        lds r22,y+4
27
        lds r23,y+5
28
        lds r24,y+6
29
        lds r25,y+7
30
        lds r2,x
31
        lds r3,x+1
32
        lds r4,x+2
33
        lds r5,x+3
34
        lds r6,x+4
35
        lds r7,x+5
36
        lds r8,x+6
37
        lds r9,x+7
38
        mov r10,r18
39
        mov r11,r19
40
        mov r12,r20
41
        mov r13,r21
42
        mov r14,r22
43
        mov r15,r23
44
        mov r16,r24
45
        mov r17,r25
46
        mov r18,r2
47
        mov r19,r3
48
        mov r20,r4
49
        mov r21,r5
50
        mov r22,r6
51
        mov r23,r7
52
        mov r24,r8
53
        mov r25,r9
54
        rcall myfunc
55
        sts z,r18
56
        sts z+1,r19
57
        sts z+2,r20
58
        sts z+3,r21
59
        sts z+4,r22
60
        sts z+5,r23
61
        sts z+6,r24
62
        sts z+7,r25
63
/* epilogue: frame size=0 */
64
        pop r17
65
        pop r16
66
        pop r15
67
        pop r14
68
        pop r13
69
        pop r12
70
        pop r11
71
        pop r10
72
        pop r9
73
        pop r8
74
        pop r7
75
        pop r6
76
        pop r5
77
        pop r4
78
        pop r3
79
        pop r2
80
        ret
81
/* epilogue end (size=17) */
82
/* function dosomething size 98 (65) */
Zugegebenermaßen ist das Umspeichern von x über r2...r9 nach r18...r25
alles andere als optimal, aber das Ergebnis wird ordentlich nach z
abgespeichert.

Bitte nicht mehr als 2 uint64_t übergeben: da gibt's einen offenen
GCC-Bug dafür, für den noch keiner eine richtige Lösung parat hat.
Der Fehler scheint im generischen GCC-Teil zu liegen, tritt aber nur
bei nicht-mainstream-CPUs wie dem AVR zu Tage, da die anderen ihre
eigenen Parameterübergaberoutinen haben.  Das führt leider dazu, dass
bei GCC daraus eine recht geringe Priorität resultiert. :-(

von Stefan (Gast)


Lesenswert?

Mit dem Qualifier naked kann man ja beim GCC für ARM und AVR den 
Prolog und Epilog von Funktionen unterdrücken.
http://www.delorie.com/gnu/docs/gcc/gcc_55.html

Hilft dir das vielleicht bei deinem Push/Pop Problem weiter?

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.