PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Code Optimierung



Siro
19.08.2010, 09:08
Hallo,
ich habe eine vermutlich simple Frage zur C Programmierung allgemein:

Darf (bzw. könnte) ein Compiler den folgenden Code optimieren.


LPC_I2C0DAT = EE_SLAVE_ADDRESS | ((EE_Address >> 8) << 1);

Ich schiebe einen Wert 8 mal nach rechts und dann einmal wieder nach links.

Könnte es passieren, daß der Compiler daraus ein >>7 wegoptimiert.
Oder ist es durch die Klammerung ausgeschlossen, daß hier optimiert wird ?
Ich könnte ja auch ((EE_Address >> 7) & 0xFE); benutzen um dies sicherzustellen. Es geht also nur generell um das Prinzip. Optimierung durch die Klammerung ausgeschlossen oder nicht.

Sinn und Zweck ist, daß das LSB Bit 0 gelöscht sein soll.
und meine Adresse in Bit 1..7 stehen soll.

Für eine Info wäre ich dankbar.
mfg. Siro

MichaF
19.08.2010, 09:27
Sehr spannende Frage :)

Aber allein die Klammer schützt dich nicht vor Optimierung. Wirklich sicher beantworten kann ich das aber nicht. Aber ich habe eine Alternative. Falls EE_Address ein uint8 ist:


LPC_I2C0DAT = EE_SLAVE_ADDRESS | ((EE_Address >> 7) & 0b11111110);

Würde das nicht auch gehen? Aber unabhängig davon interessiert es mich trotzdem was der Compiler daraus basteln darf.

Edit: EE_Adress wird kaum nur 8 Bit breit sein, sonst wäre nach dem schieben ja nichts mehr da :D Du brauchst jedenfalls eine Maske in geeigneter Bitbreite bei der nur das Bit0 eine 0 enthält ;)

Noch mal Edit: Das hast du ja schon selber rausgefunden. Oh man, heute ist glaube ich nicht mein Tag. Sorry

Siro
19.08.2010, 16:09
Kein Problem, ich übersehe auch öfters was O:)
Wie Du schon richtig erkannt hast, ist meine EE_Address kein 8 Bit sondern ein 16 Bit Wert. und stellt eine EEPROM Adresse dar für den Chip 24LC16. Dieser hat 16384 Bits bzw. 2048 Bytes also maximale EEPROM Adresse ist 0x07FF. Das Datenblatt gibt nun an, daß ich 3 obersten Bits
an die Bitposition 1..3 schreiben muss. Das LSB (Bit 0) soll 0 sein zum Schreiben.
Dazu schiebe ich den 16 Bit Wert meiner EEPROM Adresse 8 mal nach rechts. Nun bleiben nur noch die obersten 3 Adressbits Bit 8,9 und 10 übrig. Bit 0 bis 7 sind verschwunden. Wenn ich jetzt einmal nach links zurück schiebe befinden sich meine 3 obersten Adressbits wie gewünscht an Bitposition 1..3. Bit 0 ist nun gelöscht. Das funktioniert auch alles einwandfrei.
Mich würde nur interessiren, ob der Compiler diese "Arie" wegoptimieren darf (könnte). Dann würde mein Ergebnis unter Umständen nicht stimmen, das Bit 0 wäre dann das Bit 7 der EEPROM Adresse.
Wie Du selbst schon erkannt hast, kann ich auch 7 mal schieben und dann mittels AND das letzte Bit löschen. Mich würd nur interessiren darf er oder darf er nicht optimieren.
Danke Dir trotzdem, daß Du es Dir angesehn hast.
Die Frage ist also noch offen.
Siro

Gock
19.08.2010, 16:29
Für mich spricht nichts dagegen, dass er die Operationen zusammenfasst, also Deinen "Trick" weg optimiert. Der Compiler optimiert teilweise noch viel weniger offensichtliche Dinge weg, Stichwort volatile. Ich bin aber auch kein Experte für sowas.
Wenn Du ein bisschen Assembler kannst, kannst Du Dir die Ergebnisse ja anschauen. Dazu musst Du in den AVRStudio "Optionen" unter "General" einen Haken machen bei "Generate Listfile".
Gruß

