Fortran double precision program with a simple MKL BLAS routine - fortran

In trying to mix precision in a simple program - using both real and double - and use the ddot routine from BLAS, I'm coming up with incorrect output for the double precision piece. Here's the code:
program test
!! adding this statement narrowed the issue down to ddot being considered real(4)
implicit none
integer, parameter :: dp = kind(1.0d0)
!! The following 2 lines were added for the calls to the BLAS routines.
!! This fixed the issue.
real(dp), external :: ddot
real, external :: sdot
real, dimension(3) :: a,b
real(dp), dimension(3) :: d,e
integer :: i
do i = 1,3
a(i) = 1.0*i
b(i) = 3.5*i
d(i) = 1.0d0*i
e(i) = 3.5d0*i
end do
write (*,200) "sdot real(4) = ", sdot(3,a,1,b,1) ! should work and return 49.0
write (*,200) "ddot real(4) = ", ddot(3,a,1,b,1) ! should not work
write (*,200) "sdot real(8) = ", sdot(3,d,1,e,1) ! should not work
write (*,200) "ddot real(8) = ", ddot(3,d,1,e,1) ! should work and return 49.0
200 format(a,f5.2)
end program test
I've tried compiling with both gfortran and ifort using the MKL BLAS libraries as follows:
ifort -lmkl_intel_lp64 -lmkl_sequential -lmkl_core
gfortran -lmkl_intel_lp64 -lmkl_sequential -lmkl_core main.f90
The output is:
sdot real(4) = 49.00
ddot real(4) = 0.00
sdot real(8) = 4.10
ddot real(8) = 0.00
How can I get the ddot routine to correctly process the double precision values?
Additionally, adding the -autodouble flag (ifort) or -fdefault-real-8 (gfortran) flag makes both of the ddot routines work, but the sdot routines fail.
Edit:
I added the implicit none statement, and the two type statements for the ddot and sdot functions. Without the type specified for the function calls the ddot was being typed implicitly as single precision real.

I haven't used MKL, but perhaps you need a "use" statement so that the compiler knows the interface to the functions? Or to otherwise declare the functions. They are not declared so the compiler is probably assuming that return of ddot is single precision and mis-interpreting the bits.
Turning on the warning option causes the compiler to tell you about the problem. With gfortran, try:
-fimplicit-none -Wall -Wline-truncation -Wcharacter-truncation -Wsurprising -Waliasing -Wimplicit-interface -Wunused-parameter -fwhole-file -fcheck=all -std=f2008 -pedantic -fbacktrace

Passing incorrect kind variables is a case of interface mismatch (which is illegal, so in principle the compiler might do anything including starting WW III), so maybe this is messing up the stack and hence following calls also return incorrect results. Try to comment out those incorrect calls (your lines marked with "should not work") and see if that helps.
Also, enable all kinds of debug options you can find, as e.g. the answer by M.S.B. shows for gfortran.

Related

PGI compilation error in Fortran: "forward reference to function"

I am a little puzzled with the PGI Fortran compiler.
When I try to compiler the following simple module stored in the file named test.f90, with pgfortran 19.10 I get errors that I do not understand. While compiling with gfortran or ifort run well.
The file test.f90:
MODULE CT
IMPLICIT NONE
integer, parameter :: si = SELECTED_INT_KIND(4)
integer(kind=si), public, parameter :: strlen = 256
type, public :: CMT
integer (kind=si) :: nbTot
character(len=strlen), dimension(:), allocatable :: condi
CONTAINS
procedure :: find_line_condi
endtype CMT
CONTAINS
PURE function find_line_condi( table, cara ) result(k)
IMPLICIT NONE
class(CMT), intent(in) :: table
character(len=*), intent(in) :: cara
integer (kind=si) :: k
integer (kind=si) :: j
k=-1
do j=1,table%nbTot
if (trim(table%condi(j)) .eq. cara) then
k=j
RETURN
else if ( j == table%nbTot ) then
k=-1
RETURN
endif
enddo
end function find_line_condi
END MODULE CT
The compilation with pgfortran -c test.f90 returns me the following error message:
/opt/pgi/linux86-64-llvm/19.10/share/llvm/bin/llc: error: /opt/pgi/linux86-64-llvm/19.10/share/llvm/bin/llc: /tmp/pgfortranr2qeZBujkwvA.ll:23:77: error: invalid forward reference to function 'ct_find_line_condi_' with wrong type: expected 'i32 (i64*, i64*, i64*, i64)*' but was 'i16 (i64*, i64*, i64*, i64)*'
#ct$cmt$td$vft = global [1 x i8*] [i8* bitcast(i16 (i64*, i64*, i64*, i64)* #ct_find_line_condi_ to i8*)]
Does anyone has some ideas where this problem comes from?
This is a bug in the compiler. Consider the module
MODULE CT
IMPLICIT NONE
type CMT
CONTAINS
procedure, nopass :: find_line_condi
endtype CMT
CONTAINS
function find_line_condi()
integer(SELECTED_INT_KIND(4)) find_line_condi
find_line_condi=0
end function find_line_condi
END MODULE CT
which is quite a bit simpler than that of that question. Compiled with pgfortran 19.10 there is a similar gibberish output. It's left as an exercise to the reader/PGI support desk whether this simpler code is valid Fortran which should be accepted but I would consider the poor diagnostic to be something PGI would prefer to avoid.
However, this appears to be a weakness in the LLVM frontend of PGI: consider compiling with pgfortran -c -Mnollvm .... There are also ways to rewrite the code to attempt to work around this bug, such as changing the kind of the function result.
More widely, PGI introduced in the 2019 releases the LLVM code generator. This seems to be going through a number of teething difficulties. If you have code unexpectedly failing with PGI 2019 (which may have worked with 2018), then compiling with -Mnollvm to use the non-LLVM generator is worth a try.

