Re: continuation enhanced arcs

2004-12-09 Thread Miroslav Silovic
[EMAIL PROTECTED] wrote:
What this means is that care must be taken when you are writing code
that you expects to be invoked multiple times.  However, if you are a
function that on your second invocation returns via the continuation
from you first invocation, you should probably expect to be called
again because it happened the first time!
The contentious point is precisely that there is no way to tell at the 
compile time that you will be invoked multiple times. If something you 
pull from a library or a callback passed to you captures the 
continuation, you may notice that your return continuation had been 
promoted, but at that point it's already too late to kill all I/N/S 
register usage and to double-reference all PMCs. Of course, unless you 
keep the original AST and keep recompiling it to PIR. I'd argue that 
it's vastly more complex and error prone than Leo's solution he refered 
to in his post. It's also no better than refetching all lexicals.

Also, note that return-continuation-restores semantics is simply a 
(possibly premature) optimisation in its own right. CPS is supposed to 
treat every continuation the same (which turned out to be inefficient), 
and then return continuations were added to simplify the most common 
case. So, while return continuation is unpromoted, it's perfectly okay 
for it to behave any way it wants. Once it does get promoted, I'd argue 
that it should behave like a normal continuation first because it's more 
practical (see above) and second because that way it doesn't break CPS 
semantics.

   Miro



Re: continuation enhanced arcs

2004-12-09 Thread Leopold Toetsch
Matt Fowles [EMAIL PROTECTED] wrote:

 ...  This author may
 have to be a little wary about value vs reference semantics, but
 programmers are fairly used to that pitfall by now.

Yes. But this still boils down to the question, if an author or compiler
knows that a full continuation is involved and that I,S,N registers
aren't usable for a piece of code.

 Matt

leo


Re: continuation enhanced arcs

2004-12-09 Thread Nicholas Clark
On Wed, Dec 08, 2004 at 04:04:31PM -0500, Matt Fowles wrote:

 I would disagree.  Let me take the above example and work with it a little:
 
   $I0 = 10
 loop:
   $P0 = shift array
   dec $I0
   if $I0 goto loop
 
 We are (for the moment) assuming that shift array somehow causes a
 full continuations to be taken and then invoked it in a subsequent
 call.  Then this code would infinite loop; however, so would this code

Is shift a vtable method? IIRC Dan said that we're not going to be able
to take continuations that cross PMC vtable invocation.

Nicholas Clark


Re: continuation enhanced arcs

2004-12-08 Thread Leopold Toetsch
Piers Cawley [EMAIL PROTECTED] wrote:
 Leopold Toetsch [EMAIL PROTECTED] writes:

  ... While S registers hold pointers, they have
  value semantics.

 Is that guaranteed? Because it probably needs to be.

It's the current implementation and tested.

  This would restore the register contents to the first state shown above.
  That is, not only I and N registers would be clobbered also S registers
  are involved.

 That's correct. What's the problem? Okay, you've created an infinite
 loop, but what you're describing is absolutely the correct behaviour for
 a continuation.

Ok. It's a bit mind-twisting but OTOH it's the same as setjmp/longjmp
with all implications on CPU registers. C has the volatile keyword to
avoid clobbering of a register due to a longjmp.

  Above code could only use P registers. Or in other words: I, N, and S
  registers are almost[1] useless.

 No they're not. But you should expect them to be reset if you take a
 (full) continuation back to them.

The problem I have is: do we know where registers may be reset? For
example:

$I0 = 10
  loop:
$P0 = shift array
dec $I0
if $I0 goto loop

What happens if the array PMC's Cshift get overloaded and does some
fancy stuff with continuations. My gut feeling is that the loop might
suddenly turn into an infinite loop, depending on some code behind the
scenes ($I0 might be allocated into the preserved register range or not
depending on allocation pressure).

Second: if we don't have a notion that a continuation may capture and
restore a register frame, a compiler can hardly use any I,S,N registers
because some library code or external function might just restore these
registers.

 Presumably if foo() doesn't store a full continuation, the restoration
 just reuses an existing register frame and, if foo has made a full
 continuation its return does a restore by copying?

Yes, that should be a reasonable implementation.

leo


Re: continuation enhanced arcs

