* 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