Jay schrieb:
> Den Grund warum der Compiler mit dem push/pop anfängt kennst du auch?
> Sobald er die Verwendung der Register nicht mehr verfolgen kann, z.B.
> wegen eines einen Funktionsaufrufs
Warum sollte ein einfacher Funktionsaufruf den Compiler zwingend daran
hindern, die Registerverwendung verfolgen zu können? Dafür gibt es
keinen harten technischen Grund.
Das wäre höchstens dann der Fall, wenn die Funktion in einem anderen
Codemodul liegt oder es sich um einen indirekten Funktionsaufruf
handelt, dann (und nur dann) kann sich der Compiler natürlich nicht mehr
sicher sein.
Solange es aber um eine direkt aufgerufene Funktion im gleichen
Codemodul handelt und diese ihrerseits nur Funktionen im eigenen
Codemodul direkt aufruft usw., könnte der Compiler das sehr wohl
verfolgen. Wenn er will, bzw. seine Macher ihm die Fähigkeit dazu
eingehaucht haben.
Es gibt aber natürlich Grenzen, weil es im Prinzip ja ein unendliches
Problem ist, wie man sehr schnell merkt, wenn es eine Rekursion im
Callstack gibt, z.B. wegen einer absichtlich rekursiv designten
Funktion.
Man braucht in diesem Zusammenhang aber garnicht versuchen, Rekursionen
zu detektieren (was exponentiell aufwendig wäre), man bricht statt
dessen die vorausschauende Verfolgung einfach stumpf dann ab, wenn die
Register ausgehen und kehrt zähneknirschend zur normalen Methode der
Codegenerierung zurück. Führt hingegen die Vorschau ohne Unterlauf des
Registerfiles auf den initialen Aufruflevel zurück, dann ist sicher,
dass der gesamte betrachtete Code massiv optimiert werden kann, dann hat
sich der Aufwand für die Vorschau gelohnt.
Denn der Mehraufwand einer solchen Vorschau muß nur einmal, und zwar zur
Compilezeit, erbracht werden, der Gewinn hingegen klingelt zur Laufzeit
in der Kasse, bezüglich der Rechenleistung bei jedem Aufruf einer
derartig optimierten ISR, bezüglich der Latenz sogar bei jedem Aufruf
jeder ISR im System, ganz egal, ob sie auf diese Weise optimiert
werden konnte oder nicht.