I don't know if what I am writing here is already know or not, but this is something I stumbled upon lately and thought it was worth mentioning it.
There is an inconsistency in the calling convention of gfortran compiled level 1 blas functions returning a complex or doublecomplex datatype with those functions of other well known blas libraries like GotoBlas, Intel MKL, ACML and others.
All these libraries use the calling conventions which were used by g77, i.e. functions that return type default REAL actually return the C type double, and functions that return type COMPLEX return the values via an extra argument in the calling sequence that points to where to store the return value.
Since g77 is not under development anymore, most people start to compile their blas and lapack libraries using gfortran. The so called successor of g77. One of the changes that gfortran brought along is the much easier to use calling convention of complex functions which is now identical to those of functions returning REAL data, i.e. functions that return type COMPLEX return now a C struct resembling the complex value.
Although much easier, this makes it difficult to create a general FORTRAN, C or C++ code which call these level 1 blas functions and can be used together with any of the above mentioned blas libraries.
This can be seen with some examples. We use the testfile zblat1.f and compile it with gfortran and ifort and use the libraries blas_GFORTRAN.a and libgoto.a.
- Code: Select all
$ gfortran zblat1.f blas_GFORTRAN.a
$ ./a.out
Complex BLAS Test Program Results
Test of subprogram number 1 ZDOTC
----- PASS -----
Test of subprogram number 2 ZDOTU
----- PASS -----
Test of subprogram number 3 ZAXPY
----- PASS -----
Test of subprogram number 4 ZCOPY
----- PASS -----
Test of subprogram number 5 ZSWAP
----- PASS -----
Test of subprogram number 6 DZNRM2
----- PASS -----
Test of subprogram number 7 DZASUM
----- PASS -----
Test of subprogram number 8 ZSCAL
----- PASS -----
Test of subprogram number 9 ZDSCAL
----- PASS -----
Test of subprogram number 10 IZAMAX
----- PASS -----
$ ifort zblat1.f blas_GFORTRAN.a
$ ./a.out
Complex BLAS Test Program Results
Test of subprogram number 1 ZDOTC
FAIL
CASE N INCX INCY MODE I COMP(I) TRUE(I) DIFFERENCE SIZE(I)
1 1 1 1 9999 1 0.00000000D+00 0.90000000D+00 -0.9000D+00 0.9000D+00
1 1 1 1 9999 2 0.00000000D+00 0.60000000D-01 -0.6000D-01 0.9000D+00
1 2 1 1 9999 1 0.00000000D+00 0.91000000D+00 -0.9100D+00 0.1630D+01
1 2 1 1 9999 2 0.00000000D+00 -0.77000000D+00 0.7700D+00 0.1730D+01
1 4 1 1 9999 1 0.00000000D+00 0.18000000D+01 -0.1800D+01 0.2900D+01
1 4 1 1 9999 2 0.00000000D+00 -0.10000000D+00 0.1000D+00 0.2780D+01
1 1 2 -2 9999 1 0.00000000D+00 0.90000000D+00 -0.9000D+00 0.9000D+00
1 1 2 -2 9999 2 0.00000000D+00 0.60000000D-01 -0.6000D-01 0.9000D+00
1 2 2 -2 9999 1 0.00000000D+00 0.14500000D+01 -0.1450D+01 0.1630D+01
1 2 2 -2 9999 2 0.00000000D+00 0.74000000D+00 -0.7400D+00 0.1730D+01
1 4 2 -2 9999 1 0.00000000D+00 0.20000000D+00 -0.2000D+00 0.2900D+01
1 4 2 -2 9999 2 0.00000000D+00 0.90000000D+00 -0.9000D+00 0.2780D+01
1 1 -2 1 9999 1 0.00000000D+00 0.90000000D+00 -0.9000D+00 0.9000D+00
1 1 -2 1 9999 2 0.00000000D+00 0.60000000D-01 -0.6000D-01 0.9000D+00
1 2 -2 1 9999 1 0.00000000D+00 -0.55000000D+00 0.5500D+00 0.1630D+01
1 2 -2 1 9999 2 0.00000000D+00 0.23000000D+00 -0.2300D+00 0.1730D+01
1 4 -2 1 9999 1 0.00000000D+00 0.83000000D+00 -0.8300D+00 0.2900D+01
1 4 -2 1 9999 2 0.00000000D+00 -0.39000000D+00 0.3900D+00 0.2780D+01
1 1 -1 -2 9999 1 0.00000000D+00 0.90000000D+00 -0.9000D+00 0.9000D+00
1 1 -1 -2 9999 2 0.00000000D+00 0.60000000D-01 -0.6000D-01 0.9000D+00
1 2 -1 -2 9999 1 0.00000000D+00 0.10400000D+01 -0.1040D+01 0.1630D+01
1 2 -1 -2 9999 2 0.00000000D+00 0.79000000D+00 -0.7900D+00 0.1730D+01
1 4 -1 -2 9999 1 0.00000000D+00 0.19500000D+01 -0.1950D+01 0.2900D+01
1 4 -1 -2 9999 2 0.00000000D+00 0.12200000D+01 -0.1220D+01 0.2780D+01
Test of subprogram number 2 ZDOTU
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image PC Routine Line Source
a.out 00000000004079C6 Unknown Unknown Unknown
a.out 000000000040374A Unknown Unknown Unknown
a.out 00000000004028E2 Unknown Unknown Unknown
libc.so.6 00002B3BE46F0AE4 Unknown Unknown Unknown
a.out 0000000000402829 Unknown Unknown Unknown
[klaas@talvin10 blas]$ gfortran zblat1.f libgoto.a -lpthread
[klaas@talvin10 blas]$ ./a.out
Complex BLAS Test Program Results
Test of subprogram number 1 ZDOTC
Segmentation fault
$ ifort zblat1.f libgoto.a -lpthread
$ ./a.out
Complex BLAS Test Program Results
Test of subprogram number 1 ZDOTC
----- PASS -----
Test of subprogram number 2 ZDOTU
----- PASS -----
Test of subprogram number 3 ZAXPY
----- PASS -----
Test of subprogram number 4 ZCOPY
----- PASS -----
Test of subprogram number 5 ZSWAP
----- PASS -----
Test of subprogram number 6 DZNRM2
----- PASS -----
Test of subprogram number 7 DZASUM
----- PASS -----
Test of subprogram number 8 ZSCAL
----- PASS -----
Test of subprogram number 9 ZDSCAL
----- PASS -----
Test of subprogram number 10 IZAMAX
----- PASS -----
Analogue problems can be found when calling the libraries from C or C++. The function definition from the above mentioned libraries should be of the form
- Code: Select all
extern "C" {
void cdotc_(std::complex<float> *result, long *, std::complex<float> *, long *, std::complex<float> *, long *);
}
while for the gfortran compiled version you have to define it as
- Code: Select all
extern "C" {
std::complex<float> cdotc_(long *, std::complex<float> *, long *, std::complex<float> *, long *);
}
and fails to work with any of the above libraries.
I don't really see immediately a solution to this problem, maybe some coding gurus know their way out of this. But I would keep the following rules in mind when using gfortran.
- If you are sure you will only use gfortran for your code without any external blas libraries, compile the libraries with gfortran as mentioned in the make.inc examples.
- If you have a fortran code and you would like to link it with other blas libraries, compile your code with ifort or gfortran -ff2c or any other fortran compiler that uses the g77 conventions.
- If you intend to write a portable code FORTRAN/C/C++ but have no access to other blas libraries, compile them with gfortran -ff2c
If you did the above and your code is fortran, always use the -ff2c flag.
One real solution I would see is changing the level 1 blas functions into subroutines. But since BLAS and LAPACK are already so well known and have been used for several years in programs which still run now, I don't think those developers would like the idea to checking their code to see if they use any of those 7 functions.
With kind regards
Klaas