Siro
19.08.2010, 16:46
Was der Compiler teilweise wegoptimiert finde ich schon fast eine Frechheit... Ich hab die Programmzeilen doch nicht umsonst geschrieben [-X
Spaß beiseite, ich arbeite mit dem IAR Compiler und teilweise find ich das extrem störend, daß mir der Compiler dauern den Code klaut. Zumal wenn ich einen Breakpoint drauf setzte. Mit volatile konnte ich mir meistens weiterhelfen. Ich find das echt schade, wenn ich sämtliche Optimierungen ausschalte, dann sollte er gefälligst sämtlichenn Code drin lassen auch wenn er nicht aufgerufen wird. Oder aus Sicht des Compilers unnötig erscheint. Ich denke mal hier wird jeder Compiler auch seine eigenen Optimierungen vornehmen, GNU sicher anders als KEIL oder IAR usw. Ich werde wohl lieber die Variante mit 7 mal schieben und dem AND verwenden. Ist dann Kompatibler zu anderen Compilern.
Dann ist C also doch nicht so portabel ..... ? :^o
Sorry, bin halt eingefleischter Assembler Programmierer. Da kommt immer
aufs Bit genau der gleiche Code raus.

Gock
19.08.2010, 16:57
Naja, portabel ist c schon. Solange keine Compilerfehler enthalten sind, läuft es auf vielen verschiedenen Plattformen, nur eben nicht gleich schnell...
Gruß

MichaF
19.08.2010, 17:03
Naja, ich versuche jetzt einfach mal zu beschreiben wie ich das sehe. Im Allgemeinen darf/soll ein Compiler ja nur dann optimieren, wenn er Beweisen kann, das der optimierte Code in jedem Fall zu dem gleichen Ergebnis führt, wie der ohne Optimierung.

Wir haben es hier mit shift Sperationen zu tun. Und im Prinzip geht es ja um die Frage, ob dem Compieler klar ist, das er ein einmal "weggeshiftetes" Bit nicht wieder durch shift in die andere Richtung zurückholen kann. Genauer gesagt geht es um die Kenntnis, das ein nach dem shift "leeres" Bit beim Shift definitiv eine 0 wird. Dann könnte er nämlich erkennen, das ">> 8 + <<" nicht zum selben Ergebnis füht wie ">>7".

Und dass er über dieses Wissen verfügt, lässt sich an einem klassischen Optimierungsbeispiel zeigen. Eine Division durch 2^n könnte er nämlich nicht duch einen shift >> n ersetzen, wenn er nicht wüßte, das die frei werdenen Stellen eine Null ergeben.

Ich behaupte daher mal unbewiesen, das er zumindest nicht zu ">>7" optimiert. Evtl. kommt er ja sogar auf die Sache mit der Maskierung, wer weiß ;)

Siro
19.08.2010, 17:23
Hallo MichaF,
das klingt sehr plausibel, daß der Compiler sicherstellen muss, daß der erzeugte Code zum gleichen Ergebnis führen muss.
Ich habe eben mit verschiedenen Optimierungsstufen compiliert und mir den Assemblercode angesehen. Der Compiler führt es jedesmal exakt so aus wie angegeben. 8 mal rechts schieben und dann einmal links schieben.
Ich denke damit ist meine Frage beantwortet. Danke euch allen.
Siro

Gock
19.08.2010, 18:09
Na da seht Ihr mal, jetzt hab ich dem armen GNU unrecht getan, Sorry.
Allerdings muss ich sagen, dass ich in solchen Fällen vorsichtshalber immer das Schlimmste annehme und das durch eindeutige Programmierung versuche zu umgehen.
Wenn Du aber ein Assemblerfan bist, dann kannst Du sowas auch mit InlineAssembler umgehen.
Gruß

BurningWave
19.08.2010, 20:20
Das schlimmste was der arme GNU macht ist immer noch while(var) zu while(true) zu verändern, wenn var nur in einem Interrupt verändert wird und nicht volatile ist.

MichaF
19.08.2010, 22:45
Das schlimmste was der arme GNU macht ist immer noch while(var) zu while(true) zu verändern, wenn var nur in einem Interrupt verändert wird und nicht volatile ist.
Was aus Compilersicht meiner Meinung nach korrekt ist.
Beispiel:

"var" ist als nicht volatile deklariert

"var" wird innerhalb der main Routine nicht direkt, und auch nicht durch Funktionsaufrufe/call by Refrenze etc. geändert.

-> der Compiler kommt zu der Annahme, das "var" sich über die gesamte Laufzeit nicht ändern wird, also wird die Variable überall im Code duch eine Konstante ersetzt, durch 0, bzw. durch einen evtl. initialisierten Wert. Das es ein komplett abgetrenntes "Programm", nämlich eine Interruptroutine gibt, welches durch die Hardware aufgerufen wird, kann der Compiler ohne Hilfe nicht wissen.

Im übrigen ist mir kein einziger Fall bekannt, bei dem der GCC durch eine Optimierung zu falschem Maschinencode führt. Allerdings kann der Compiler eben nur über die Informationen verfügen, die man ihm auch mitteilt. Und ob eine Variable nun volatile ist oder nicht, muss man ihm schon sagen. Tut man das nicht, kommt es zu derart "veroptimierten" Schleifen. Macht man sich aber klar, was man da eigentlich gerade geschrieben hat, hat der Compiler keinen Fehler gemacht.