comp.lang.ada
 help / color / mirror / Atom feed
* Making the same mistake as the broken C interface to fortran
@ 2019-06-24 23:33 Chris M Moore
  2019-07-02 20:57 ` Simon Wright
  0 siblings, 1 reply; 9+ messages in thread
From: Chris M Moore @ 2019-06-24 23:33 UTC (permalink / raw)


Hi,

Read this interesting article today:

https://lwn.net/SubscriberLink/791393/41d57555202e8cdb/

Synopsis: C interfaces to Fortran makes some assumptions about how to 
call fortran ABIs (I don't need to pass the hidden length parameter if 
its a character*1) but now Gfortran has optimisations which assume a 
different calling convention (Thou shalt pass the hidden length).

There are work arounds (compile fortran with 
‑fno‑optimize‑sibling‑calls) but it seems that the proper fix is to pass 
the hidden length parameter.

I had a quick look at the LAPACK bindings and they both seem to use Ada 
characters. :/

-- 
sig pending (since 1995)


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Making the same mistake as the broken C interface to fortran
  2019-06-24 23:33 Making the same mistake as the broken C interface to fortran Chris M Moore
@ 2019-07-02 20:57 ` Simon Wright
  2019-07-03  7:06   ` Chris M Moore
  0 siblings, 1 reply; 9+ messages in thread
From: Simon Wright @ 2019-07-02 20:57 UTC (permalink / raw)


Chris M Moore <zmower@ntlworld.com> writes:

> Read this interesting article today:
>
> https://lwn.net/SubscriberLink/791393/41d57555202e8cdb/
>
> Synopsis: C interfaces to Fortran makes some assumptions about how to
> call fortran ABIs (I don't need to pass the hidden length parameter if
> its a character*1) but now Gfortran has optimisations which assume a
> different calling convention (Thou shalt pass the hidden length).
>
> There are work arounds (compile fortran with
> ‑fno‑optimize‑sibling‑calls) but it seems that the proper fix is to
> pass the hidden length parameter.
>
> I had a quick look at the LAPACK bindings and they both seem to use
> Ada characters. :/

The code generated with Convention=Fortran should abide by the ABI, and
if that says to pass a hidden length parameter then that's what should
happen.

I don't know enough x86_64 (or thumb) assembler to be at all sure, but
it looks to me as though no length parameter gets passed.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Making the same mistake as the broken C interface to fortran
  2019-07-02 20:57 ` Simon Wright
@ 2019-07-03  7:06   ` Chris M Moore
  2019-07-03 19:02     ` Randy Brukardt
  0 siblings, 1 reply; 9+ messages in thread
From: Chris M Moore @ 2019-07-03  7:06 UTC (permalink / raw)


On 02/07/2019 21:57, Simon Wright wrote:
> Chris M Moore <zmower@ntlworld.com> writes:
> 
>> Read this interesting article today:
>>
>> https://lwn.net/SubscriberLink/791393/41d57555202e8cdb/
>>
>> Synopsis: C interfaces to Fortran makes some assumptions about how to
>> call fortran ABIs (I don't need to pass the hidden length parameter if
>> its a character*1) but now Gfortran has optimisations which assume a
>> different calling convention (Thou shalt pass the hidden length).
>>
>> There are work arounds (compile fortran with
>> ‑fno‑optimize‑sibling‑calls) but it seems that the proper fix is to
>> pass the hidden length parameter.
>>
>> I had a quick look at the LAPACK bindings and they both seem to use
>> Ada characters. :/
> 
> The code generated with Convention=Fortran should abide by the ABI, and
> if that says to pass a hidden length parameter then that's what should
> happen.
> 
> I don't know enough x86_64 (or thumb) assembler to be at all sure, but
> it looks to me as though no length parameter gets passed.
> 

Hi Simon,

So the question is do we break the API or not?  We could make the 
bindings thicker and thus slower.  Or break the typing and force client 
software to change.  The software engineer in me says the former but I'm 
not a user of this API so I doubt my views count for much.