2004-12-08 Thread Piers Cawley
Leopold Toetsch [EMAIL PROTECTED] writes:

 Piers Cawley [EMAIL PROTECTED] wrote:
 Leopold Toetsch [EMAIL PROTECTED] writes:

  ... While S registers hold pointers, they have
  value semantics.

 Is that guaranteed? Because it probably needs to be.

 It's the current implementation and tested.

  This would restore the register contents to the first state shown above.
  That is, not only I and N registers would be clobbered also S registers
  are involved.

 That's correct. What's the problem? Okay, you've created an infinite
 loop, but what you're describing is absolutely the correct behaviour for
 a continuation.

 Ok. It's a bit mind-twisting but OTOH it's the same as setjmp/longjmp
 with all implications on CPU registers. C has the volatile keyword to
 avoid clobbering of a register due to a longjmp.

  Above code could only use P registers. Or in other words: I, N, and S
  registers are almost[1] useless.

 No they're not. But you should expect them to be reset if you take a
 (full) continuation back to them.

 The problem I have is: do we know where registers may be reset? For
 example:

 $I0 = 10
   loop:
 $P0 = shift array
 dec $I0
 if $I0 goto loop

 What happens if the array PMC's Cshift get overloaded and does some
 fancy stuff with continuations. My gut feeling is that the loop might
 suddenly turn into an infinite loop, depending on some code behind the
 scenes ($I0 might be allocated into the preserved register range or not
 depending on allocation pressure).

 Second: if we don't have a notion that a continuation may capture and
 restore a register frame, a compiler can hardly use any I,S,N registers
 because some library code or external function might just restore these
 registers.

This is, of course, why so many languages that have full continuations
use reference types throughout, even for numbers. And immutable strings...


Re: continuation enhanced arcs

2004-12-08 Thread Leopold Toetsch
Piers Cawley [EMAIL PROTECTED] wrote:
 Leopold Toetsch [EMAIL PROTECTED] writes:

 The problem I have is: do we know where registers may be reset? For
 example:

 $I0 = 10
   loop:
 $P0 = shift array
 dec $I0
 if $I0 goto loop

 What happens if the array PMC's Cshift get overloaded and does some
 fancy stuff with continuations. My gut feeling is that the loop might
 suddenly turn into an infinite loop, depending on some code behind the
 scenes ($I0 might be allocated into the preserved register range or not
 depending on allocation pressure).

 Second: if we don't have a notion that a continuation may capture and
 restore a register frame, a compiler can hardly use any I,S,N registers
 because some library code or external function might just restore these
 registers.

 This is, of course, why so many languages that have full continuations
 use reference types throughout, even for numbers. And immutable strings...

So my conclusion that (in combination with restoring registers to the
values of continuation creation) I,S,N registers are almost unusable is
correct?

What about my proposal Lexicals, continuations, and register
allocation? Would that provide proper semantics for continuations?

leo


Re: continuation enhanced arcs

2004-12-08 Thread Matt Fowles
Leo~


On Wed, 8 Dec 2004 20:29:00 +0100, Leopold Toetsch [EMAIL PROTECTED] wrote:
 So my conclusion that (in combination with restoring registers to the
 values of continuation creation) I,S,N registers are almost unusable is
 correct?

I would disagree.  Let me take the above example and work with it a little:

  $I0 = 10
loop:
  $P0 = shift array
  dec $I0
  if $I0 goto loop

We are (for the moment) assuming that shift array somehow causes a
full continuations to be taken and then invoked it in a subsequent
call.  Then this code would infinite loop; however, so would this code
as the second call is returning through the first calls continuation.

  $P0 = shift array
  $P1 = shift array

On the other hand, if every call to shift array took a full
continuation, did some stuff, and eventually returned through its
return continuation.  Then neither would infinite loop, as every call
to shift array would have its own return continuation.

What this means is that care must be taken when you are writing code
that you expects to be invoked multiple times.  However, if you are a
function that on your second invocation returns via the continuation
from you first invocation, you should probably expect to be called
again because it happened the first time!  If you are expecting other
behavior, it is probably because one person wrote the whole chain of
calls and had some extra knowledge about the caller.  This author may
have to be a little wary about value vs reference semantics, but
programmers are fairly used to that pitfall by now.

Matt
-- 
Computer Science is merely the post-Turing Decline of Formal Systems Theory.
-???


Re: continuation enhanced arcs

2004-12-07 Thread Leopold Toetsch
Piers Cawley [EMAIL PROTECTED] wrote:

 Further to my last response. If you have things set up so that you can
 return multiple times from the same function invocation then the return
 continuation should have been replaced with a full continuation before
 the first return, so even the first return will use copying semantics,
 and the registers will always be restored to the state they were in when
 the function was first called, which is absolutely the right thing to
 do.

