Konstantenpropagation

Konstantenpropagation 1:

Verfügbar ab TwinCAT 3.1.4026.14

Die statische Codeanalyse basiert auf Konstantenpropagation, deren Ergebnisse für verschiedene Prüfungen genutzt werden. So wird beispielsweise überprüft, ob Pointer ungleich 0 sind, oder ob Arrayindizes außerhalb des gültigen Bereichs liegen.

Sie können die statische Analyse effektiv unterstützen, allein wenn sie wissen, wie diese Analyse funktioniert und wo ihre Grenzen liegen.

Sehen Sie auch: Befehl 'Werte der Konstantenpropagation für aktuellen Editor anzeigen'

Konstantenpropagation

Bei der statischen Analyse wird versucht, den Wert einer Variable anhand ihrer Verwendung zu bestimmen.

Beispiel:

PROGRAM MAIN
VAR
    x     : INT;
    bTest : BOOL;
END_VAR
x := 99;
 
IF x < 100 THEN
    bTest := TRUE;
END_IF

In der Implementierung in Zeile 1 zeichnet die Konstantenpropagation den Wert 99 für die Variable x, um diesen Wert für weitere Analysen zu verwenden. Die Analyse erkennt dann, dass der Ausdruck in der nachfolgenden IF-Anweisung konstant TRUE ist.

Lokal durchgeführte Konstantenpropagation

Ein Wert wird nur lokal im Baustein ermittelt. Es ist unerheblich, wie eine Eingabe übergeben wird. Auch die Ergebnisse von Funktionsaufrufen sind irrelevant.

Beispiel:

FUNCTION Func : BOOL
VAR_INPUT
    bTest : BOOL;
END_VAR
IF bTest THEN
    Func := OtherFunc(TRUE);
END_IF

Wenn der Parameter bTest bei jedem Aufruf auf TRUE gesetzt wird, hat dies keine Auswirkung auf die Konstantenpropagation. Auch wenn OtherFunc(TRUE) immer TRUE zurück gibt, hat dies keine Auswirkung auf die Konstantenpropagation.

Nur temporäre Variablen haben Initialwerte

Statische lokale Variablen in Programmen und Funktionsbausteinen haben keinen angenommenen Initialwert. Die Variablen behalten ihre Werte des letzten Aufrufes und können daher prinzipiell "alles" sein.

Lokale Variablen in Funktionen und temporäre Variablen haben einen Initialwert bei jedem Aufruf. Die Konstantenpropagation rechnet mit diesem Initialwert.

Beispiel:

PROGRAM MAIN
VAR
    x     : INT := 6;
    bTest : BOOL;
END_VAR
VAR_TEMP
    y     : INT := 8;
END_VAR
bTest := x < y;

Die Variable y wird bei jeder Ausführung von MAIN den Wert 8 haben. Die Variable x jedoch nicht unbedingt. Daher wird die Konstantenpropagation nur für y einen Wert annehmen, nicht aber für x.

Es empfiehlt sich, Variablen, die immer zuerst geschrieben und dann gelesen werden, als temporäre Variablen zu deklarieren.

Konstantenpropagation ermittelt Wertebereiche für numerische Datentypen

Um die Komplexität zu reduzieren, wird für jede Variable ein Wertebereich mit Ober- und Untergrenze ermittelt.

Beispiel:

PROGRAM MAIN
VAR
    x     : INT := 6;
    bTest : BOOL;
    y     : INT;
END_VAR
IF bTest THEN
    x := 1;
ELSE
    x := 100;
END_IF
 
IF x = 77 THEN
    y := 13;
END_IF

Hier wird für die Variable x der Wertebereich [1..100] ermittelt. Infolgedessen wird in Zeile 7 der Vergleich x = 77 nicht als konstanter Ausdruck erkannt, da 77 innerhalb des Wertebereichs liegt.

Wiederkehrende komplexe Ausdrücke werden nicht als die gleiche Variable erkannt

Komplexe Ausdrücke haben unter Umständen keinen Wert zugeordnet. Wenn solche Ausdrücke mehrfach vorkommen, ist es hilfreich, eine Hilfsvariable einzuführen.

Beispiel:

PROGRAM MAIN
VAR
    x         : DINT;
    py        : POINTER TO INT;
    y         : INT;
    testArray : ARRAY [0..4] OF DINT;
END_VAR
IF py <> 0 THEN
    IF py^ >= 0 AND py^<= 4 THEN
        x := testArray[py^];
    END_IF
 
    y := py^;
 
    IF y <= 0 AND y <=4 THEN
        x := testArray[y];
    END_IF
END_IF

