comp.lang.ada
 help / color / mirror / Atom feed
* How do typical Ada calling conventions work ?
@ 2015-08-21  8:37 Hadrien Grasland
  2015-08-21 10:41 ` Markus Schöpflin
  2015-08-25 18:38 ` gautier_niouzes
  0 siblings, 2 replies; 11+ messages in thread
From: Hadrien Grasland @ 2015-08-21  8:37 UTC (permalink / raw)


I am currently having fun re-implementing some of Numerical Recipes' code snippets in Ada. Since this is just a personal project, I do not care about scaling to very large matrices/vectors, so I chose to keep things simple by allocating arrays on the stack, rather than on the heap. But then I suddenly found myself wondering what kind of implementation magic made my code work at all.

Let me elaborate: in the C family, as far as I know, programming language rules enforce that the size of almost any variable, including function results, must be known at compile-time, with C99 VLAs as a notable exception.

This makes it easy for implementations to devise calling conventions : the caller can allocate as much space as needed for the return value in registers or on the stack frame, right before pushing parameters. Upon function return, the caller will find the result where it would expect it.

However, as far as I can tell, Ada does not offer this guarantee : if I write this code, for example...

"type Unconstrained_Array is array (Positive range <>) of Integer;

function Make_Array return Unconstrained_Array;"

...there is no way for a caller of Make_Array to tell, in advance, how big the function's result will be. So only the callee knows enough to allocate space for its return value.

Does someone know how typical Ada implementations manage to cope with this, and if it varies a lot from one implementation to another ?

Thanks in advance,
Hadrien

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

* Re: How do typical Ada calling conventions work ?
  2015-08-21  8:37 How do typical Ada calling conventions work ? Hadrien Grasland
@ 2015-08-21 10:41 ` Markus Schöpflin
  2015-08-21 12:47   ` Niklas Holsti
  2015-08-25 18:38 ` gautier_niouzes
  1 sibling, 1 reply; 11+ messages in thread
From: Markus Schöpflin @ 2015-08-21 10:41 UTC (permalink / raw)


Am 21.08.2015 um 10:37 schrieb Hadrien Grasland:

> Does someone know how typical Ada implementations manage to cope with this, and if it varies a lot from one implementation to another ?

GNAT allocates such objects on the secondary stack. Quote from the user guide:

---%<---
`-Dnn[k|m]'
This switch can be used to change the default secondary stack size value to a 
specified size nn, which is expressed in bytes by default, or in kilobytes 
when suffixed with k or in megabytes when suffixed with m.

The secondary stack is used to deal with functions that return a variable 
sized result, for example a function returning an unconstrained String. There 
are two ways in which this secondary stack is allocated.

For most targets, the secondary stack is growing on demand and is allocated as 
a chain of blocks in the heap. The -D option is not very relevant. It only 
give some control over the size of the allocated blocks (whose size is the 
minimum of the default secondary stack size value, and the actual size needed 
for the current allocation request).

For certain targets, notably VxWorks 653, the secondary stack is allocated by 
carving off a fixed ratio chunk of the primary task stack. The -D option is 
used to define the size of the environment task's secondary stack.
--->%---

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

* Re: How do typical Ada calling conventions work ?
  2015-08-21 10:41 ` Markus Schöpflin
@ 2015-08-21 12:47   ` Niklas Holsti
  2015-08-22  8:31     ` Hadrien Grasland
  0 siblings, 1 reply; 11+ messages in thread
From: Niklas Holsti @ 2015-08-21 12:47 UTC (permalink / raw)


On 15-08-21 13:41 , Markus Schöpflin wrote:
> Am 21.08.2015 um 10:37 schrieb Hadrien Grasland:
>
>> Does someone know how typical Ada implementations manage to cope with
>> this, and if it varies a lot from one implementation to another ?
>
> GNAT allocates such objects on the secondary stack. Quote from the user
> guide:
>
> ---%<---
> `-Dnn[k|m]'
> This switch can be used to change the default secondary stack size value
> to a specified size nn, which is expressed in bytes by default, or in
> kilobytes when suffixed with k or in megabytes when suffixed with m.
>
> The secondary stack is used to deal with functions that return a
> variable sized result, for example a function returning an unconstrained
> String. There are two ways in which this secondary stack is allocated.
>
> For most targets, the secondary stack is growing on demand and is
> allocated as a chain of blocks in the heap. The -D option is not very
> relevant. It only give some control over the size of the allocated
> blocks (whose size is the minimum of the default secondary stack size
> value, and the actual size needed for the current allocation request).
>
> For certain targets, notably VxWorks 653, the secondary stack is
> allocated by carving off a fixed ratio chunk of the primary task stack.
> The -D option is used to define the size of the environment task's
> secondary stack.
> --->%---