Here is again the example I've brought recently. Please go through it
and tell me what's wrong with my conclusion.


   $I0 = 42 # set I16, 42 42
   $N0 = 2.5# set N16, 2.5..101...
   $S0 = a# set S16, a0x1004  - a
   $P0 = a# set P16, a0x2008  - a
  loop:
   foo()# set P0, ...; invokecc

 We have some temporary variables and a function call. Variables are used
 beyond that point, so the register allocator puts these in the preserved
 register range. The function Cfoo() might or might not capture the
 continuation created by the Cinvokecc opcode.

 Let's assume, it is captured, and stored into a global, if it wasn't
 already, i.e. the first time. According to Dan's plan, the function
 return restores the register contents to the state of the creation of
 the return continuation, which is shown in the right column.

   $I0 += 1 # add I16, 1  43
   $N0 *= 2.0   # mul N16, 2.0.101
   $S0 .= b   # concat S16, b 0x1008  - ab
   inc $P0  # inc P16 0x2008  - b
   dec a# dec P17 0x200c  - 1
   if a goto loop   # if P17, loop

 A note WRT strings: the concat might or might not assign a new string to
 S16. It depends on the capacity of the string buffer. But generally:
 string operations do create new string headers with a different memory
 address like shown here. While S registers hold pointers, they have
 value semantics.

 Now we loop once over the function call. This creates a new return
 continuation and on function return registers are restored to their new
 values (44, 10.0, abb, c). All fine till here.

 The loop counter a reaches zero. Now the next instruction is
 another function call.

   bar()# set P0, ... invokecc

 The bar() function extracts the return continuation captured in the
 first call to foo() from the global and invokes it. Control flow
 continues right after the invokecc opcode that called foo().

 This would restore the register contents to the first state shown above.
 That is, not only I and N registers would be clobbered also S registers
 are involved.

 Above code could only use P registers. Or in other words: I, N, and S
 registers are almost[1] useless.

leo


Re: continuation enhanced arcs

2004-12-07 Thread Piers Cawley
Leopold Toetsch [EMAIL PROTECTED] writes:

 Piers Cawley [EMAIL PROTECTED] wrote:

 Further to my last response. If you have things set up so that you can
 return multiple times from the same function invocation then the return
 continuation should have been replaced with a full continuation before
 the first return, so even the first return will use copying semantics,
 and the registers will always be restored to the state they were in when
 the function was first called, which is absolutely the right thing to
 do.

 Here is again the example I've brought recently. Please go through it
 and tell me what's wrong with my conclusion.


$I0 = 42 # set I16, 42 42
$N0 = 2.5# set N16, 2.5..101...
$S0 = a# set S16, a0x1004  - a
$P0 = a# set P16, a0x2008  - a
   loop:
foo()# set P0, ...; invokecc

  We have some temporary variables and a function call. Variables are used
  beyond that point, so the register allocator puts these in the preserved
  register range. The function Cfoo() might or might not capture the
  continuation created by the Cinvokecc opcode.

  Let's assume, it is captured, and stored into a global, if it wasn't
  already, i.e. the first time. According to Dan's plan, the function
  return restores the register contents to the state of the creation of
  the return continuation, which is shown in the right column.

$I0 += 1 # add I16, 1  43
$N0 *= 2.0   # mul N16, 2.0.101
$S0 .= b   # concat S16, b 0x1008  - ab
inc $P0  # inc P16 0x2008  - b
dec a# dec P17 0x200c  - 1
if a goto loop   # if P17, loop

  A note WRT strings: the concat might or might not assign a new string to
  S16. It depends on the capacity of the string buffer. But generally:
  string operations do create new string headers with a different memory
  address like shown here. While S registers hold pointers, they have
  value semantics.

Is that guaranteed? Because it probably needs to be.


  Now we loop once over the function call. This creates a new return
  continuation and on function return registers are restored to their new
  values (44, 10.0, abb, c). All fine till here.

  The loop counter a reaches zero. Now the next instruction is
  another function call.

bar()# set P0, ... invokecc

  The bar() function extracts the return continuation captured in the
  first call to foo() from the global and invokes it. Control flow
  continues right after the invokecc opcode that called foo().

  This would restore the register contents to the first state shown above.
  That is, not only I and N registers would be clobbered also S registers
  are involved.

That's correct. What's the problem? Okay, you've created an infinite
loop, but what you're describing is absolutely the correct behaviour for
a continuation. If you need any state to be 'protected' from taking the
continuation then it needs to be in a lexical or a mutated PMC. This is
just how continuations are supposed to work. 

  Above code could only use P registers. Or in other words: I, N, and S
  registers are almost[1] useless.

No they're not. But you should expect them to be reset if you take a
(full) continuation back to them. 

Presumably if foo() doesn't store a full continuation, the restoration
just reuses an existing register frame and, if foo has made a full
continuation its return does a restore by copying?


Re: continuation enhanced arcs

2004-12-06 Thread Leopold Toetsch
Piers Cawley [EMAIL PROTECTED] wrote:
 Leopold Toetsch [EMAIL PROTECTED] writes:

 Matt Fowles [EMAIL PROTECTED] wrote:

 Thanks for the clear explanation.  I did not realize that S registers
 could switch pointers, that does make things a little harder.  I have
 a recommendation for a possible hybrid solution.  Incur the cost of
 spilling I,S,N registers heavily.  Restore the state of P register.

 My conclusion was that with the copying approach I,S,N registers are
 unusable.

 But you only need to copy when the frame you're restoring is a full
 continuation

