Skip to main content

Constant Propagation

With the CODESYS Static Analysis version V5.0.0.0, the analysis of the code is based on constant propagation. The results of constant propagation are used for various checks. For example, it checks if pointers are not equal to 0, or if array indices are out of valid range.

You can effectively support static analysis just by knowing how this analysis works and what its limitations are.

Constant propagation

Static analysis attempts to determine the value of a variable based on its usage.

Example 1. Example
PROGRAM PLC_PRG
//Declaration
VAR
    x: INT;
    bTest: BOOL;
END_VAR
//Implementation
x := 99;
IF x < 100 THEN
    bTest := TRUE;
END_IF

In the implementation in line 1, the constant propagation records the value 99 for the variable x to use this value for further analysis. The analysis then recognizes that the expression in the following IF-Statement constant TRUE is.



Locally performed constant propagation

A value is determined only locally in the function block. It is irrelevant how an input is passed. The results of function calls are also irrelevant.

Example 2. Example
FUNCTION Func : BOOL
//Declaration
VAR_INPUT
    bText : BOOL;
END_VAR
//Implementation
IF bTest THEN
    Func := OtherFunc(TRUE);
END_IF


Even if the parameter bTest is set to TRUE on every call, this has no effect on the constant propagation. Even if OtherFunc(TRUE) always returns TRUE, this has no effect on constant propagation.

Only temporary variables have initial values.

Static local variables in programs and function blocks have no assumed initial value. The variables keep their values from the last call and can therefore be "anything" in principle.

Local variables in functions and temporary variables have an initial value on each call. The constant propagation calculates with this initial value.

Example 3. Example
PROGRAM PLC_PRG
//Declaration
VAR
    x: INT := 6;
    bTest: BOOL;
END_VAR
VAR_TEMP
    y : INT := 8;
END_VAR
bText := x < y;

The variable y is executed every time PLC_PRG have the value 8. The variable x , however, not necessarily. Therefore, constant propagation is only used for y assume a value, but not for x.

It is recommended to declare variables which are always written first and then read as temporary variables.



Constant propagation determines value ranges for numeric data types.

To reduce complexity, a range of values with upper and lower limits is determined for each variable.

Example 4. Example
PROGRAM PLC_PRG
VAR
    x: INT := 6;
    bTest: BOOL;
    y : INT;    
END_VAR
//Implementation
IF bTest THEN
    x := 1;
ELSSE
    x := 100;
END_IF
IF x = 77 THEN
    y := 13;
END_IF

Here the value range [1..100] is determined for the variable x. As a result, on line 7, the comparison x = 77 is not recognized as a constant expression because 77 is within the range of values.



Recurring complex expressions are not recognized as the same variable.

Complex expressions may not have a value assigned. If such expressions occur multiple times, then it is helpful to introduce an auxiliary variable.

Example 5. Example
PROGRAM PLC_PRG
VAR
    x: DINT;
    py : POINTER TO INT;
    y : INT; 
    testArray : ARRAY [0..4] OF DINT;   
END_VAR
//Implementation
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

On line 2, an error is issued for a possible access via pointer to a value, although the area pointed to by the pointer is checked. If the value is first copied into a local variable and its range is checked, then the constant propagation can determine the range of values for that variable and allows access into the array on line 7.



Branching

For branching, individual branches are calculated separately. Value ranges from the individual ranges are then combined to form a new value range.

Example 6. Example
//Implementation
IF func(TRUE) THEN
    x := 1;
ELSE 
    x := 10;
END_IF

IF func(FALSE) THEN
    y := x;
ELSE
    Y := 2*x;
END_IF

On line 6, x has the range [1..10]. After line 11, y has the value range [1..20]; this results from the union of the two value ranges [1..10] and [2..20].



Conditions

Example 7. Example

Conditions can restrict the value range of a variable in a code block. Several conditions can be combined. Mutually exclusive conditions can also result in an empty value range.

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

y has the value range [1..9] on line 2. This results in the value range [0..9] for x on line 6. Combined with the condition x < 0, this results in an empty set of possible values for x on line 8. The code is not accessible. The static analysis will report that the condition x < 0 always returns FALSE at this point.



Looping

Constant propagation will loop code until the values of the variables in the loop no longer change. It is assumed that a loop can be run any number of times. The values determined so far are combined with the previous values. Variables which are changed within the loop have a successively growing range. Here, the constant propagation does not take all possible values for ranges, but uses only limits which occur in the code and also the values 0, 1, 2, 3, and 10 because these are often relevant.

Example 8. Example

The simplest way to describe the procedure is by example:

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

The constant propagation knows the following about the loop:

i, x, and y are 0 at the beginning of the first execution of the loop. The condition i <= 5 applies to the code in the loop. The condition i > 5 applies to the code after the loop.

For the values of the variables in the loop, the constant propagation determines the following values:

i

x

y

[0..5]

[0..MAXDINT]

[0..5]

In detail, the following intermediate steps are passed through:

Pass

i

x

y

1

0

[0..1]

0

i was initialized with 0; y always gets the same values as i.

2

[0..1]

[0..2]

[0..1]

6

[0..5]

[0..6]

[0..5]

First, the range [0..6] is actually calculated for i. However, it is known that i < 5 is a condition. Therefore, the value for the code in the loop is limited to this value.

7

[0..5]

[0..7]

[0..5]

10

[0..5]

[0..10]

[0..5]

x is incremented more and more. From 10, however, the value is "rounded up" to MAXINT.

11

[0..5]

[0..MAXDINT]

[0..5]

MAXDINT + 1 results in MAXDINT

As of 11

From the 11th pass, the values in the loop will not change. The propagation is ended.

Furthermore, i = 6 applies for the code following this loop. The range [0..6] is determined in the loop and this is combined with the condition i > 5, which results in exactly the value 6.