I stumbled across an interesting, old discussion about GNAT's approach 
(it seems a secondary stack was not the initial choice) with references 
to some other compilers:

http://computer-programming-forum.com/44-ada/2227f74c82f45451.htm


-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .


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

* Re: How do typical Ada calling conventions work ?
  2015-08-21 12:47   ` Niklas Holsti
@ 2015-08-22  8:31     ` Hadrien Grasland
  2015-08-24 22:03       ` Randy Brukardt
  0 siblings, 1 reply; 11+ messages in thread
From: Hadrien Grasland @ 2015-08-22  8:31 UTC (permalink / raw)


Le vendredi 21 août 2015 14:47:05 UTC+2, Niklas Holsti a écrit :
> On 15-08-21 13:41 , Markus Schöpflin wrote:
> > Am 21.08.2015 um 10:37 schrieb Hadrien Grasland:
> >
> >> Does someone know how typical Ada implementations manage to cope with
> >> this, and if it varies a lot from one implementation to another ?
> >
> > GNAT allocates such objects on the secondary stack. Quote from the user
> > guide:
> >
> > ---%<---
> > `-Dnn[k|m]'
> > This switch can be used to change the default secondary stack size value
> > to a specified size nn, which is expressed in bytes by default, or in
> > kilobytes when suffixed with k or in megabytes when suffixed with m.
> >
> > The secondary stack is used to deal with functions that return a
> > variable sized result, for example a function returning an unconstrained
> > String. There are two ways in which this secondary stack is allocated.
> >
> > For most targets, the secondary stack is growing on demand and is
> > allocated as a chain of blocks in the heap. The -D option is not very
> > relevant. It only give some control over the size of the allocated
> > blocks (whose size is the minimum of the default secondary stack size
> > value, and the actual size needed for the current allocation request).
> >
> > For certain targets, notably VxWorks 653, the secondary stack is
> > allocated by carving off a fixed ratio chunk of the primary task stack.
> > The -D option is used to define the size of the environment task's
> > secondary stack.
> > --->%---
> 
> I stumbled across an interesting, old discussion about GNAT's approach 
> (it seems a secondary stack was not the initial choice) with references 
> to some other compilers:
> 
> http://computer-programming-forum.com/44-ada/2227f74c82f45451.htm
> 
> 
> -- 
> Niklas Holsti
> Tidorum Ltd
> niklas holsti tidorum fi
>        .      @       .

Thanks for your answers ! These are some pretty nice ways to do it instead indeed.

I'm glad the secondary stack approach won in the end for GNAT, it sounds more efficient, clean and scalable than what they were attempting in the beginning.

Hadrien


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

* Re: How do typical Ada calling conventions work ?
  2015-08-22  8:31     ` Hadrien Grasland
@ 2015-08-24 22:03       ` Randy Brukardt
  2015-08-25  5:32         ` Per Sandberg
  0 siblings, 1 reply; 11+ messages in thread
From: Randy Brukardt @ 2015-08-24 22:03 UTC (permalink / raw)


"Hadrien Grasland" <hadrien.grasland@gmail.com> wrote in message 
news:2541f7b7-b728-421b-96cf-e0d656e984a2@googlegroups.com...
...
>Thanks for your answers ! These are some pretty nice ways to do it instead 
>indeed.
>
>I'm glad the secondary stack approach won in the end for GNAT, it sounds 
>more
> efficient, clean and scalable than what they were attempting in the 
> beginning.

I doubt that. The scheme Janus/Ada uses is much simpler: the memory is 
allocated off of a special storage pool and it is then freed using the same 
mechanism that does other finalization (indeed, the memory management [which 
we used in Ada 83] was repurposed to do finalization, rather than the other 
way around).

This is probably not as efficient as the secondary stack approach, but I 
find that irrelevant in 99.9% of programs. All functions that return 
non-elementary types are somewhat more expensive than the similar parameter 
passing, so if efficiency is a primary concern, one must use procedures 
rather than functions. The cases where function return by secondary stack 
would be efficient enough but function return by heap is not efficient 
enough are going to be quite rare [in the vast majority of cases either both 
are good enough or neither are] -- thus there are better things to spend 
effort on.

                                                    Randy.


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

* Re: How do typical Ada calling conventions work ?
  2015-08-24 22:03       ` Randy Brukardt
@ 2015-08-25  5:32         ` Per Sandberg
  2015-08-25  7:05           ` AdaMagica
  2015-08-31 23:01           ` Randy Brukardt
  0 siblings, 2 replies; 11+ messages in thread
From: Per Sandberg @ 2015-08-25  5:32 UTC (permalink / raw)




Den 2015-08-25 00:03, Randy Brukardt skrev:
> "Hadrien Grasland" <hadrien.grasland@gmail.com> wrote in message
> news:2541f7b7-b728-421b-96cf-e0d656e984a2@googlegroups.com...
> ...
>> Thanks for your answers ! These are some pretty nice ways to do it instead
>> indeed.
>>
>> I'm glad the secondary stack approach won in the end for GNAT, it sounds
>> more
>> efficient, clean and scalable than what they were attempting in the
>> beginning.
>
> I doubt that. The scheme Janus/Ada uses is much simpler: the memory is
> allocated off of a special storage pool and it is then freed using the same
> mechanism that does other finalization (indeed, the memory management [which
> we used in Ada 83] was repurposed to do finalization, rather than the other
> way around).
>
> This is probably not as efficient as the secondary stack approach, but I
> find that irrelevant in 99.9% of programs. All functions that return
> non-elementary types are somewhat more expensive than the similar parameter
> passing, so if efficiency is a primary concern, one must use procedures
> rather than functions. The cases where function return by secondary stack
> would be efficient enough but function return by heap is not efficient
> enough are going to be quite rare [in the vast majority of cases either both
> are good enough or neither are] -- thus there are better things to spend
> effort on.
>
>                                                      Randy.
>
>
If you want to use a function "returning" large or limited objects you 
could always use the "extended return" where the returned object will be 
created in place.

type large_or_limited is ....;
function my_function return large_or_limited is
begin
    return ret : large_or_limited do
       do_what_you_need;
    end return;
end my_function;

/Per


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

* Re: How do typical Ada calling conventions work ?
  2015-08-25  5:32         ` Per Sandberg
@ 2015-08-25  7:05           ` AdaMagica
  2015-08-25  7:28             ` AdaMagica
  2015-08-31 23:01           ` Randy Brukardt
  1 sibling, 1 reply; 11+ messages in thread
From: AdaMagica @ 2015-08-25  7:05 UTC (permalink / raw)


Am Dienstag, 25. August 2015 07:32:14 UTC+2 schrieb Per Sandberg:
> If you want to use a function "returning" large or limited objects you 
> could always use the "extended return" where the returned object will be 
> created in place.

There is no guarantee for build in place. For non-limited objects, extended return will most probably work like a traditional return.

Build-in-place is a requirement only for limited objects (there may be no copies).

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

* Re: How do typical Ada calling conventions work ?
  2015-08-25  7:05           ` AdaMagica
@ 2015-08-25  7:28             ` AdaMagica
  0 siblings, 0 replies; 11+ messages in thread
From: AdaMagica @ 2015-08-25  7:28 UTC (permalink / raw)


Am Dienstag, 25. August 2015 09:05:09 UTC+2 schrieb AdaMagica:
> Am Dienstag, 25. August 2015 07:32:14 UTC+2 schrieb Per Sandberg:
> > If you want to use a function "returning" large or limited objects you 
> > could always use the "extended return" where the returned object will be 
> > created in place.
> 
> There is no guarantee for build in place. For non-limited objects, extended return will most probably work like a traditional return.
> 
> Build-in-place is a requirement only for limited objects (there may be no copies).

RM 6.5(5.11/3)
AARM 7.5(9.a/2)

(I just don't feel like searching for more relevant paragraphs.)

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

* Re: How do typical Ada calling conventions work ?
  2015-08-21  8:37 How do typical Ada calling conventions work ? Hadrien Grasland
  2015-08-21 10:41 ` Markus Schöpflin
@ 2015-08-25 18:38 ` gautier_niouzes
  2015-08-26 15:53   ` Hadrien Grasland
  1 sibling, 1 reply; 11+ messages in thread
From: gautier_niouzes @ 2015-08-25 18:38 UTC (permalink / raw)


Le vendredi 21 août 2015 10:37:24 UTC+2, Hadrien Grasland a écrit :
> I am currently having fun re-implementing some of Numerical Recipes' code snippets in Ada.

Just a side note: you can automatically translate the full Pascal version of the Numerical Recipes with P2Ada: http://p2ada.sf.net/ . The translated code needs some rework, but it might save you some work in the end.
_________________________
Gautier's Ada programming
http://sf.net/users/gdemont/

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

* Re: How do typical Ada calling conventions work ?
  2015-08-25 18:38 ` gautier_niouzes
@ 2015-08-26 15:53   ` Hadrien Grasland
  0 siblings, 0 replies; 11+ messages in thread
From: Hadrien Grasland @ 2015-08-26 15:53 UTC (permalink / raw)


@Per : Actually, I already use this extended return syntax quite liberally in my code, mostly because I like its aesthetics better than the declare..begin..end equivalent : it is more concise, and simultaneously clarifies that the variable being declared will ultimately hold the function's result... :-)


Le mardi 25 août 2015 20:38:06 UTC+2, gautier...@hotmail.com a écrit :
> Le vendredi 21 août 2015 10:37:24 UTC+2, Hadrien Grasland a écrit :
> > I am currently having fun re-implementing some of Numerical Recipes' code snippets in Ada.
> 
> Just a side note: you can automatically translate the full Pascal version of the Numerical Recipes with P2Ada: http://p2ada.sf.net/ . The translated code needs some rework, but it might save you some work in the end.
> _________________________
> Gautier's Ada programming
> http://sf.net/users/gdemont/

Unfortunately, I'm using the 3rd edition of the Numerical Recipes book, which is C++-only. Also, I only have access to the book, not the code archive.

Besides, something which I may not have made clear enough is that this is mostly a personal exercise to work a bit on my Ada skills, not a project which I need to finish quickly for work or anything like that. So in this context, it makes more sense for me to carefully walk through the code, examine ways I could re-write it to use more idiomatic Ada constructs, have some fun with Ada 2012 contracts, and overall take my time.


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

* Re: How do typical Ada calling conventions work ?
  2015-08-25  5:32         ` Per Sandberg
  2015-08-25  7:05           ` AdaMagica
@ 2015-08-31 23:01           ` Randy Brukardt
  1 sibling, 0 replies; 11+ messages in thread
From: Randy Brukardt @ 2015-08-31 23:01 UTC (permalink / raw)


"Per Sandberg" <per.s.sandberg@bahnhof.se> wrote in message 
news:55dbfddd$0$20676$862e30e2@ngroups.net...
...
> If you want to use a function "returning" large or limited objects you 
> could always use the "extended return" where the returned object will be 
> created in place.
>
> type large_or_limited is ....;
> function my_function return large_or_limited is
> begin
>    return ret : large_or_limited do
>       do_what_you_need;
>    end return;
> end my_function;

As noted by Christophe, the syntax of a return statement has no effect on 
how objects are returned. The compiler might use build-in-place semantics 
for all returns or none; it's only required for inherently limited objects. 
It's highly unlikely that a compiler would act differently for extended 
returns rather than simple returns, because that would make calls dependent 
on the contents of the body.

                                   Randy.


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

end of thread, other threads:[~2015-08-31 23:01 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-21  8:37 How do typical Ada calling conventions work ? Hadrien Grasland
2015-08-21 10:41 ` Markus Schöpflin
2015-08-21 12:47   ` Niklas Holsti
2015-08-22  8:31     ` Hadrien Grasland
2015-08-24 22:03       ` Randy Brukardt
2015-08-25  5:32         ` Per Sandberg
2015-08-25  7:05           ` AdaMagica
2015-08-25  7:28             ` AdaMagica
2015-08-31 23:01           ` Randy Brukardt
2015-08-25 18:38 ` gautier_niouzes
2015-08-26 15:53   ` Hadrien Grasland

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