Yes. With the effect that semantics of I,S,N (i.e. value registers)
suddenly changes.

 I'd submit that, in the vast majority of cases you're not going to be
 dealing with full continuations, and on the occasions when you are the
 programmer using them will be aware of the cost and will be willing to
 pay it.

*If* the programmer is aware of the fact that a subroutine can return
multiple times, he can annotate the source so that a correct CFG is
created that prevents register reusing alltogether. The problem is
gone in the first place.

*If* that's not true, you'd get the effect that suddenly I,S,N registers
restore to some older values which makes this registers de facto unusable.

leo


Re: continuation enhanced arcs

2004-12-06 Thread Piers Cawley
Leopold Toetsch [EMAIL PROTECTED] writes:

 Piers Cawley [EMAIL PROTECTED] wrote:
 Leopold Toetsch [EMAIL PROTECTED] writes:

 Matt Fowles [EMAIL PROTECTED] wrote:

 Thanks for the clear explanation.  I did not realize that S registers
 could switch pointers, that does make things a little harder.  I have
 a recommendation for a possible hybrid solution.  Incur the cost of
 spilling I,S,N registers heavily.  Restore the state of P register.

 My conclusion was that with the copying approach I,S,N registers are
 unusable.

 But you only need to copy when the frame you're restoring is a full
 continuation

 Yes. With the effect that semantics of I,S,N (i.e. value registers)
 suddenly changes.

 I'd submit that, in the vast majority of cases you're not going to be
 dealing with full continuations, and on the occasions when you are the
 programmer using them will be aware of the cost and will be willing to
 pay it.

 *If* the programmer is aware of the fact that a subroutine can return
 multiple times, he can annotate the source so that a correct CFG is
 created that prevents register reusing alltogether. The problem is
 gone in the first place.

 *If* that's not true, you'd get the effect that suddenly I,S,N registers
 restore to some older values which makes this registers de facto unusable.

But they're bloody value registers. They're *supposed* to restore to the
state they were in when the function was originally called. Which is
what copying semantics does.



Re: continuation enhanced arcs

2004-12-06 Thread Piers Cawley
Leopold Toetsch [EMAIL PROTECTED] writes:

 Piers Cawley [EMAIL PROTECTED] wrote:
 Leopold Toetsch [EMAIL PROTECTED] writes:

 Matt Fowles [EMAIL PROTECTED] wrote:

 Thanks for the clear explanation.  I did not realize that S registers
 could switch pointers, that does make things a little harder.  I have
 a recommendation for a possible hybrid solution.  Incur the cost of
 spilling I,S,N registers heavily.  Restore the state of P register.

 My conclusion was that with the copying approach I,S,N registers are
 unusable.

 But you only need to copy when the frame you're restoring is a full
 continuation

 Yes. With the effect that semantics of I,S,N (i.e. value registers)
 suddenly changes.

 I'd submit that, in the vast majority of cases you're not going to be
 dealing with full continuations, and on the occasions when you are the
 programmer using them will be aware of the cost and will be willing to
 pay it.

 *If* the programmer is aware of the fact that a subroutine can return
 multiple times, he can annotate the source so that a correct CFG is
 created that prevents register reusing alltogether. The problem is
 gone in the first place.

 *If* that's not true, you'd get the effect that suddenly I,S,N registers
 restore to some older values which makes this registers de facto
 unusable.

Further to my last response. If you have things set up so that you can
return multiple times from the same function invocation then the return
continuation should have been replaced with a full continuation before
the first return, so even the first return will use copying semantics,
and the registers will always be restored to the state they were in when
the function was first called, which is absolutely the right thing to
do.



Re: continuation enhanced arcs

2004-12-05 Thread Piers Cawley
Leopold Toetsch [EMAIL PROTECTED] writes:

 Matt Fowles [EMAIL PROTECTED] wrote:

 Thanks for the clear explanation.  I did not realize that S registers
 could switch pointers, that does make things a little harder.  I have
 a recommendation for a possible hybrid solution.  Incur the cost of
 spilling I,S,N registers heavily.  Restore the state of P register.

 My conclusion was that with the copying approach I,S,N registers are
 unusable.

But you only need to copy when the frame you're restoring is a full
continuation (and, actually, if copy on write works at a per register
level, copy on write might be the way to go). If it's a return
continuation you can simply use the stored state. 

I'd submit that, in the vast majority of cases you're not going to be
dealing with full continuations, and on the occasions when you are the
programmer using them will be aware of the cost and will be willing to
pay it.



Re: continuation enhanced arcs

