Wir gehen vom Programm linalg in der Version 2.1 aus und übersetzen es mit
-cxdb und -O1. Nach dem Start des Debuggers setzen wir die Schrittweite auf
''expression'', setzen einen Breakpoint an den Beginn der Routine GETVEC und
lassen das Programm bis dahin laufen:
set step expression
break routine getvec
run
Wir sehen uns nun den Wert von I mit ''print I'' an und bekommen die
erstaunliche Meldung ''Variable's storage is not available.''. Genauere
Informationen über I erhalten wir mit
info expression I ,
nämlich u.a.:
used to create 1 synthesized variable(s):
1. <INDV> ?i0 = (loc(R)+-8)+(8*(I-1))
Da keine Gültigkeitsbereiche (''liveness ranges'') angegeben werden, ist die
Variable I vollständig wegoptimiert worden; sie kommt im Object-Code nicht
vor. Dafür wurde eine Variable ?i0 vom Optimierer erzeugt, die auf die
angegebene Weise mit I zusammenhängt. Der Grund für diese Ersetzung ist
klar: Statt bei jeder Iteration die Größe I zu erhöhen und dann die
Stelle R(I) zu suchen, wird gleich ein Pointer in das Array hinein
verwendet, der bei jeder Iteration um 8 Byte (Größe eines Elements von R)
weiter zeigt. Weitere Informationen zu der synthetischen Variablen ?i0
erhält man mit
info expression \?i0 .
Als nächstes sehen wir uns mit
info line 20
die Source-Units an, die in Zeile 20 beginnen und bekommen u.a.:
Id Address Boundaries Start End Kind
2. ( 3) 0: 0 20 x 13 20 x 17 <STMT> I = 1
3. ( 5) 80001cfe:80001d02 20 x 20 20 x 20 <EXPR> N
80001cf6:80001cfa
80001ce8:80001cf0
Zeile 2 zeigt, daß das Statement ''I 1'' im Source-Code im Object-Code
keine Entsprechnug hat, und wissen inzwischen auch, warum. Die nächste
Zeile zeigt, daß der simple Ausdruck ''N'' im Objekt-Code an drei Stellen
auftaucht. Mit
info expression N
sehen wir uns das genauer an:
object type: Fortran identifier
location: @(@($ap+4)) <0x8008c6a8>
size: 4 bytes
type: INTEGER*4
value: 100
used to create 1 synthesized variable(s):
1. <SEXP> ?c1 = (loc(R)+-8)+(8*N)
3 liveness ranges:
Start End Location
1. 0x80001cf0:0x80001cf6 - register s0
2. 0x80001d02:0x80001d08 - register a5
3. 0x80001ce4:0x80001d44 - @(@($ap+4))
Man erkennt, daß die Variable N nicht direkt in den Speicher geladen wird,
sondern daß sie über den Argumentpointer $ap angesprochen und zusätzlich
in Registern gehalten wird. Außerdem wird sie noch an anderer Stelle
durch den Pointer ?c1 ersetzt, der auf das Ende des Arrays R zeigt.
Um zu sehen, was passiert, wenn wir auf diese vielfältige Source-Unit ''N''
einen Breakpoint setzen, öffnen wir nun ein Disassemble-Fenster (Menü
''ProcessWindows'' im Source-Fenster) und setzen den Breakpoint auf die
Source-Unit 5 (vgl. ''info line 20 '' -Ausgabe von oben):
break source 5 .
Tatsächlich erscheinen im Disassembler-Listing drei Breakpoints, von denen
der erste an der gleichen Stelle sitzt wie der schon vorher an den Anfang
der Routine GETVEC gesetzte. Diese Doppelbelegung wird durch einen ''*'' im
Listing angezeigt.
Peter Junglas 18.10.1993