Silverfrost Forums

Welcome to our forums

Request: Do full expression evaluation if /checkmate used

2 Dec 2018 6:02 (Edited: 3 Dec 2018 1:55) #22901

The suggestion/feature request grew out of an experience with a 20,000 line program (550 kbytes).

The NAG compiler was finding an undefined variable with this program, but FTN95 and Lahey found no such error. As usual, it took quite a bit of effort to find the explanation.

Here is a short example.

program undef
   implicit none
   integer :: i, ka, ix(3)
!
   call init(3,ix,ka)
   do i=1,3
      if(ka > 2 .and. ix(i) >= 0)then
         print *,'Found a case, i = ',i
      endif
   end do
end program

subroutine init(n,ia,k)
   implicit none
   integer k, n, ia(n)
   k=2
   ia(k) = 3
   return
end

The IF statement on the seventh line contains two expressions with an .AND. between them. The values of the variables in the expressions are such that the second part, IX(I) >= 0, need not be evaluated, but the compiler may decide to evaluate the second part. The programmer has to ensure that IX(I) is defined, and may expect the compiler to help with shortcomings when /checkmate or /undef has been specified.

Please consider the following change to the behavior of the checking code that is generated when /checkmate is specified. Ascertain whether all the expressions in the IF() have defined values, and issue the usual error messages if not. In other words, /checkmate or /undef would imply 'No short-circuit evaluation'. For the example code above, the programmer would find out with the compiler's help that IX(1) and IX(3) are undefined.

Thanks for your consideration.

3 Dec 2018 1:58 #22904

Quoted from John-Silver did the NAG compiler name specifically what variables were undefinied (i.e. the 2 you mention.

The error it gave is

Runtime Error: undef.f90, line 7: Reference to undefined variable IX(I)
Program terminated by fatal error
3 Dec 2018 8:15 #22907

mecej4

Thank you for your feedback.

The Fortran standard does not specify that the first part of the logical condition must be evaluated before the second and I presume that the NAG compiler has used the reverse order in this context. You could test this by making both parts undefined.

If my presumption is correct then the NAG compiler is not doing more than FTN95.

Unfortunately it would be a significant task to get FTN95 to plant code to evaluate all the components of a logical AND (when earlier conditions fail).

3 Dec 2018 9:41 #22910

Quoted from PaulLaidler ... I presume that the NAG compiler has used the reverse order in this context. ... If my presumption is correct then the NAG compiler is not doing more than FTN95.

Paul, that is a good point, so I looked at the intermediate C code that the NAG compiler produces. Without -C=undefined, the relevant lines read

Tmp1 = 3;
INIT(&Tmp1,ix,&ka);
for(i = 1;i <= 3;i++) {
if (ix[i + -1]>=0 && ka>2) { ...<code to execute WRITE statement ...}

With -C=undefined, the code for the body of the DO is expanded to (I paraphrase)

If i is undefined, print message saying so.
If IX(I) is undefined, print message saying so.
If KA is undefined, print message saying so.
Tmp5 = ix[Tmp2]>=0 && ka>2;
If (Tmp5), execute WRITE statement

Thus, the checking is thorough. In particular, there is a check on the DO index I being defined during each iteration of the loop).

I also tried changing the order of the logical operands to

if(ix(i) >= 0 .and. ka > 2)then

and received the same 'undefined IX(I)' as before, which is consistent with checking every variable that is present in the complete logical expression.

=0 && ka>2)

With -C=undefined, the code for the body of the DO is expanded to (I paraphrase)

If i is undefined, print message saying so.
If IX(I) is undefined, print message saying so.
If KA is undefined, print message saying so.
Tmp5 = ix[Tmp2]>=0 && ka>2;
If (Tmp5), execute WRITE statement

Thus, the checking is thorough. In particular, there is a check on the DO index I being defined during each iteration of the loop).

I also tried changing the order of the logical operands to

if(ix(i) >= 0 .and. ka > 2)then

and received the same 'undefined IX(I)' as before, which is consistent with checking every variable that is present in the complete logical expression.

[quote:c5dedc270f="PaulLaidler"]Unfortunately it would be a significant task to get FTN95 to plant code to evaluate all the components of a logical AND (when earlier conditions fail).

I understand completely, and I posted this thread to gauge the level of interest in being able to do such thorough checking.

Of course, the price of thorough checking at runtime -- the overhead -- is also large. The code in question, with the checks enabled, took 20X longer. On an i5-8400, the checked run took about 100 s. At the time that the code was written (1990s), the CPUs on PCs were not fast enough to make such runs feasible, so we can suspect that many old codes may still contain such bugs.

3 Dec 2018 10:05 #22911

mecej4

This confirms my presumption. The NAG compiler is evaluating the second expression before the first.

When trying to understand what is happening, it is not helpful to change the presented order of evaluation (in the code). What you need to do is to keep the same order but make both parts flag up 'undefined' (by changing the code to access an undefined variable instead of ka at this point). Then you will get your original runtime failure, confirming that the second expression is evaluated first (at runtime).

3 Dec 2018 11:31 #22914

Just out of interest, how do you tell, just by looking at it, if an integer variable is undefined? Isn't it the case that all bit patterns in an integer variable represent valid integers? (Unlike a real, where a specific sequence indicates 'undefined').

Does the NAG compiler keep track of whether integer variables are, in fact, defined? Or does it allocate a special bit pattern to that effect?

Eddie

3 Dec 2018 12:03 #22916

The bit pattern for 32 bits is usually 0xF0F0F0.... which is a large negative integer. The chances of hitting it are small. It's more of a problem with INTEGER*1 and CHARACTER(1) variables.

3 Dec 2018 12:06 #22917

FTN95 uses documented special values for representing 'undefined' integers of various kinds. There is a minute chance of an integer variable acquiring such a special value legitimately but end up being labelled as 'undefined', but that is a price we have to accept.

I don't know the internal details of how NAG implements -C=undefined, but the C code segments that I have seen indicate that NAG generates and maintains tag variables, with various values signifying different status attributes.

3 Dec 2018 1:26 #22918

Aha! And so it is (documented). And how appropriate that it should be FOFO!

For a LOGICAL, anything except 0 and 1, I suppose.

Eddie

3 Dec 2018 2:33 #22919

According to the online help, https://silverfrost.com/ftn95-help/devel/checking_for_undefined_variables_undef.aspx , and the FTN95.CHM file that I have in the FTN95 folder, the values used to represent 'undefined' are Z'80', Z'8080' and Z'8080808080' for 1, 2 and 4-byte integers. When one of these values is placed in a register, the high bit gets extended if necessary to fill out the register.

With older compilers, I have seen Z'BAADF00D' and Z'DEADBEEF' used for similar purposes. Many of the debuggers used in the early days of PCs were not symbolic, and viewing a memory dump in hex would make the undefined variables obvious if one happened to be on the lookout for these patterns. See https://en.wikipedia.org/wiki/Hexspeak .

3 Dec 2018 3:26 #22921

Ah yes. I should have looked it up. F0F0... is used for something else - perhaps a dangling pointer.

Please login to reply.