2004-12-05 Thread Piers Cawley
Luke Palmer [EMAIL PROTECTED] writes:

 Piers Cawley writes:
 I'd submit that, in the vast majority of cases you're not going to be
 dealing with full continuations, and on the occasions when you are the
 programmer using them will be aware of the cost and will be willing to
 pay it.

 Yeah probably.  Except the problem isn't the cost.  The problem is the
 semantics.  If you copy the registers, then when you invoke the
 continuation, their *values* restore to what they were when you made the
 continuation.  These are not proper semantics, and would result in
 subtle, incorrect infinite loops.

PMCs don't relocate, so the values you're restoring are simply the
addresses of said PMCs. The Numeric registers are value registers
anyway so no problem there (since there's no way of making a pointer to
the contents of such a register AFAICT). I'm not sure about string
registers.

And anyway, copying is how it used to work, and work it did, albeit slowly.


Re: continuation enhanced arcs

2004-12-05 Thread Luke Palmer
Piers Cawley writes:
 I'd submit that, in the vast majority of cases you're not going to be
 dealing with full continuations, and on the occasions when you are the
 programmer using them will be aware of the cost and will be willing to
 pay it.

Yeah probably.  Except the problem isn't the cost.  The problem is the
semantics.  If you copy the registers, then when you invoke the
continuation, their *values* restore to what they were when you made the
continuation.  These are not proper semantics, and would result in
subtle, incorrect infinite loops.

Luke


Re: continuation enhanced arcs

2004-12-04 Thread Leopold Toetsch
Matt Fowles [EMAIL PROTECTED] wrote:

 Thanks for the clear explanation.  I did not realize that S registers
 could switch pointers, that does make things a little harder.  I have
 a recommendation for a possible hybrid solution.  Incur the cost of
 spilling I,S,N registers heavily.  Restore the state of P register.

My conclusion was that with the copying approach I,S,N registers are
unusable.

 I suggest this because it seems likely that P registers will have much
 greater pressure on them then the others.

Who knows that (now)?

Here is the register usage line Dan has posted some time ago:

|  registers needed:I3597, N0, S962, P6207

(these are of course virtual registers but 271 registers got spilled)

It'll be ultimate fun to map registers to 16 preserved P over a
call, BTW.

 Matt

leo


Re: continuation enhanced arcs

2004-12-01 Thread Luke Palmer
Bill Coffman writes:
 I can see that there is true magic in the power of using references in
 this way.  Nonetheless, how can the compiler figure out that it can't
 use an integer here?  The compiler should use integers when it can,
 but it sounds like you are saying that when a variable crosses a sub
 call (which might invoke a continuation) it will then have to be a PMC
 or String to do the right thing.

Yep.  And that's something that the compiler will just have to know (or
give IMCC enough information to do something about it).

And, IIRC, an S register wouldn't work either, since strings are value
types at the bytecode level. 

Luke

  Remember the PMC and string registers
  hold pointers to pmc/string structures, which is all we're preserving
  -- the *pointer* to the structure, not the contents of the structure.
  (Though that's an interesting thing to do for other reasons, like,
  say, transactions, we're not going to be doing that) The contents can
  change over and over without the register itself ever changing.
  
  
  
  # these two lines are main
  outer()
  $saved.call
  
 
 Bill
 
  JEff
  
  --
  Dan
 


Re: continuation enhanced arcs

2004-12-01 Thread Bill Coffman
All,

As with most technical problems, fully specifying them, is often half
the battle.  In this case, I think we're getting close to
understanding the issues at least.

[please treat all statements as possible questions]

First, consider my original post in this thread:
http://www.nntp.perl.org/group/perl.perl6.internals/27383
To summarize:
  Full continuations are powerful but expensive.  They are like hidden
goto's and add arcs to the control flow graph.  This causes more
registers to interfere.
  Proposed Solutions:
- Accept the arcs and probable spilling.  We still have the regions
between sub calls.
- Put labels on certain subs that denote they might call or be called
by a continuation.
- Pragmas indicating ranges where continuations won't be called (or will be).
- Restore registers from lexicals somewhere, after each function call.
- Accept incorrectness, as the current implementation does (discovered
when new allocator failed 2 tests, and Leo saw the problem).

Next, consider Dan's message, Lexicals, continuations, and register
allocation:
On Tue, 30 Nov 2004 10:22:29 -0500, Dan Sugalski [EMAIL PROTECTED] wrote:
 So far as I can tell there are two cases here:
 
 1) A return continuation
 
 2) A regular continuation
 
[snip return contuations, which are far from solved, but likely a
subset of the below]
 
 The second case, where code takes an arbitrary continuation that
 returns to location X, wherever X is. I'm missing the problem there,
 too. Assuming there's a way to note the destination to the register
 allocator (with those points being places where all registers must be
 assumed to be trash) I'm not seeing the problem either. There are
 only two cases here, where the destination is marked and where it
 isn't. If it's marked, the register allocator assumes things are
 dirty and loads everything, which is fine. If it's unmarked, the code
 has essentially shot itself and everything quietly goes to hell since
 you've lied to the register allocator and you shouldn't do that.
 Which is fine too. Don't Do That.

If I read the above correctly, Dan is advocating the strongest
restriction of all, which is to specify any arcs that might be added. 
That is, specify all sub_i - sub_j, where - means that a
continuation saved in sub_j is invoked by sub_i.

To reclassify the reasonable solutions:
1a. Concentrate on restoring registers after calling -- probably using
the lexicals.
1b. Possibly increase the size of the register set, and/or try to use
lexicals or globals (I think of this as a kind of improved spilling)..
2a. Insert all the arcs into the CFG, which will increase spilling, but
2b. Reduce the number of arcs in the CFG, by introducing various
annotations on subs indicating when they do or do not save or invoke a
continuation.  Especially target library functions.

Currently, I'm trying to work on 2a right now, but my day job is
making that tough lately.  Would like to see more attention payed to
2b, by those who care about the issue.  In particular I'd like to see
HLL designers say, Yeah, 2b looks like a great idea!, and maybe a
few, yeah, let's specifically implement the following...

Then, there are additional problems to contend with...

On Wed, 1 Dec 2004 09:49:34 -0800, Jeff Clites [EMAIL PROTECTED] wrote:
 But so it sounds like I and N registers are a bit of a waste then, no?
 They won't really be used. Even in your my int @foo case, you could
 have an optimized backing store for the array, but you'd have to
 on-the-fly create a PMC to hold any values you pulled out of the array,
 e.g. for a subsequent x = @foo[1] (in Perl6 syntax)--x would have to
 hold a full PMC there, it seems, so nothing there would end up in an I
 register (except as in intermediate in immediately creating the PMC).
[snippage of examples]

If I understand right, PerlArray's would be used for my int @foo. 
If you want to use these values, you have to copy back and forth from
I* registers, for the most part.

The ISN registers can be used in the nether regions, between sub calls
(even the lower half of the registers can be used there).  Subs which
are garanteed not to call or save continuations are safe (see 2b
above), and ISN registers can be used while crossing those.

However, we now know that only P registers can cross unsafe subs,
unless ...  well, there's probably certain cases where ISN's can be
used.  That question would take more thought.

My sense is that we want to support continuations, but we don't want
to be crushed under the heavy load.  Perhaps we can adapt the policy
that if one is brazen enough to use full continuations, then s/he
should be expected to at least inform the compiler about it.

Bill


Re: continuation enhanced arcs

