Re: Calling conventions -- easier way?

2001-10-21 Thread Dan Sugalski

At 11:00 PM 10/19/2001 -0400, Bryan C. Warnock wrote:
>On Friday 19 October 2001 01:46 pm, Dan Sugalski wrote:
> > I'm currently leaning either towards returning values in registers
> > [PSIN][0-4] with the total number of each type in register I0 somehow
>
>Order determination of the return values.

That's an issue if we don't have declared return value lists. If we do, we 
can do it implicitly--the first five string returns are in S0-S4, the first 
four integers in I1-I4, the first five PMCs in P0-P4, and the first five 
floats in N0-N4.

Without return value lists, I think we're going to have to either push 'em 
on a stack, or return a single list PMC with the returns. The only problem 
with a list is that you can only put PMCs in 'em, which won't work too well 
for those cases when you don't need a full PMC.

Dan

--"it's like this"---
Dan Sugalski  even samurai
[EMAIL PROTECTED] have teddy bears and even
  teddy bears get drunk




Re: Calling conventions -- easier way?

2001-10-19 Thread Bryan C . Warnock

On Friday 19 October 2001 01:46 pm, Dan Sugalski wrote:
> I'm currently leaning either towards returning values in registers
> [PSIN][0-4] with the total number of each type in register I0 somehow

Order determination of the return values. 

(Yes, I was the one asking for register windows.  Shame on me.)

-- 
Bryan C. Warnock
[EMAIL PROTECTED]



Re: Calling conventions -- easier way?

2001-10-19 Thread Gregor N. Purdy

Dan --

> Ah, but I'd rather do it right the first time than have to redo it later, 
> especially if the redoing is incompatible with what was done first. ;)

I would, too. But I view Jako is being a sort of test bed for what our
choices at the Parrot level do to language implementers. So, Jako is
intended to track the current-best-practice, as it changes. That means
I expect, for example, to re-implement the calling convention stuff a
few times. Heck, Jako had subroutines before we had bsr!

> >FWIW, I'd rather not dedicate registers to special uses at the Parrot
> >level.
> 
> These would only be reserved for subroutine calls, which is pretty standard 
> on CPUs with a reasonable number of registers. Normally a half-dozen or so 
> float and general registers are marked as scratch, so the callee can mess 
> with them as it wants. You say registers X-Y hold the parameters to the 
> caller, register X holds the return value, register Y holds the status (if 
> they're separate) and registers M-N are declared as scratch and the callee 
> doesn't have to preserve them.
> 
> The only time these rules are in effect is when you make a sub call. Within 
> the sub, you can do whatever you like with the registers.
> 
> Now, things are more interesting with Parrot, since we have at least one 
> language that can potentially take and return a huge list of things, which 
> is why I'm tending towards the "pass a list in P0, return a list in P0" way 
> of doing things, or a separate stack of values. The biggest problem with a 
> stack is that things are in reverse order, where passing in a list gets 
> them to you in proper order.

I agree that a HLL that has a list type should use that list type for its
arg and return passing. But, low level stuff (like Jako is
currently) should still have access to a reasonable no-pmc-required
calling convention, IMO.


Regards,

-- Gregor




Re: Calling conventions -- easier way?

2001-10-19 Thread Dan Sugalski

At 01:55 PM 10/19/2001 -0400, Gregor N. Purdy wrote:
>Dan --
>
> > >Should we have bsr(i|ic, i|ic), that jumps to $1, with the return
> > >address below the $2 arguments? Similarly, should we have ret(i|ic),
> > >that rotates the return address out from under $1 arguments and then
> > >returns to it?
> >
> > Nope. For a number of reasons, the biggest being that we're not returning
> > our return values on the stack. :)
>
>Well, until something better comes along, Jako subroutines return *their*
>return values on the stack... :)

Ah, but I'd rather do it right the first time than have to redo it later, 
especially if the redoing is incompatible with what was done first. ;)

> > > > OTOH, we could keep our current ABI, and pop the return address 
> into an I
> > > > register, and then push it and ret, or jmp to it.
> > >
> > > The return address is a pointer, which doesn't necessarily fit in an
> > > IV,
> > > I believe. I played with doing this first, but didn't like having to
> > > use
> > > a register for it. If we wanted registers to be part of the calling
> > > convention, we should just say so, but again we run into the question
> > > of which type of register to use.
> >
> > I'm currently leaning either towards returning values in registers
> > [PSIN][0-4] with the total number of each type in register I0 somehow, or
> > as arg stack that's separate from the call stack. The latter is probably
> > the better way to go, but it's got more overhead in some ways. It'd make
> > interfacing with RPN languages easier, though.
>
>FWIW, I'd rather not dedicate registers to special uses at the Parrot
>level.

