LAPACK Archives

[Lapack] Note on some Fortran calling conventions.

Just a quick note that may prevent others from making 
forehead-sized holes in their office walls.  Different
Fortran compilers return REAL and COMPLEX results in
different ways.  This affects the binding work in some
unpleasant ways.

Also, you cannot combine libraries compiled with
different compilers unless you're very, very careful.
Some vendors (Intel) support only one compiler's
conventions, and others (AMD) provide optimized
libraries for 6 different compilers.

Below I'm assuming that a Fortran REAL is equivalent
to a C float.  You can tell some compilers to make
REALs equivalent to double, but that's another mess.
I'm ignoring name mangling (translating a Fortran name
FOO to C name foo_), which also is subject to random
compiler defaults and flags.

The f2c compiler defined a set of Fortran calling
conventions appropriate for C at the time.  Other 
compilers, _including gfortran_ have adopted more
"modern" conventions.

Some current compilers, including g77 and ifort, have
kept the f2c conventions.  Two important aspects are
the following:

  1) Single-precision REAL variables are returned as
double-precision results.  So 
        REAL FUNCTION FOO ()
          FOO = 1.0
        END
acts like
        double foo() { return (double)1.0f; }
The _value_ returned fits in single precision, but the
slot used to return it is double.

  2) Complex results are returned in an extra argument.
        COMPLEX FUNCTION BAR (X)
          REAL X
          BAR = (X, -1.0)
        END
acts like
        void bar(float x, float _Complex *out)
        { *out = x - 1.0f * _Complex_I; }

Now most users (including me) mis-declare C bindings
for the first case.  I had been using "float foo()".
On systems with wide floating-point registers, the
wrong binding often works correctly and you never see
the problem.  The return value slot is just a register
regardless of the data's type.  The second one's a
killer on any platform.  (Which explains a problem
we had with clarnd() in the itref code once upon a
time.)

Other compilers, like gfortran by default, would make
the two routines above act like the more straight-
forward:
  1) float foo() { return 1.0f; }
  2) float _Complex bar(float x)
     { return x - 1.0f * _Complex_I; }

Coping with the first case in bindings is relatively
easy.  The latter case is similar to the hell of passing
strings between C and Fortran.  It's solvable, but not
by simple CPP macro trickery.

In the particular case of gfortran, you can tell it
to use the f2c calling conventions by passing -ff2c.

Jason

<Prev in Thread] Current Thread [Next in Thread>


For additional information you may use the LAPACK/ScaLAPACK Forum.
Or one of the mailing lists, or