2004-11-30 Thread Bill Coffman
On Tue, 30 Nov 2004 14:45:39 -0500, Dan Sugalski [EMAIL PROTECTED] wrote:
 At 11:20 AM -0800 11/30/04, Jeff Clites wrote:
 % cat continuation6.ruby
 def strange
  callcc {|continuation| $saved = continuation}
 end
 
 def outer
  a = 0
  strange()
  a = a + 1
  print a = , a, \n
 end
 
 Through the joys of reference types, a will continue to increase
 forevermore, assuming the compiler hasn't incorrectly put a in an int
 register. (Which'd be wrong) 

I can see that there is true magic in the power of using references in
this way.  Nonetheless, how can the compiler figure out that it can't
use an integer here?  The compiler should use integers when it can,
but it sounds like you are saying that when a variable crosses a sub
call (which might invoke a continuation) it will then have to be a PMC
or String to do the right thing.

 Remember the PMC and string registers
 hold pointers to pmc/string structures, which is all we're preserving
 -- the *pointer* to the structure, not the contents of the structure.
 (Though that's an interesting thing to do for other reasons, like,
 say, transactions, we're not going to be doing that) The contents can
 change over and over without the register itself ever changing.
 
 
 
 # these two lines are main
 outer()
 $saved.call
 

Bill

 JEff
 
 --
 Dan


Re: continuation enhanced arcs

2004-11-29 Thread Jeff Clites
On Nov 28, 2004, at 2:48 AM, Piers Cawley wrote:
I just thought of a heuristic that might help with register
preservation:
A variable/register should be preserved over a function call if either 
of the
following is true:

1. The variable is referred to again (lexically) after the function has
   returned.
2. The variable is used as the argument of a function call within the
   current compilation unit.
That doesn't solve it, though you'd think it would. Here's the 
counter-example:

x = 1
foo()
print x
y = 2
return y
You'd think that x and y could use the same memory location (register, 
variable--whatever), since ostensibly their lifetimes don't overlap. 
But continuation re-invocation can cause foo() to return multiple 
times, and each time it should print 1, but it won't if x and y use 
the same slot (it would print 2 each time after the first). In 
truth, their lifetimes do overlap, due to the hidden (potential) loops 
created by continuations.

The problem isn't preservation across calls per se, it's the implicit 
loops. Continuations are basically gumming up tons of potential 
optimizations.

JEff


Re: continuation enhanced arcs

2004-11-28 Thread Piers Cawley
Leopold Toetsch [EMAIL PROTECTED] writes:

 Piers Cawley [EMAIL PROTECTED] wrote:
 Leopold Toetsch [EMAIL PROTECTED] writes:

 We don't have a problem WRT register preservation, the problem arises
 due to register re-using.

 Ah! [a light goes on over Piers's head].

 Or am I missing something fundamental?

 I don't know ;)

 I was. Hmm... bugger. So, unless we make the register allocator solve
 the halting problem, the rule becomes If you're playing silly beggars
 with continuations and you're expecting to get at something in a
 'surprising' way, stuff it in a lexical or we guarantee that you will be
 anally violated by an enraged waterbuffalo that's just sick to death of
 non-determinism?

 This would make quite a fine explanation in the docs, except that's a
 bit unclear about stuff *it*. The waterbuffalo is concerned of
 preserved *temporary* variables too.

I just thought of a heuristic that might help with register
preservation:

A variable/register should be preserved over a function call if either of the
following is true:

1. The variable is referred to again (lexically) after the function has
   returned.  
2. The variable is used as the argument of a function call within the
   current compilation unit.

Condition 2 is something of a bugger if you have big compilation units,
but register allocation is always going to be a pain when there are big
compilation units around.



Re: continuation enhanced arcs

2004-11-27 Thread Leopold Toetsch
Piers Cawley [EMAIL PROTECTED] wrote:
 Leopold Toetsch [EMAIL PROTECTED] writes:

 We don't have a problem WRT register preservation, the problem arises
 due to register re-using.

 Ah! [a light goes on over Piers's head].

 Or am I missing something fundamental?

 I don't know ;)

 I was. Hmm... bugger. So, unless we make the register allocator solve
 the halting problem, the rule becomes If you're playing silly beggars
 with continuations and you're expecting to get at something in a
 'surprising' way, stuff it in a lexical or we guarantee that you will be
 anally violated by an enraged waterbuffalo that's just sick to death of
 non-determinism?

This would make quite a fine explanation in the docs, except that's a
bit unclear about stuff *it*. The waterbuffalo is concerned of
preserved *temporary* variables too.

leo


Re: continuation enhanced arcs

2004-11-26 Thread Piers Cawley
Leopold Toetsch [EMAIL PROTECTED] writes:

 Piers Cawley [EMAIL PROTECTED] wrote:
 Okay, I'm confused, I thought that the whole point of a caller saves,
 continuation passing regime was that the caller only saves what it's
 interested in using after the function returns.

 We don't have a problem WRT register preservation, the problem arises
 due to register re-using.

 ... Exactly *where* that
 return happens, and whether it happens more than once, is completely
 irrelevant from the point of view of the caller.

 The return can only happen, where the normal function call would have
 returned, but anyway.

 ... ISTM that the register
 allocator should work on the principle that anything it didn't save
 before it made the call will be toast afterwards.

 Yes. But - please remember your example Fun with nondeterministic searches.
 Here's the relevant piece of code from main:

arr1=[1,3,5]
arr2=[1,5,9]
x = choose(arr1)
y = choose(arr2)
$P0 = find_lex fail
$P0()

 You know, both choose calls capture the continuation and backtrack via
 fail (basically). But the register allocator isn't aware of that. The
 control flow graph (CFG) is linear top down, with new basic blocks
 starting after each function call. arr2 is obviously used around a
 call and allocated in the preserved (non-volatile) register area. This
 works fine.

 Now the register allocator assigns a register to $P0. It finds the
 register that arr2 had usable, because in a linear CFG, there's no way
 that arr2 might be used again. So that register is considered being
 available. Now if $P0 happens to get the register that arr2 had,
 backtracking through the call to fail() obviously fails, as arr2 is
 now the Closure PMC. And that was exactly the case.

Ah! [a light goes on over Piers's head].


 Or am I missing something fundamental?

 I don't know ;) 

I was. Hmm... bugger. So, unless we make the register allocator solve
the halting problem, the rule becomes If you're playing silly beggars
with continuations and you're expecting to get at something in a
'surprising' way, stuff it in a lexical or we guarantee that you will be
anally violated by an enraged waterbuffalo that's just sick to death of
non-determinism?
 




Re: continuation enhanced arcs

2004-11-25 Thread Piers Cawley
Okay, I'm confused, I thought that the whole point of a caller saves,
continuation passing regime was that the caller only saves what it's
interested in using after the function returns. Exactly *where* that
return happens, and whether it happens more than once, is completely
irrelevant from the point of view of the caller. ISTM that the register
allocator should work on the principle that anything it didn't save
before it made the call will be toast afterwards. Doing anything more
sophisticated than optimizing register allocation on a sub by sub basis
seems like a license for getting completely and utterly plaited.

Or am I missing something fundamental?


Re: continuation enhanced arcs

2004-11-23 Thread Leopold Toetsch
Matt Fowles wrote:
It is also possible for functions to jump forward to the return
continuation of a function called later on 
Yes. But I can't see a problem with that. The opcode after an invoke 
opcode is already the begin of a new basic block. The forward branch 
would just be an additional edge in the CFG with no additional information.

The (for the register allocator invisible) creation of loops is the PITA.
Matt
leo


continuation enhanced arcs

2004-11-22 Thread Bill Coffman
Hello all,

I would like to address the problem of how continuations have affected
the register allocator.  This problem came to the public eye, when two
tests that the new register allocator failed.  Leo's analysis was
essentially that the allocator was fine, but that our handling of
continuations was incomplete, as far control flow and regiester
allocation went.

First, I think that it is important to acknowledge what is actually
agreed upon.  Exceptions are handled as a special case of
continuations, and as such, this is a subproblem of the general
continuations problem.  Leo's proposed solution, below seems to have
been accepted as workable, correct, and fast enough.

 Quoth [EMAIL PROTECTED]:
 1a) for exceptions:

  set_eh handler, catch_label

   This is just a small adaption of the sequence of installing an
   exception handler.
   It depends a bit, if exception handlers are inline or nested
   closures or both.

Second, is the larger, *unresolved* problem of continuations in
general.  Bear with me, as I am just barely beginning to understand
continuations myself.  Comments on my observations are more than
welcome.  Especially on my mistakes.

Continuations are a kind of goto.  When you invoke a continuation,
it moves the program counter to where the continuation was taken, and
restore most state (but not registers).  This scheme has provided a
wealth of power, with acceptable performance for a variety of
circumstances.  One neglected consideration, when implementing this
strategy, is the effect on the control flow graph.

sub1()  ---+  -+
... ||
sub2()  +-+ |
...| |
sub3()  ---+-+

In the continuations enhanced control flow graph (the control flow
graph (cfg), after one considers the effects of continuations), it is
possible for any subroutine to jump back to the exit point of any
previous subroutine.  Leo has drawn the picture a few times, as above,
showing the complex web of links from any sub to any sub.  It is the
control flow graph which provides the register allocator with the
information it nees to determines which variables interfere.  They
interfere if they could be active at the same time.  If they
interfere, they must be assigned different registers.

Now, consider a slightly different topic: According to recent
decisions, the lower half of the registers (0-15) for all types, will
not survive a subroutine call.  This has created what we can call
volatile, and non-volatile symbols (variables).  Non-volatile symbols
do not cross subroutine calls, and can therefore be put in the lower
register half.  Volatile symbols cross sub calls, and cannot be put in
the lower half.  (Think the volatile keyword from C, which means
don't mess with this value, well it sort of means that.)

Here's the funny thing -- in the new continuations enhanced flowgraph,
every volatile symbol in a subroutine will interfere with every other
volatile symbol.  Here's an informal proof.  Remember all those arcs
that Leo drew?  For instance, if v1 crosses sub1() and v2 crosses
sub2(), there is an arc from sub2() back to sub1() [wolog, sub1 is
first].  So v1 is live when v2 is live, and the two symbols interfere.
 All those arcs extend the life range of each symbol to that extent. 
Therefore, all volatile symbols in the sub will interfere.

What this means is that if your subroutine has more than 16 volatile
symbols of a given kind, there will be spilling.

Here's a list of proposals I have seen to deal with that issue:

1) Let the above stand (I think I was the only one who said that, and
that was before I had really thought about it).

2) Let the above stand, but allow for a pragma to turn off the arcs. 
Thus, I can create a range within the sub, that turns off all those
pesky continuation enhanced arcs within that range.  HLL compiler
writers will be able to set this pragma, knowing that none of it's
subs use continuations.  (Larry Wall's suggestion.)

3) Specifically a label for each subroutine that *might* set a
continuation.  Others have said that continuations should not be the
common case, if a continuation could be called, then labelling it as
RESUMABLE, isn't such a bad idea.  (Leo's idea.)
3a) The natural extension of that is to also have label, like
INVOKEABLE, for subs that might invoke a continuation.

4) Fetch all from lexicals/globals after a function call.  (Another
of Leo's.)
4a) Use lexicals instead of registers. (Not sure who mentioned it, but
it seems like just spilling everything, using a slightly different
spilling scheme.)
4b) Conditionally fetch ... (Ben's suggestion is one that deserves
some further thought.  Leo doesn't think it could work, and he
understands the problem better than I, but his answer is not a
difinitive impossible, so that gives some hope.)

5) Let the symbols interfere.  The chances are that the program will
run correctly anyway.  Let the register allocator do it's thing, and
every