[MPI3 Fortran] Fwd: [Mpi-comments] MPI 3.0: Fortran 2008 interface - issue with the LOGICAL kind
Tobias Burnus
burnus at net-b.de
Thu Feb 28 16:10:58 CST 2013
N.M. Maclaren wrote:
> Drop ALL of the BIND(C) from the functions, as they aren't currently
> conforming. Plain INTEGER is not guaranteed to be
> interoperable, and nor is DOUBLE PRECISION (Wtime, Wtick). I hope to
> make default types more interoperable in the next standard, but
> that hasn't even been discussed yet.
That's probably the simplest. The actual implementation might even use C
binding in this case, iff the Fortran interface is already interopable
with C, e.g. integer matches "int" etc. For logicals, it could either
make sure to only use the .true./.false. values for the Fortran compiler
or to ensure other values are properly handled. [0 and 1 seems work
correctly with all compilers I tested and might be a reasonable
assumption for an implementation (but not the MPI spec itself).] Whether
there is a bind(C) or not should undetectable from the user program. If
the Fortran interface is not interoperable, the MPI implementation can
then still use a wrapper.
N.M. Maclaren wrote:
> On Feb 28 2013, Craig Rasmussen wrote:
>>> The real question is what (integer) value does .TRUE._C_BOOL have?
Currently? My experience is that you get with most compilers 1 but with
some compilers -1.
>> Would great damage be done to the international standard gods if
>> .TRUE._C_BOOL evaluates to the integer value 1? I guess the C
>> programmer has to know what value (not processor dependent) to set it to.
Well, the C99 standard states: "When any scalar value is converted to
_Bool, the result is 0 if the value compares equal to 0;
otherwise, the result is 1." ("6.3.1.2 Boolean type").
> I can't see why it should be. It's not the solution I proposed, but is
> in many ways simpler.
I also do no see a problem with requiring that .TRUE._C_BOOL evaluates
to 1. One could argue that the current standard (F2008 combined with
C99) already mandates this for interoperability. (A clarification in the
Fortran standard wouldn't harm, however.)
(But I do not see how that would help. The problem with the current MPI
specification is not that logical(C_BOOL) doesn't interoperate with
_Bool but that it currently uses "LOGICAL", which is on most systems not
the same as _Bool.)
Bill Long wrote:
> The fatal flaw in the MPI interface here is that the corresponding C
> formal parameter is not _Bool or anything that looks like LOGICAL.
> Instead it is 'int'.
I mostly concur, except that the Fortran and the C code do not need to
have the same data type. (Well, unless one insists that the binding name
is the same, which the current MPI spec implies via "bind(C)".) If one
doesn't require the same binding name, one could use logical(C_bool) or
something else on the Fortran side – while C uses "int".
Craig Rasmussen wrote:
> 1. Suppose a compiler has a default logical size equivalent to a
> default integer. Since the standard only requires one logical kind,
> this compiler may not have a type that is interoperable with a _Bool C
> type. In this instance C_BOOL would be a negative value.
As written, 32bit Darwin seems to use sizeof(_Bool) == 4 by default.
And, thus, sizeof(int)==sizeof(_Bool). However, that doesn't imply that
a compiler cannot support _Bool. It just means that _Bool only should
have the values 0 and 1 while "int" can have any value. That's not
different to the more common sizeof(_Bool) == 1, which is not the same
as "signed char" even if both have the same size. In any case, the byte
size is independent from whether the Fortran+accompanying C compiler
supports _Bool or not (i.e. c_bool < 0).
> 3. Suppose a Fortran compiler has the following mapping:
> _Bool flag = 0; /* flag maps to .FALSE. */
> if (flag != 0) ...; /* flag maps to .TRUE. */
> This seems to me to be the sane way to map values from C to Fortran.
> The same mapping can be done for any C integer type to an equivalently
> sized Fortran LOGICAL.
First, in C99, "flag != 0" is not a _Bool but an "int" (see C99, "6.5.9
Equality operators"). Secondly, is it completely unclear what you mean
by "a Fortran compiler has". "flag != 0" is not a valid Fortran
expression and whether the compiler translates a "logical(c_bool)"
variable into assembler code which resembles "flag != 0" or not is
really compiler dependent. A simple "if(flag)" on an x86 system will
likely be translated into "jz" or "jnz" (jump if zero or jump if not
zero); that will regard any nonzero integer as .true. However, ".not."
can be implemented by flipping a single bit, if true is always "1" (or,
e.g., "-1"). If the compiler expects 0 and 1 and flips the respective
bit, then ".not." of "-1" will give "-2" which in conditions (via
jz/jnz) is regarded as .true. as is -1. That issue occurs with GCC for
Fortran's logicals (and also for C99's _Bool); seemingly, NAG's Fortran
compiler does something similar in some cases.
N.M. Maclaren wrote:
> On Feb 28 2013, Craig Rasmussen wrote:
>>> (3) Or one forces the compiler to accept also other values than
>>> .true./.false. As with the previous item, it will affect also all
>>> non-Bind(C) logicals. And C_Bool should presumably excluded as one
>>> otherwise might get in trouble with the C compiler.
>>
>> It seems it has to anyway to be compatible with C. I don't have the
>> C99 standard but it appears that there isn't a constant for "true"
>> and "false" without including stdbool.h. Thus a Fortran compiler will
>> have to anticipate values other than .true./.false.
>
> true and false are specified to be 1 and zero in stdbool.h.
I think most C programmers regard them as canonical values for true and
false - and use them as such. (It is also in line with C99's _Bool).
Also from the Fortran side I would be fine with using those. (I am not
sure whether all vendors would be.) However, it is nearly certain that
most C programmer will assume that "int" <-> logical(c_int) will work
such that any nonzero integer is regarded as .true., even if we write in
the Fortran standard that only 1 and 0 are supported. That will lead to
difficult to find wrong-code problems, which depend on the compiler, the
optimization flag and the expression.
>>> (4) Last, handling dummy arguments/result variables of BIND(C)
>>> procedures differently. That probably would work, but it requires a
>>> bunch of the careful addition of additional constraints. For
>>> instance, to prohibit the TARGET/POINTER attribute for those.
>>
>> To me this is the only sane response given that C evaluates 0 to
>> false and everything else to true. Nick you want to weigh in on the C
>> standard.
>
> Tempting, but no. I will say that I can see no reason to prohibit the
> TARGET/POINTER attribute according to whether BIND(C) is there.
Do you mean in terms of the consistency/conciseness of the standard? Or
in terms of a reason why it would be needed?
I assume the former. But regarding the latter: Assume "-1" is passed to
a "LOGICAL(kind=4), target :: dummy". Then "logical(kind=4), pointer ::
ptr; ptr => dummy" will cause problems: Either "ptr" is "-1" but the
compiler does not know that the value has to be treated in a special
way. Or the compiler changes "ptr" to "1" on entering the BIND(C)
procedure – which gives a segfault if "-2" is in read-only memory. Or it
creates a copy, which doesn't work as soon as the value is changed
through "ptr" and read via "dummy" (or vice versa). Thus, prohibiting
TARGET/POINTER seems to be required to allow for a different internal
representation.
I can perfectly understand that one doesn't want to go this route, but
if one does, such a constraint seems to be required.
Tobias
More information about the mpiwg-fortran
mailing list