Hallo,
ich versuche mit dem avr-gcc effizient auf register variablen
zuzugreifen.
Leider macht er aus
1
registeriasm("r17")
2
...
3
--i
folgendes
1
mov r24,r17
2
subi r24,lo8(-(-1))
3
mov r17,r24
Der Compiler scheint register variablen wie Ram zu behandeln:
laden, dekrementieren, speichern. Es ist egal welches Register ich
benutze (high oder low).
Wie kann ich den Compiler dazu bringen ein 'subi r17' oder 'dec' zu
generieren?
(avr-gcc version ist 4.3.4)
Vielen Dank im Voraus,
Chris
Chris schrieb:> Wie kann ich den Compiler dazu bringen ein 'subi r17' oder 'dec' zu> generieren?
Gar nicht. Wenn du wirklich was optimieren möchtest, schreib Funktionen
direkt in ASM und linke sie mit dem übrigen Programm zusammen. Dazu
gibt's ein Kapitel in der avr-libc Doku inkl. Beispiel.
Welchen Code generiert der Compiler für i-- ?
Wie wirken sich die Optimierungen aus (-O2 oder -Os)?
Chris schrieb:> Der Compiler scheint register variablen wie Ram zu behandeln:> laden, dekrementieren, speichern.
In welchem Kontext passiert das? Hast du ein kleines, kompilierbares
Testprogramm, wo man das Problem sehen kann?
Unabhängig davon ist es aber immer etwas gefährlich, C-Variablen feste
Register zuzuweisen und bringt oft mehr Nachteile als Vorteile.
@tom:
Also der GCC kann mir doch ganz toll ganze Codeblöcke wegoptimieren
(wenn man mal das volentile vergisst ;-) und dann kann er diese
einfache Registeroptimierung nicht ???
@Yalu
Ich probiere mal das runterzubrechen in ein kleines Programm. Mir ist es
bei der Statevariabe aufgefallen, die in der Interruptrutine verändert
wird.
Eine Registervariable bringt mir schon ca 100 Bytes weniger, weil state
naürlich als volatile deklariert ist und daher immer aus dem Ram neu
geladen und gespeichert wird wird.
Und das Programm macht nicht so viel, auf ein Register kann ich (bzw.
der Compiler) gut verzichten. Und die Avr-Lib wird auch nicht benutzt,
also auch von hier keine Gefahr.
Ich versuche mal ein kleines Beispiel zu machen, vielleicht bring das
neue Erkenntnisse.
Viele Grüsse,
Chris
"register" ist ein Relikt aus dem Ur-C-PDP-11-Pleistozän. Aktuelle gcc's
nehmen das höchstens noch als unverbindlichen Wunsch des Programmieres
zur Kenntnis, und ignorieren es, wenn immer erforderlich. "volatile
register" kann der gcc schon gar nicht, was u.a. daran liegt, daß das
gar keinen Sinn ergibt.
Wenn du deine volatile state-variable am Anfang der ISR in eine lokale
Variable umkopierst, und am Ende wieder zurück, dann hat der Compiler
dazwischen alle Optimierungsmöglichkeiten. Den würde ich da einfach
machen lassen, und ihm nicht ins Handwerk pfuschen.
Wenn es tatsächlich auf jeden einzelnen Zyklus und jedes einzelne Byte
ankommt, nimm, wie schon gesagt wurde, Assembler.
Oliver
Ja dass hört sich gut an, das den Compiler einfach machen zu lassen.
Leider ist er doch nicht so schlau. Wie gesagt, mit dem Holzhammer an
eine Registervariable gebunden spart mir schon 100 Byte und ich bin halt
knapp über den 2K vom ATtiny2313. und wenn er den Zugriff auch noch
besser machen würde hätte ich noch mehr davon. Im Hauptprogramm wird die
Statevariable auch sehr häufig abgefragt.
Vielleicht wenn man das Programm mit --complete (oder wie heisst die
option?) compiliert kann der Compiler das besser optimieren. (hat da
jemand Erfahrung?)
Zu Assembler kann ich mich noch nicht durchringen, solange ich es in C
hinbekomme.
Gruss
Chris
Wenn du r17 als Registervariable verwendest fliegt dir der Code um die
Ohren, wenn das Register zur Parametrübergabe verwendet wird. Du kannst
nicht einfach eine Registervariable verwenden und erwarten daß ein
Compiler eine dynamische ABI-Anpassung vornimmt.
Und überhaupt: Ist die Registervariable lokal oder global?
Wenn du Code sparen willst, dann:
Fass Variablen, die zueinander gehören, zu Strukturen zusammen und
greife indirekt darauf zu. Das spart dann pro Zugriff 2 Bytes. Um das
sinnvoll nutzen zu können, braucht das Programm aber eine gewisse
Grundstruktur, weil der Code ansonsten nur Pointervariablen am
Rumschaufeln ist (wegen der mageren Ausstattung der AVRs mit
Adressregistern).
> So, hat jemand eine Idee wie man dem Compiler helfen kann ?
Indem man ihm nicht sein Haupt-Arbeits-Register klaut. R24 ist eine noch
viel beschissenere Wahl als r17. Beschränke dich auf die Register 2 bis
7, oder lass es ganz bleiben.
Chris schrieb:> Eine Registervariable bringt mir schon ca 100 Bytes weniger,Chris schrieb:> Leider kann der Optimierer -O3 das nicht mehr richten
Wenn es dir um die Codegröße geht, dann benutze -Os, nicht -O3.
BTW:
Oliver schrieb:> "volatile> register" kann der gcc schon gar nicht, was u.a. daran liegt, daß das> gar keinen Sinn ergibt.
Was ergibt daran keinen Sinn?
In Bezug auf Sinn und Zweck von volatile sehe ich da keinen Unterschied
zur "normalen" Variable.
@Oliver:
>> "volatile register" kann der gcc schon gar nicht,>Je nun, was wollte ich dir mit meinen Worten wohl sagen?
Das weiss ich leider nicht was Du mir sagen willst.
Also der Compiler beschwert sich nicht.
Aber lassen wir doch das volatile vorm Register mal weg dann macht der
Compiler dieses hier:
1
.LM1:
2
ldi r25,lo8(100) ; tmp43,
3
sts tmp,r25 ; tmp, tmp43
4
.L2:
5
.stabn 68,0,14,.LM2-.LFBB1
6
.LM2:
7
sts tmp,r25 ; tmp, ivtmp.16
8
subi r25,lo8(-(-1)) ; ivtmp.16,
9
.stabn 68,0,15,.LM3-.LFBB1
10
.LM3:
11
brne .L2 ; ,
12
ldi r24,lo8(0) ; state,
Das Register r24 wird ganz zum Schluss mit 0 geladen. Ist ja auch
korrekt so. Aber das will ich nun schon gar nicht.
Der GCC macht auf jeden Fall was ziemlich anderes. Vielleicht ja auch
was anderes als im Manual steht. Macht aber Sinn wenn GCC das Register
als Speicherstelle ansieht und halt jedes mal vor der Verwendung sich
den Wert daraus holt. Und nicht nur einmal zum Schluss.
Gruss
chris
Chris schrieb:> @Oliver:>>> "volatile register" kann der gcc schon gar nicht,>>Je nun, was wollte ich dir mit meinen Worten wohl sagen?> Das weiss ich leider nicht was Du mir sagen willst.
volatile bezieht sich auf Objekte in der Speicherklasse static storage,
und da liegt eine explizite Registervariable nun mal nicht. Die liegt
eben in der Speicherklasse register, wie angeordnet.
Von daher dient ein "volatile register ...asm" bestenfalls der eigenen
Verwirrung; stätestens wenn das Register in einer ISR und im
Normalo-Code verwendet wird, ist eine Bauchlandung vorprogrammiert (etwa
Poll-Schleife auf so eine Variable).
Chris schrieb:> Vielleicht wenn man das Programm mit --complete (oder wie heisst die> option?) compiliert kann der Compiler das besser optimieren. (hat da> jemand Erfahrung?)
--combine
Ja, ich benutze es gerne.
Es macht eine sehr effiziente Optimierung und findet fast jedes
vergessene "volatile".
D.h. wenns danach nicht mehr geht, hat er Dir was wegoptimiert, was
volatile sein muß.
Es müssen alle C-Files in einem Rutsch compiliert werden. Das geht am
besten auf der Kommandozeile, *.c expandiert zu allen C-Files im
aktuellen Verzeichnis.
Hier ein Beispiel (a.bat):
Beitrag "mehrere MC seriell über Datenbus verbinden (1Draht)"
Peter
Johann L. schrieb:> Aber bekanntlich ignoriert man Warnungen am besten... sind ja keine> Fehler ;-)
Welche Warnungen ??
Compiliere bitte mit GCC 4.3.4 und natürlich mit -ffixed-r24
Zu den Warnungen bei volatile register gibts einen Thread auf der
AVR-GCC-Bug-Liste, das wurde anscheinend oft in den verschiedenen
Versionen geändert.
Hilft mir aber nicht viel. Hast Du einen konstruktiven Vorschlag wie man
effektiv eine Registervariable in C verwenden kann die in einer ISR
verändert wird?
Seit Ihr schnell ....
Johann L. schrieb:>Und der Code ist so auch ok.
Formaljuristisch ist er ok. Aber es soll natürlich die Abfrage auf
state==0 nicht wegoptimiert werden. Bei einer statischen Variable macht
man das mit volatile. Und was macht man bei einer Registervariablen ???
Chris schrieb:> Formaljuristisch ist er ok. Aber es soll natürlich die Abfrage auf> state==0 nicht wegoptimiert werden. Bei einer statischen Variable macht> man das mit volatile. Und was macht man bei einer Registervariablen ???
Selbst der Klassiker
1
asm volatile ("":"+r"(state));
bleibt wirkungslos... (avr-gcc 3.4, 4.3, 4.5), ebenso ein Verändern von
state in der Schleife. Was willst da machen?
Verwende andere, robuste Techniken, um die Codegröße zu optimieren. Da
ist zudem mehr zu holen. Auf den L-Regs sind eh kaum Operationen
möglich. Wahrscheinlich wird dein Code mit der Registervariablen nur
deshalb so klein, weil die hälfte in der Tonne landet...
Chris schrieb:> Compiliere bitte mit GCC 4.3.4 und natürlich mit -ffixed-r24
Ich hab hier net jede jemals veröffentliche avr-gcc Version ;-)
-ffixed-n änder nix am ABI. Es nimmt die Variable dem Registerallokator,
wenn er Pseudoregister zuordnen will. Aber -ffixed verhindert nicht das
Erzeugen von r24 per se, zB durch Funktionsaufrufe wie a = b / c zur
libgcc.
Bestenfalls Register, die nicht vom ABI belegt werden (wie oben schon
geschrieben r2-r7) sind für sowas zu gebrauchen.
In einer Anwendung mit avr-gcc 3.4 verwende ich globale
Registervariablen, weil das 200000 Speicherzugriffe pro Sekunde spart.
Im Endeffekt bringt's nicht sooo viel, auch nicht für die Codegröße (die
übrigens kleiner ist als mit jeder 4-er Version, die ich je angetestet
habe). Aber nun ist's in Code eben mal drinne... An Codegröße macht das
einen Unterschied von -0.5%, also lächerlich. Aber da ich in der ISR
jeden Tick brauche, bleibt's eben drin.