In Zeile 3 wird ein Fehler ausgegeben für einen möglichen Zugriff über Pointer auf einen Wert, obwohl der Bereich, auf den der Pointer zeigt, überprüft wird. Wird der Wert zuerst in eine lokale Variable kopiert und deren Bereich überprüft, dann kann die Konstantenpropagation den Wertebereich für diese Variable ermitteln und erlaubt den Zugriff in den Array in Zeile 9.

Verzweigungen

Bei Verzweigungen werden einzelne Zweige getrennt berechnet. Wertebereiche aus den einzelnen Bereichen werden anschließend zu einem neuen Wertebereich vereinigt.

Beispiel:

IF func(TRUE) THEN
    x := 1;
ELSE
    x := 10;
END_IF
 
IF func(FALSE) THEN
    y := x;
ELSE
    y := 2*x;
END_IF

In Zeile 6 hat x den Bereich [1..10]. Nach Zeile 11 hat y den Wertebereich [1..20]. Dies ergibt sich aus der Vereinigung der beiden Wertebereiche [1..10] und [2..20].

Bedingungen

Beispiel:

Bedingungen können den Wertebereich einer Variablen in einem Codeblock einschränken. Mehrere Bedingungen können kombiniert werden. Einander ausschließende Bedingungen können auch zu einem leeren Wertebereich führen.

IF y > 0 AND y < 10 THEN
    x := y;
ELSE
    x:= 0;
END_IF
 
IF x < 0 THEN
    i := 99;
END_IF

y hat in Zeile 2 den Wertebereich [1..9]. Daraus ergibt sich für x in Zeile 6 der Wertebereich [0..9]. Kombiniert mit der Bedingung x < 0 ergibt das in Zeile 9 für x eine leere Menge an möglichen Werten. Der Code ist nicht erreichbar. Die statische Analyse wird melden, dass die Bedingung x < 0 an dieser Stelle immer FALSE ergibt.

Schleifen

Die Konstantenpropagation wird Schleifen im Code so lange ausführen, bis sich die Werte der Variablen in der Schleife nicht mehr ändern. Dabei wird angenommen, dass eine Schleife beliebig oft durchlaufen werden kann. Die bisher ermittelten Werte werden mit den vorhergehenden Werten vereint. Variablen, die innerhalb der Schleife geändert werden, haben einen sukzessiv wachsenden Bereich. Dabei nimmt die Konstantenpropagation nicht alle möglichen Werte für Bereiche an, sondern verwendet nur im Code vorkommende Grenzen und außerdem die Werte 0, 1, 2, 3 und 10, da diese häufig eine Rolle spielen.

Am einfachsten wird das Vorgehen an einem Beispiel deutlich.

Beispiel:

PROGRAM MAIN
VAR
    x : DINT;
    i : DINT;
    y : DINT;
END_VAR
x := 0;
y := 0;
 
FOR i := 0 TO 5 DO
    x := x + 1;
    y := i;
END_FOR

Die Konstantenpropagation weiß folgendes über die Schleife:

i, x, und y sind zu Beginn der ersten Ausführung der Schleife 0. Für den Code in der Schleife gilt die Bedingung i <= 5. Für den Code nach der Schleife gilt die Bedingung i > 5.

Für die Werte der Variablen in der Schleife ermittelt die Konstantenpropagation folgende Werte:

 

i

x

y

 

 

[0..5]

[0..MAXDINT]

[0..5]

 

Im Detail werden folgende Zwischenschritte durchlaufen:

Durchlauf

i

x

y

 

1

0

[0..1]

0

i wurde mit 0 initialisiert, y bekommt immer die gleichen Werte wie i

2

[0..1]

[0..2]

[0..1]

 

6

[0..5]

[0..6]

[0..5]

Zunächst wird tatsächlich der Bereich [0..6] für i berechnet. Es ist aber bekannt, dass i < 5 eine Bedingung ist. Daher wird der Wert für den Code in der Schleife auf diesen Wert begrenzt.

7

[0..5]

[0..7]

[0..5]

 

10

[0..5]

[0..10]

[0..5]

x wird immer weiter hochgezählt. Ab 10 wird allerdings der Wert auf MAXDINT "aufgerundet".

11

[0..5]

[0..MAXDINT]

[0..5]

MAXDINT + 1 ergibt MAXDINT

ab 11

 

 

 

Ab dem 11. Durchlauf werden sich die Werte in der Schleife nicht mehr ändern. Die Propagation wird beendet.

Darüber hinaus gilt für den nach dieser Schleife folgenden Code: i = 6. Es wird in der Schleife der Bereich [0..6] ermittelt und dieser mit der Bedingung i > 5 kombiniert, was exakt den Wert 6 ergibt.