-- 
sig pending (since 1995)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Making the same mistake as the broken C interface to fortran
  2019-07-03  7:06   ` Chris M Moore
@ 2019-07-03 19:02     ` Randy Brukardt
  2019-07-03 21:31       ` Chris M Moore
  0 siblings, 1 reply; 9+ messages in thread
From: Randy Brukardt @ 2019-07-03 19:02 UTC (permalink / raw)


"Chris M Moore" <zmower@ntlworld.com> wrote in message 
news:2uYSE.298383$sJ3.119314@fx04.am4...
...
> So the question is do we break the API or not?

That's not the question. The question is ensuring that the Ada compiler 
properly implements the Fortran convention. If it does, then the API doesn't 
change. And if it doesn't, then fix the silly compiler (or get a different 
one that does the right thing). The Annex B "Implementation Advice" 
(specifically, B.5(22-26)) is very close to a requirement, in that the 
interface is not useful if one can't depend on the mapping.

If your worrying about what hack to use to make a broken compiler work 
(hopefully only because you need an immediate solution), the answer ought to 
be that no one cares -- do whatever makes sense. Because no one should be 
*requiring* an Ada compiler to do the wrong thing, so when the bug is 
ultimately fixed, you'll have to revert to some version of the original API. 
(That to me suggests using a thicker binding -- which is always preferable 
anyway IMHO -- raw C or Fortran interfaces don't make good Ada libraries.)

BTW, I note that type Fortran_Character is in fact an array type, so that 
could be confusing some readers of the API (it surely would have confused 
me).

                                                     Randy.












We could make the
> bindings thicker and thus slower.  Or break the typing and force client 
> software to change.  The software engineer in me says the former but I'm 
> not a user of this API so I doubt my views count for much.
>
> -- 
> sig pending (since 1995) 


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Making the same mistake as the broken C interface to fortran
  2019-07-03 19:02     ` Randy Brukardt
@ 2019-07-03 21:31       ` Chris M Moore
  2019-07-04  8:38         ` Simon Wright
  0 siblings, 1 reply; 9+ messages in thread
From: Chris M Moore @ 2019-07-03 21:31 UTC (permalink / raw)


On 03/07/2019 20:02, Randy Brukardt wrote:
> "Chris M Moore" <zmower@ntlworld.com> wrote in message
> news:2uYSE.298383$sJ3.119314@fx04.am4...
> ...
>> So the question is do we break the API or not?
> 
> That's not the question. The question is ensuring that the Ada compiler
> properly implements the Fortran convention. If it does, then the API doesn't
> change. And if it doesn't, then fix the silly compiler (or get a different
> one that does the right thing). The Annex B "Implementation Advice"
> (specifically, B.5(22-26)) is very close to a requirement, in that the
> interface is not useful if one can't depend on the mapping.
> 
<snip>
> 
> BTW, I note that type Fortran_Character is in fact an array type, so that
> could be confusing some readers of the API (it surely would have confused
> me).

I'm sure GNAT does the right thing if you're using Fortran_Character. 
Unfortunately the bindings use Standard.Character.

>> We could make the
>> bindings thicker and thus slower.  Or break the typing and force client
>> software to change.  The software engineer in me says the former but I'm
>> not a user of this API so I doubt my views count for much.

Or maybe the answer is both.  Leave in the Character interface with a 
body to do the conversion and add another version to do the thin wrapper 
using Fortran_Character.  Nothing breaks but if speed becomes a problem 
then switch to using the proper thin version.

Chris