These would only be reserved for subroutine calls, which is pretty standard 
on CPUs with a reasonable number of registers. Normally a half-dozen or so 
float and general registers are marked as scratch, so the callee can mess 
with them as it wants. You say registers X-Y hold the parameters to the 
caller, register X holds the return value, register Y holds the status (if 
they're separate) and registers M-N are declared as scratch and the callee 
doesn't have to preserve them.

The only time these rules are in effect is when you make a sub call. Within 
the sub, you can do whatever you like with the registers.

Now, things are more interesting with Parrot, since we have at least one 
language that can potentially take and return a huge list of things, which 
is why I'm tending towards the "pass a list in P0, return a list in P0" way 
of doing things, or a separate stack of values. The biggest problem with a 
stack is that things are in reverse order, where passing in a list gets 
them to you in proper order.

Dan

--"it's like this"---
Dan Sugalski  even samurai
[EMAIL PROTECTED] have teddy bears and even
  teddy bears get drunk




Re: Calling conventions -- easier way?

2001-10-19 Thread Michael Maraist

On Fri, 19 Oct 2001, Gregor N. Purdy wrote:

> Dan --
> FWIW, I'd rather not dedicate registers to special uses at the Parrot
> level. Jako reserves [INPS]0 for temporaries, but that is at its
> discretion, not dictated by Parrot (and I like it that way :). I was
> wishing for separate data and address stacks when I was writing the
> Jako calling convention stuff, but I can live with the rotate solution.
> If the choices come down to reserved registers or separate stacks,
> though, I'm squarely in the separate stacks camp.

Not that it matters at this stage, but if we rely on compilers for
temporaries, then what happens when we integrate different compiled
binaries?  MIPS (and I believe alpha) was good at reserved registers.
Aside from "macro'd ops" most reserved registers only reserved at
subroutine call time.  Eventually all the compilers are going to have
to deal with register renaming (we're going to run out of registers
for a lot of code, and I don't think pushing and poping the register stack is going to 
be
very helpful).

I'd be curious to read up on register renaming compiler strategies
(anybody have any online references?).  Guess the basic algorithm is
to assume an infinite number of registers, then perform data
dependency checks and reduce the tree.  In my up and comming post, I
suggest a "peek R, i|ic" op-code which allows you to store fundamental
datatypes in subroutine local stack memory (like hardware CPUs).  If
all variables are mapped within the stack frame, then register
renaming should merely consist of pushing unused valued to their
associated frame-offset and reusing that register and extracting it's
replacement value from another address.

-Michael





Re: Calling conventions -- easier way?

2001-10-19 Thread Gregor N. Purdy

Dan --

> >Should we have bsr(i|ic, i|ic), that jumps to $1, with the return
> >address below the $2 arguments? Similarly, should we have ret(i|ic),
> >that rotates the return address out from under $1 arguments and then
> >returns to it?
> 
> Nope. For a number of reasons, the biggest being that we're not returning 
> our return values on the stack. :)

Well, until something better comes along, Jako subroutines return *their*
return values on the stack... :)

> > > OTOH, we could keep our current ABI, and pop the return address into an I
> > > register, and then push it and ret, or jmp to it.
> >
> > The return address is a pointer, which doesn't necessarily fit in an
> > IV,
> > I believe. I played with doing this first, but didn't like having to
> > use
> > a register for it. If we wanted registers to be part of the calling
> > convention, we should just say so, but again we run into the question
> > of which type of register to use.
> 
> I'm currently leaning either towards returning values in registers 
> [PSIN][0-4] with the total number of each type in register I0 somehow, or 
> as arg stack that's separate from the call stack. The latter is probably 
> the better way to go, but it's got more overhead in some ways. It'd make 
> interfacing with RPN languages easier, though.

FWIW, I'd rather not dedicate registers to special uses at the Parrot
level. Jako reserves [INPS]0 for temporaries, but that is at its
discretion, not dictated by Parrot (and I like it that way :). I was
wishing for separate data and address stacks when I was writing the
Jako calling convention stuff, but I can live with the rotate solution.
If the choices come down to reserved registers or separate stacks,
though, I'm squarely in the separate stacks camp.


Regards,

-- Gregor




Re: Calling conventions -- easier way?

2001-10-19 Thread Michael Maraist

On Fri, 19 Oct 2001, Dan Sugalski wrote:

> At 01:24 PM 10/19/2001 -0400, Gregor N. Purdy wrote:
> >James --
> >
> >Should we have bsr(i|ic, i|ic), that jumps to $1, with the return
> >address below the $2 arguments? Similarly, should we have ret(i|ic),
> >that rotates the return address out from under $1 arguments and then
> >returns to it?
>
> Nope. For a number of reasons, the biggest being that we're not returning
> our return values on the stack. :)
>
> > > OTOH, we could keep our current ABI, and pop the return address into an I
> > > register, and then push it and ret, or jmp to it.
> >
> >The return address is a pointer, which doesn't necessarily fit in an IV,
> >I believe. I played with doing this first, but didn't like having to use
> >a register for it. If we wanted registers to be part of the calling
> >convention, we should just say so, but again we run into the question of
> >which type of register to use.
>
> I'm currently leaning either towards returning values in registers
> [PSIN][0-4] with the total number of each type in register I0 somehow, or
> as arg stack that's separate from the call stack. The latter is probably
> the better way to go, but it's got more overhead in some ways. It'd make
> interfacing with RPN languages easier, though.
>