Automatic allocation failing when casting from integer to real(dp)

I don't know whether I'm hitting a compiler bug or missing something. I'm attempting to run the following code:
program test
implicit none
integer, parameter :: dp=kind(1.d0)
integer, allocatable :: int_mat(:,:)
integer, allocatable :: int_mat_2(:,:)
real(dp), allocatable :: real_mat(:,:)
allocate(int_mat(2,2))
int_mat = 0
int_mat_2 = int_mat
real_mat = int_mat ! Falls over here.
end program
Compiling and running with nagfor (flags: -f2003 -C=all) works as expected. Compiling and running with gfortran (flags: -std=f2003 -fcheck=all) fails at runtime with the error message:
At line 13 of file test.f90
Fortran runtime error: Array bound mismatch for dimension 1 of array 'real_mat' (1/2)
I would expect the code to succeed, as int_mat_2 and real_mat should be allocated implicitly. This seems to be happening correctly for int_mat_2 but not for real_mat.
I have tried this with various gfortran versions (5.4, 6.3, 7.0), and all have the same problem.
As found by francescalus, this was this compiler bug, which has since been fixed for more recent gfortran versions.

division by zero doesn't work with ieee_arithmetic in gfortran 5.4

I'm using ieee_arithmetic with Fortran on a Linux machine that runs gfortran version 5.4.0.
I'm getting an error of division by zero when trying to initialize values for Inf and NaN.
There doesn't seem to be an issue with ieee_arithmetic because elsewhere in the file I can successfully call ieee_is_finite() with no issues.
I thought that ieee_arithmetic allowed division by zero to be used for these specific cases, but I must be missing something. Below is a sample of code:
module rcrlib_gnu
use, intrinsic :: ieee_arithmetic ! requires gfortran version 5.0 or higher
implicit none
integer, parameter :: SP=kind(1.0), DP=selected_real_kind(9,99)
integer, parameter :: stderr=0
public SP, DP, is_finite, stderr, initialize
contains
subroutine initialize(infty,nan)
real(kind=DP), intent(out) :: infty, nan
infty = 1.0_dp/0.0_dp ! huge(1.0_dp)
nan = 0.0_dp/0.0_dp
end subroutine initialize
elemental function is_finite(x)
real(kind=DP), intent(in) :: x
logical :: is_finite
is_finite = ieee_is_finite(x) ! This call requires "ieee_arithmetic"
end function is_finite
end module rcrlib_gnu
It seems I'm missing something basic, so I would appreciate any help.
To reproduce the error, save the above code snippet as rcrlib_gnu_example.f90 and then execute the following line:
gfortran -o rcr rcrlib_gnu_example.f90
The resulting error output is
rcrlib_gnu_example.f90:12:18:
infty = 1.0_dp/0.0_dp ! huge(1.0_dp)
1
Error: Division by zero at (1)
rcrlib_gnu_example.f90:13:16:
nan = 0.0_dp/0.0_dp
1
Error: Division by zero at (1)
Thanks to Pascal Cuoq, I solved the problem.
The version of the initialize subroutine that compiles is below:
subroutine initialize(infty,nan)
real(kind=DP), intent(out) :: infty, nan
infty = huge(1.0_dp)+100
nan = infty-infty
end subroutine initialize
So basically set infinity to be the largest floating point number plus 100, then set NaN to be the difference between infinity and itself.
Thanks, all, for your quick responses and patience with my lack of FORTRAN experience.

Calling BLAS functions

Here is a simple program
PROGRAM MAIN
implicit none
integer, PARAMETER :: N=10
real*8 :: A(N)
real*8 :: x=0.1D0
integer :: i=1
Do i=1,N
A(i)=i
end do
call dscal(N,x, A, 1)
x=dasum(N,A,1)
END PROGRAM MAIN
I compile with the command
gfortran test.f90 -o test -O1 -I /usr/include/ -L /usr/lib -lblas
While I have no problem calling the subroutine dscal I get the following error for the function dasum
test.f90:15.2:
x=dasum(N,A,1)
1
Error: Function 'dasum' at (1) has no IMPLICIT type
Should I include a certain file to define the BLAS functions?
For functions, you need to manually specify the return value (and if you are feeling posh, optionally an external):
real*8,external :: dasum
Additionally, please don't use real*8. It is not Standard-conforming, not portable and quite confusing. Instead use the kind parameter to define the precision, e.g.:
real(kind=kind(1.d0))
or the like. If you can use the ISO_Fortran_env module, use its constants REAL32 and REAL64.

How to force fortran compiler to generate an error in case of violation "intent(in)" by subroutine with omitted intent

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!