Before reporting this as a compiler bug at the Intel forums, I'd like to know if the following is standard conforming. My question is: is the order of logical operations always fixed in Fortran?
! main.f90
interface
subroutine f(x)
logical, intent(in), optional :: x
end subroutine f
end interface
call f(.false.)
call f(.true.)
call f()
end program
! f.f90
subroutine f(x)
logical, intent(in), optional :: x
print*, present(x) .and. x
end subroutine f
gfortran main.f90 f.f90 && ./a.out prints
F
T
F
ifort main.f90 f.f90 && ./a.out prints
F
T
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image PC Routine Line Source
a.out 0000000000476D75 Unknown Unknown Unknown
a.out 0000000000474997 Unknown Unknown Unknown
a.out 0000000000444264 Unknown Unknown Unknown
a.out 0000000000444076 Unknown Unknown Unknown
a.out 0000000000425176 Unknown Unknown Unknown
a.out 00000000004027A0 Unknown Unknown Unknown
libpthread.so.0 00007F3560702E80 Unknown Unknown Unknown
a.out 0000000000402633 Unknown Unknown Unknown
a.out 000000000040260F Unknown Unknown Unknown
a.out 00000000004025AE Unknown Unknown Unknown
libc.so.6 00007F3560371710 Unknown Unknown Unknown
a.out 00000000004024A9 Unknown Unknown Unknown
I'm using GCC 5.3.0 and Ifort 16.0.2.
No, the Fortran standards make no guarantee about the ordering in which logical expressions are evaluated. Like mathematical expressions compilers are free to reorder them into orders which would be equivalent in the perfect world of 'real logic' (or 'real mathematics') but which are not equivalent in the imperfect world of computers.
You might enforce an order of evaluation like this:
if (.not. present(x)) then
print*, .false.
else
print*, x
end if
My copy of the draft standard includes the clause
7.1.5.4.2 Evaluation of logical intrinsic operations
Once the interpretation of a logical intrinsic operation is established, the
processor may evaluate any other expression that is logically
equivalent, provided that the integrity of parentheses in any
expression is not violated.
My interpretation of the standard is that the program does not conform because it makes reference to an optional argument which is not present. Refer to section 12.5.2.12 3 (1) which rules against this. Because the order of evaluation of the operands of the .and. operator is undefined x may be referenced when not present.
Related
I tried to implement an easy Matrix multiplication, but I Keep getting the error
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image PC Routine Line Source
test_performance. 00000000004708F1 Unknown Unknown Unknown
test_performance. 000000000046F047 Unknown Unknown Unknown
test_performance. 000000000043F544 Unknown Unknown Unknown
test_performance. 000000000043F356 Unknown Unknown Unknown
test_performance. 0000000000423DFF Unknown Unknown Unknown
test_performance. 000000000040384D Unknown Unknown Unknown
libpthread.so.0 00002AD8B44769F0 Unknown Unknown Unknown
test_performance. 00000000004034A8 Unknown Unknown Unknown
test_performance. 0000000000402ECE Unknown Unknown Unknown
libc.so.6 00002AD8B46A6BE5 Unknown Unknown Unknown
test_performance. 0000000000402DD9 Unknown Unknown Unknown
This is my Code:
PROGRAM test_performance
IMPLICIT NONE
INTEGER :: DIM_M, DIM_L, DIM_N, index1, index2,index3,index4
INTEGER, DIMENSION(4,4) :: A,B,C
DIM_L=4
DIM_M=4
DIM_N=4
DO index1=1,DIM_M
DO index2=1,DIM_L
print *, 'here I am!'
A(index1,index2)=index1+index2
END DO
END DO
DO index3=1,DIM_L
DO index4=1,DIM_N
B(index3,index4)=index3+index4
END DO
END DO
print *,'A= ',A
print *,'B= ',B
CALL MATRIXMULTIPLICATION
PRINT *, 'C=', C
END PROGRAM test_performance
SUBROUTINE MATRIXMULTIPLICATION(A,B,C, DIM_M, DIM_L, DIM_N)
INTEGER, INTENT(IN) :: DIM_M, DIM_L, DIM_N
INTEGER, INTENT(IN) :: A(4,4), B(4,4)
INTEGER, INTENT(OUT) :: C(4,4)
INTEGER :: ii=1,jj=1, kk=1
DO ii=1, DIM_M
DO jj=1, DIM_N
DO kk=1, DIM_L
C(ii,jj)=C(ii,jj)+A(ii,ll)*B(ll,jj)
END DO
END DO
END DO
END SUBROUTINE MATRIXMULTIPLICATION
I don't know why I get this error, since the Dimension and all the Indices should just be fine. I tried to find the error by using all possible stuff, but I don't havy any clue anymore what the error could be.
The statement
CALL MATRIXMULTIPLICATION
doesn't include the arguments needed when the routine is called. A poor solution would be to simply replace that statement by
CALL MATRIXMULTIPLICATION(A,B,C, DIM_M, DIM_L, DIM_N)
A better solution would be, however, to make the subroutine's interface explicit. There are a number of ways of doing this, one by putting it into a module and useing the module. For a single subroutine that might be overkill but is definitely the way to go as your programs become larger and more complex.
A simple straightforward and satisfactory for your current purposes solution would be to move the line
END PROGRAM test_performance
to follow the line
END SUBROUTINE MATRIXMULTIPLICATION
and, where the end program line originally was insert the line
contains
If you had written your program along these lines in the first place the compiler would have seen your egregious error and pointed it out to you. As it stands the subroutine is external to the program and the compiler can't match its dummy and actual arguments at compile time; as written that argument matching is the programmer's responsibility, one you've rather fluffed.
Further improvements would be to make your subroutine handle arrays of any size and to not bother passing the array dimensions through the argument list. Fortran arrays carry their size and shape information with them, on the rare occasion a routine needs to know them explicitly it can make enquiries.
Even easier would be to use the matmul intrinsic and to spend your time programming other, perhaps more challenging and more interesting, parts of your code.
Here is the source (lets call it test4.F):
do 10 i=1
write(*,*) i
10 continue
end
With gfortran:
$gfortran test4.F
$./a.out
-259911288
with ifort:
$ifort test4.F
$./a.out
0
I know the syntax is incorrect. So both should throw compile-time errors.
Your test program is indeed not valid Fortran, but there isn't a syntax problem.
When the file has a .F suffix both gfortran and ifort assume that the program uses fixed form source. In fixed form source, blanks in statements aren't significant (outside character contexts). Your program is equivalent to:
do10i=1
write(*,*) i
10 continue
end
With comments:
do10i=1 ! Set the real variable do10i to value 1
write(*,*) i ! Write the undefined integer variable i
10 continue ! Do nothing
end ! End execution
Because of implicit typing you have a defaul real variable do10i and so there isn't a syntax error for a do control, and there isn't a do control that sets i to 1.
Instead your program is invalid because you are referencing the value of i although it hasn't first been defined (because it isn't a loop variable). But this isn't an error the compiler has to complain about at compile time (or even run time). A compiler is allowed to print any value it likes. gfortran chose one, ifort another.
Liberal use of implicit none and avoiding fixed-form source are good ways to avoid many programming errors. In this case, use of an end do instead of continue would also alert the compiler to the fact that you intended there to be some looping.
Which version of gfortran are you using? With gfortran-6, the following
PROGRAM MAIN
USE ISO_FORTRAN_ENV, ONLY:
1 COMPILER_VERSION,
2 COMPILER_OPTIONS
C EXPLICIT TYPING ONLY
IMPLICIT NONE
C VARIABLE DECLARATIONS
INTEGER I
DO 10 I = 1
WRITE (*,*) I
10 CONTINUE
PRINT '(/4A/)',
1 'THIS FILE WAS COMPILED USING ', COMPILER_VERSION(),
2 ' USING THE OPTIONS ', COMPILER_OPTIONS()
END PROGRAM MAIN
indeed throws the error
main.F:13:13:
DO 10 I = 1
1
Error: Symbol ‘do10i’ at (1) has no IMPLICIT type
I suspect that test4.F does not include the implicit none statement. Consequently, DO 10 I = 1 is interpreted as an implicitly defined real variable DO10I = 1. Here is a sample of a fixed form statement showing what are now (post Fortran 90) considered significant blanks followed by an equivalent statement without the blanks
DO I=1 , M AX ITER S
DO I = 1 , MAXITERS
Upshot, always use explicit variable declarations in all your programs. Better yet, only write Fortran in free source form main.f90. Free source form is more compatible with modern interactive input devices than fixed form. The maximum line length is 132 characters, compared to the older limit of 72 characters. This reduces the possibility of text exceeding the limit, which could lead the compiler to misinterpret names. Here's the same code in free source form
program main
use ISO_Fortran_env, only: &
stdout => OUTPUT_UNIT, &
compiler_version, &
compiler_options
! Explicit typing only
implicit none
! Variable declarations
integer :: i
do i = 1, 3
write (stdout, *) i
end do
print '(/4a/)', &
' This file was compiled using ', compiler_version(), &
' using the options ', compiler_options()
end program main
and
gfortran-6 -std=f2008ts -o main.exe main.f90
./main.exe
yields
1
2
3
This file was compiled using GCC version 6.1.1 20160802 using the options -mtune=generic -march=x86-64 -std=f2008ts
I have some legacy Fortran code which I was asked to analyze and translate to a modern language. I don't know which compiler was used in the past to compile the code, so for now, I'm trying to compile it with gfortran. The code contains a statement like this was causes gfortran to complain:
program test
implicit none
integer*4 :: var
var=.true.
if(var) then
write(*,*) "Hi"
endif
end program test
Compiling this with gfortran gives the following error:
test.f:6:9:
if(var) then
1
Error: IF clause at (1) requires a scalar LOGICAL expression
(In addition, it gives a warning about the conversion done in var=.true.).
I'm not sure which which compiler the code was compiled, but apparently the code should compile as it is. Is there a way to tell gfortran to accept this conversion?
According to the docs, no implicit conversion is done within if-statements though: https://gcc.gnu.org/onlinedocs/gfortran/Implicitly-convert-LOGICAL-and-INTEGER-values.html
This is not possible in GFortran. The manual states:
However, there is no implicit conversion of INTEGER values in
if-statements, nor of LOGICAL or INTEGER values in I/O operations.
You are only able to perform implicit conversions in assignments like your
integer :: var
var = .true.
but even there you must be very careful. It is not standard conforming and the value var will differ between compilers. Intel used to use -1 (all bits set to 1), unless -standard-semantics was chosen, for .true., but gfortran uses +1 as in the C language. New versions of Intel Fortran changes the default. The other direction is even trickier, there might be values which are neither .true. nor .false..
This question is connected to my previous question: How to force compiler to interpret omitted intent as intent(inout) . It appears impossible to interpret omitted intent as intent(inout), so problem of violation of intent(in) is still exists.
The same example:
module test
implicit none
contains
subroutine fun1(x)
real(8), intent(in)::x
call fun2(x)
end subroutine
subroutine fun2(x)
real(8) :: x
x = 10
end subroutine
end module
This code can be compiled without any errors/warnings by gfortran and ifort. So my questions is:
How to force fortran compiler to generate an error when intent(in) variable is passed to subroutine with omitted intent ( but with declared interface)?
As IanH said you need a processor (i.e. compiler) that can pick this up for you. For instance the NAG compiler does (disclaimer - I work for NAG) if you give it the right flags. I modified your code a very little to make it portable and added a driver to show this:
$ cat t.f90
module test
implicit none
Integer, Parameter :: wp = Selected_real_kind( 12, 70 )
contains
subroutine fun1(x)
real(wp), intent(in)::x
call fun2(x)
end subroutine
subroutine fun2(x)
real(wp) :: x
x = 10
end subroutine
end module
Program test_test
Use test
Implicit None
Real( wp ) :: x
x = 5.0_wp
Call fun1( x )
End Program test_test
$ nagfor t.f90
NAG Fortran Compiler Release 5.3.1 pre-release(904)
[NAG Fortran Compiler normal termination]
$ ./a.out
$ nagfor -C=all -C=undefined t.f90
NAG Fortran Compiler Release 5.3.1 pre-release(904)
[NAG Fortran Compiler normal termination]
$ ./a.out
Runtime Error: t.f90, line 15: Dummy argument X is associated with an expression - cannot assign
Program terminated by fatal error
Aborted (core dumped)
$
So search the flags, there may be something to help - if not complain to whoever supplies the compiler!
When compiled with either GNU Fortran (v4.4.3) or Sun Studio F95 (v8.3) and no array bounds checking the following program runs without error. However, when array bounds checking is switched on (gfortran -fbounds-check and f95 -C, respectively) the GNU compiled executable runs again without error, whereas the Sun Studio compiled executable gives the run-time error,
****** FORTRAN RUN-TIME SYSTEM ******
Subscript out of range. Location: line 44 column 20 of 'nosize.f90'
Subscript number 2 has value 1 in array 't$27'
That's an error in the call to sub2(), which uses an automatic array dummy argument for x. The sub1() calls run fine with either compiler and any flags.
To my knowledge this program is "legal", in that a zero sized array may be referenced like a non-zero sized array, and there is no explicit indexing of the zero length dimension of x. But is there some zero sized array slicing or automatic array subtlety that I'm missing here? And should I expect array bounds checking to behave the same across different compilers, or should I consider it a vendor-specific extension?
MODULE subs
IMPLICIT NONE
CONTAINS
SUBROUTINE sub1(x)
IMPLICIT NONE
REAL :: x(:,:)
PRINT*,'------------------------------------'
PRINT*,SHAPE(x)
PRINT*,SIZE(x)
END SUBROUTINE sub1
SUBROUTINE sub2(n1,n3,x)
IMPLICIT NONE
INTEGER,INTENT(in) :: n1, n3
REAL :: x(n1,n3)
PRINT*,'------------------------------------'
PRINT*,SHAPE(x)
PRINT*,SIZE(x)
END SUBROUTINE sub2
END MODULE subs
PROGRAM nosize
USE subs
IMPLICIT NONE
INTEGER :: n1 = 2, n2 = 2, n3 = 0
REAL,ALLOCATABLE :: x(:,:,:)
ALLOCATE(x(n1,n2,n3))
x(:,:,:) = -99.9
PRINT*,'ALLOCATED? ',ALLOCATED(x)
PRINT*,'SHAPE =',SHAPE(x)
PRINT*,'SIZE =',SIZE(x)
PRINT*,'X =',x
CALL sub1(x(:,1,:))
CALL sub2(n1,n3,x(:,1,:))
END PROGRAM nosize
It doesn't give any problems with intel's fortran compiler with -check bounds; and IBM's xlf, which in my experience is extremely strict, also didn't complain with -qcheck.
But more broadly, yes, there's no standard about what bounds checking should or shouldn't do. I can certainly see why some compilers would flag an assignment to a zero-length array as being bad/wrong/weird; it is a strange corner-case.