-- 
sig pending (since 1995)


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Making the same mistake as the broken C interface to fortran
  2019-07-03 21:31       ` Chris M Moore
@ 2019-07-04  8:38         ` Simon Wright
  2019-07-05 13:49           ` Chris M Moore
  0 siblings, 1 reply; 9+ messages in thread
From: Simon Wright @ 2019-07-04  8:38 UTC (permalink / raw)


Chris M Moore <zmower@ntlworld.com> writes:

> On 03/07/2019 20:02, Randy Brukardt wrote:
>> "Chris M Moore" <zmower@ntlworld.com> wrote in message
>> news:2uYSE.298383$sJ3.119314@fx04.am4...
>> ...
>>> So the question is do we break the API or not?
>>
>> That's not the question. The question is ensuring that the Ada
>> compiler properly implements the Fortran convention. If it does, then
>> the API doesn't change. And if it doesn't, then fix the silly
>> compiler (or get a different one that does the right thing). The
>> Annex B "Implementation Advice" (specifically, B.5(22-26)) is very
>> close to a requirement, in that the interface is not useful if one
>> can't depend on the mapping.
>>
> <snip>
>>
>> BTW, I note that type Fortran_Character is in fact an array type, so
>> that could be confusing some readers of the API (it surely would have
>> confused me).

It confused the heck out of me, too. You'd've expected a warning at
least if you use a dodgy parameter type!

I did a little poking around with GCC 9.1.0:

Fortran:

      subroutine callee (c)
      character (1), intent (in) :: c

      print *, 'parameter c is ', c

      end

Ada:

with Interfaces.Fortran;
procedure Call is
   procedure Callee_C (C : Character)
   with
     Import,
     Convention => Fortran,
     External_Name => "callee_";
   procedure Callee_F (C : Interfaces.Fortran.Fortran_Character)
   with
     Import,
     Convention => Fortran,
     External_Name => "callee_";
   procedure Callee_S (S : String)
   with
     Import,
     Convention => Fortran,
     External_Name => "callee_";
begin
   Callee_C ('c');
   Callee_F ((1 => 'f'));
   Callee_F ("F string");
   Callee_S ("A string");
end Call;

Result:

$ gfortran -c callee.f
$ gnatmake -gnatwa call.adb -largs callee.o -lgfortran
gcc -c -gnatwa call.adb
gnatbind -x call.ali
gnatlink call.ali callee.o -lgfortran
$ ./call
 parameter c is c
 parameter c is f
 parameter c is F
 parameter c is A
 
> I'm sure GNAT does the right thing if you're using
> Fortran_Character. Unfortunately the bindings use Standard.Character.

Which bindings are those? I can certainly look at changing the ones in
gnat-math-extn (Should be https://sf.net/p/gnat-math-extn, but down at
the moment), but those are entirely internal.

====================

For what it's worth, the issue is that a long-standing feature of the
Fortran ABI is that 'character' is an array type, so that the fat
parameter contains (1) the address of the first element and (2) the
length of the actual (I'm not sure whether these two parts are
necessarily contiguous). If the Fortran only ever accesses the first
element, it doesn't matter if the length part is never actually passed
on the stack, which is what happens when Ada or C passes Character or
char rsp.

However, with a new optimisation, if the Fortran compiler recognises an
opportunity for "tail recursion" (or a sibling call), it reuses
the current stack arguments for the sibling call, including the length
component of the character argument. If that length component was never
actually pushed by the original caller, oops, trashed stack.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Making the same mistake as the broken C interface to fortran
  2019-07-04  8:38         ` Simon Wright
@ 2019-07-05 13:49           ` Chris M Moore
  2019-07-05 17:44             ` Simon Wright
  0 siblings, 1 reply; 9+ messages in thread
From: Chris M Moore @ 2019-07-05 13:49 UTC (permalink / raw)


On 04/07/2019 09:38, Simon Wright wrote:
> Chris M Moore <zmower@ntlworld.com> writes:
> 
>> On 03/07/2019 20:02, Randy Brukardt wrote:
>>> "Chris M Moore" <zmower@ntlworld.com> wrote in message
>>> news:2uYSE.298383$sJ3.119314@fx04.am4...
>>> ...
>>>> So the question is do we break the API or not?
>>>
>>> That's not the question. The question is ensuring that the Ada
>>> compiler properly implements the Fortran convention. If it does, then
>>> the API doesn't change. And if it doesn't, then fix the silly
>>> compiler (or get a different one that does the right thing). The
>>> Annex B "Implementation Advice" (specifically, B.5(22-26)) is very
>>> close to a requirement, in that the interface is not useful if one
>>> can't depend on the mapping.
>>>
>> <snip>
>>>
>>> BTW, I note that type Fortran_Character is in fact an array type, so
>>> that could be confusing some readers of the API (it surely would have
>>> confused me).
> 
> It confused the heck out of me, too. You'd've expected a warning at
> least if you use a dodgy parameter type!

Agreed.

> I did a little poking around with GCC 9.1.0:
> 
> Fortran:
> 
>        subroutine callee (c)
>        character (1), intent (in) :: c
> 
>        print *, 'parameter c is ', c
> 
>        end

I'm having flashbacks.  Send help. ;)

> Ada:
> 
> with Interfaces.Fortran;
> procedure Call is
>     procedure Callee_C (C : Character)
>     with
>       Import,
>       Convention => Fortran,
>       External_Name => "callee_";
>     procedure Callee_F (C : Interfaces.Fortran.Fortran_Character)
>     with
>       Import,
>       Convention => Fortran,
>       External_Name => "callee_";
>     procedure Callee_S (S : String)
>     with
>       Import,
>       Convention => Fortran,
>       External_Name => "callee_";
> begin
>     Callee_C ('c');

I've looked at the assembler for this.  Passing 'c' results in only a 
byte pushed to the stack.  And then (aha!) the address on the stack is 
placed in the rdi register.

>     Callee_F ((1 => 'f'));
>     Callee_F ("F string");
>     Callee_S ("A string");

These pass the address of a fixed string (in the ro text area) in the 
rdi register.