I was in the middle of writing up something on this topic.. I'm still
working on the details, so I'll summarize.

The more out-of-band data the better.. It's faster (no munging an all
in one stack), more efficient (don't have to abstract it's type),
and we're not limited like some hardware is (e.g. having a single stack
segment).

Most of my bias is based on a paper on stack-based machines presented
by someone else earlier in this mailing list.  It was a good paper,
though somewhat dated.

The only problem with having out-of-band return addresses is syncing
up with the stack (unrolling it for exceptions of frame-analysis). I
was working on a concept that used segregated stack-frames for the
parameter stack, with the stack frame header referencing the
"top-of-return-address stack".  Alternatively, the
return-address-stack could contain a reference into the parameter
stack(s).  The latter would be easier for unrolling, but makes the
pushed value a little more complex.

I'm not particular on the details, though I'm still working on them,
but I definately think out-of-line return addresses are "good
thing"(tm).

-Michael




Re: Calling conventions -- easier way?

2001-10-19 Thread Dan Sugalski

At 01:24 PM 10/19/2001 -0400, Gregor N. Purdy wrote:
>James --
>
> > Hey all.  I just looked through the changes to jakoc, and I think the
> > calling convention is mostly good... except for the return address.
> >
> > Originaly, I thought that perhaps it'd be good to put the return address
> > after the args on the stack, so that once you've eaten the args, it's 
> in the
> > right position to ret without doing any swaps.
>
>I just put in the 'rotate' op Dan requested instead of 'swap', and it begs
>the question:
>
>Should we have bsr(i|ic, i|ic), that jumps to $1, with the return
>address below the $2 arguments? Similarly, should we have ret(i|ic),
>that rotates the return address out from under $1 arguments and then
>returns to it?

Nope. For a number of reasons, the biggest being that we're not returning 
our return values on the stack. :)

> > OTOH, we could keep our current ABI, and pop the return address into an I
> > register, and then push it and ret, or jmp to it.
>
>The return address is a pointer, which doesn't necessarily fit in an IV,
>I believe. I played with doing this first, but didn't like having to use
>a register for it. If we wanted registers to be part of the calling
>convention, we should just say so, but again we run into the question of
>which type of register to use.

I'm currently leaning either towards returning values in registers 
[PSIN][0-4] with the total number of each type in register I0 somehow, or 
as arg stack that's separate from the call stack. The latter is probably 
the better way to go, but it's got more overhead in some ways. It'd make 
interfacing with RPN languages easier, though.

Dan

--"it's like this"---
Dan Sugalski  even samurai
[EMAIL PROTECTED] have teddy bears and even
  teddy bears get drunk




Re: Calling conventions -- easier way?

2001-10-19 Thread Gregor N. Purdy

James --

> Hey all.  I just looked through the changes to jakoc, and I think the
> calling convention is mostly good... except for the return address.
> 
> Originaly, I thought that perhaps it'd be good to put the return address
> after the args on the stack, so that once you've eaten the args, it's in the
> right position to ret without doing any swaps.

I just put in the 'rotate' op Dan requested instead of 'swap', and it begs
the question:

   Should we have bsr(i|ic, i|ic), that jumps to $1, with the return
   address below the $2 arguments? Similarly, should we have ret(i|ic),
   that rotates the return address out from under $1 arguments and then
   returns to it?

These don't have to be instead of the exising ops. They can be in addition
to them (since the current ops are equivalent to a final 0 arg in the
new ones).
 
> OTOH, we could keep our current ABI, and pop the return address into an I
> register, and then push it and ret, or jmp to it.

The return address is a pointer, which doesn't necessarily fit in an IV,
I believe. I played with doing this first, but didn't like having to use
a register for it. If we wanted registers to be part of the calling
convention, we should just say so, but again we run into the question of
which type of register to use.


Regards,

-- Gregor




Calling conventions -- easier way?

2001-10-19 Thread James Mastros

Hey all.  I just looked through the changes to jakoc, and I think the
calling convention is mostly good... except for the return address.

Originaly, I thought that perhaps it'd be good to put the return address
after the args on the stack, so that once you've eaten the args, it's in the
right position to ret without doing any swaps.

That would have to be done by doing a:
SET In, *+  (Assuming that we can do constant arith on *)


jmp 


OTOH, we could keep our current ABI, and pop the return address into an I
register, and then push it and ret, or jmp to it.

  -=- James Mastros