> end Call;
> 
> Result:
> 
> $ gfortran -c callee.f
> $ gnatmake -gnatwa call.adb -largs callee.o -lgfortran
> gcc -c -gnatwa call.adb
> gnatbind -x call.ali
> gnatlink call.ali callee.o -lgfortran
> $ ./call
>   parameter c is >   parameter c is f
>   parameter c is F
>   parameter c is A

So it works at the moment for the small example we have.

>> I'm sure GNAT does the right thing if you're using
>> Fortran_Character. Unfortunately the bindings use Standard.Character.
> 
> Which bindings are those?

I was looking at the LAPACK ones on sourceforge.

> I can certainly look at changing the ones in
> gnat-math-extn (Should be https://sf.net/p/gnat-math-extn, but down at
> the moment), but those are entirely internal.

I'd wait until we have conclusive proof we have a problem.  I'll do some 
more digging.

<snip>

-- 
sig pending (since 1995)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Making the same mistake as the broken C interface to fortran
  2019-07-05 13:49           ` Chris M Moore
@ 2019-07-05 17:44             ` Simon Wright
  2019-07-07 16:33               ` Chris M Moore
  0 siblings, 1 reply; 9+ messages in thread
From: Simon Wright @ 2019-07-05 17:44 UTC (permalink / raw)


Chris M Moore <zmower@ntlworld.com> writes:

> On 04/07/2019 09:38, Simon Wright wrote:
>> procedure Call is
>>     procedure Callee_C (C : Character)
>>     with
>>       Import,
>>       Convention => Fortran,
>>       External_Name => "callee_";
>>     procedure Callee_F (C : Interfaces.Fortran.Fortran_Character)
>>     with
>>       Import,
>>       Convention => Fortran,
>>       External_Name => "callee_";
>>     procedure Callee_S (S : String)
>>     with
>>       Import,
>>       Convention => Fortran,
>>       External_Name => "callee_";
>> begin
>>     Callee_C ('c');
>
> I've looked at the assembler for this.  Passing 'c' results in only a
> byte pushed to the stack.  And then (aha!) the address on the stack is
> placed in the rdi register.

Because all Fortran parameters are passed by reference.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Making the same mistake as the broken C interface to fortran
  2019-07-05 17:44             ` Simon Wright
@ 2019-07-07 16:33               ` Chris M Moore
  0 siblings, 0 replies; 9+ messages in thread
From: Chris M Moore @ 2019-07-07 16:33 UTC (permalink / raw)


On 05/07/2019 18:44, Simon Wright wrote:
> Chris M Moore <zmower@ntlworld.com> writes:
> 
>> On 04/07/2019 09:38, Simon Wright wrote:
>>> procedure Call is
>>>      procedure Callee_C (C : Character)
>>>      with
>>>        Import,
>>>        Convention => Fortran,
>>>        External_Name => "callee_";
>>>      procedure Callee_F (C : Interfaces.Fortran.Fortran_Character)
>>>      with
>>>        Import,
>>>        Convention => Fortran,
>>>        External_Name => "callee_";
>>>      procedure Callee_S (S : String)
>>>      with
>>>        Import,
>>>        Convention => Fortran,
>>>        External_Name => "callee_";
>>> begin
>>>      Callee_C ('c');
>>
>> I've looked at the assembler for this.  Passing 'c' results in only a
>> byte pushed to the stack.  And then (aha!) the address on the stack is
>> placed in the rdi register.
> 
> Because all Fortran parameters are passed by reference.


I spoke too soon when I said

 > I'm sure GNAT does the right thing if you're using Fortran_Character.

If I change callee.f to

       subroutine callee (c)
       character (len=*), intent (in) :: c

       print *, 'parameter c is ', c

       end

then STORAGE_ERROR is the order of the day no matter the call used. 
Looking at the assembler, this is because GNAT does not pass the length 
of the string.

I compared it to fcall.f:

       program fcall
       call callee("OK")
       call callee("Oh noes")
       stop
       end

and this unsurprisingly does pass the lengths.

I've used the webform on the Community section of the GNAT website to 
provide feedback.  I've pointed out that the issue also affects single 
chacter parameters.

Chris

-- 
sig pending (since 1995)


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-07-07 16:33 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-24 23:33 Making the same mistake as the broken C interface to fortran Chris M Moore
2019-07-02 20:57 ` Simon Wright
2019-07-03  7:06   ` Chris M Moore
2019-07-03 19:02     ` Randy Brukardt
2019-07-03 21:31       ` Chris M Moore
2019-07-04  8:38         ` Simon Wright
2019-07-05 13:49           ` Chris M Moore
2019-07-05 17:44             ` Simon Wright
2019-07-07 16:33               ` Chris M Moore

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox