Leopold Toetsch <[EMAIL PROTECTED]> writes:
> Piers Cawley <[EMAIL PROTECTED]> wrote:
>> Leopold Toetsch <[EMAIL PROTECTED]> writes:
>
>>> C<savetop> becomes C<pushtopp> if only P-registers are used. Saving only
>>> 3 or 5 registers isn't possible yet. We have no opcodes for that.
>
>>   save Pn
>>   save Pm
>
> Well, these are already used for pushing items onto the user stack. It
> could be
>
>    pushtopp 3   # save P16..P18
>    savetop 4    # save 4 regs from all I16 ..., S16, N16, P16 ... P19
>
> and so on.

Out of interest, why do we have distinct register and user stacks?

[...]

>> ... Presumably, because IMCC knows that
>> cont_ret is a continuation target, it can create the appropriate
>> real_cont_ret and add the appropriate stack manipulation code in there?
>> This would be really cool.
>
> The code for creating the continuation and the return must be in sync.
> When you pass the continuation on into a subroutine and want to return
> either normally or through the continuation, we need something like:
>
>     $P0 = newcont dest_label FOR _invoker
>     _invoker($P0)
>     ...
>   dest_label:
>     ...

But the function the continuation gets passed to is completely
irrelevant. When you make a continuation you want to save exactly the
same state as you'd save if you were making a function call at the same
point. 

Say you had code like

     ...
     $P0 = "Something"
     $P1 = "Something else"
     $P2 = "Some other thing"
     .newcont $P3, dest_label
     ...
   do_return:
     .pcc_begin_return
     .pcc_end_return


   dest_label:
     print $P0
     print $P2
     branch do_return

Then it'd be cool if IMCC could look ahead to see that when (if) the
continuation is invoked, the only registers that get used are $P0 and
$P2 and emit something like:


     ...
     $P0 = "Something"
     $P1 = "Something else"
     $P2 = "Some other thing"
     save P1
     save P2
     save $P0
     save $P2
     $P3 = newcont Continuation, dest_label
     restore $P2
     restore $P0
     restore P2
     restore P1
     ...
   do_return:
     .pcc_begin_return
     .pcc_end_return


   dest_label:
     restore $P2
     restore $P0
     restore P2
     restore P1
     print $P0
     print $P2
     branch do_return
    
But I have the feeling I'm thinking IMCC is rather more sophisticated
than it is in real life. From the point of view of a programmer, the
important thing is that invoking a continuation should return the upper
and control registers (but not the argument registers) to the state
they were in when the continuation was made. How the continuation is
subsequently stored/passed is completely irrelevant to this. 

> Creating correct code from that is a bit ugly, because the continuation
> is created, before the actual call sequence is generated. So a bit more
> verbose:
>
>     .pcc_begin prototyped
>     .arg_newcont dest_label
>     .pcc_call _invoker
>     .pcc_end
>     ...
>
>   .CONT_TARGET dest_label:
>
> That's still complicated but doable. That would need searching the
> current unit for subroutine calls that have a C<.arg_newcont> argument,
> compare the labels and create finally the very same register
> restore opcode(s) that the function call has.
>
> OTOH storing a continuation inside a global can't prepare any code for
> the continuation return, because nothing about the continuation's usage
> is known.

This is irrelevant.

>>>   assign $P0, P1       # vtable->set_pmc  (N/Y)
>
>> Assign would be good. I can't really think of an occasion when you'd
>> want to copy anything less than the full context held by the
>> continuation.
>
> What about:
>
>   .sym pmc cont
>   cont = newcont dest
>   ...
>   updatecc cont   # assign current P1's context to cont
>
> With
>
>   assign cont, P1
>
> we need another syntax extension to actually get the real P1 register:
>
>   assign cont, current_P1
>
> or P1 is always restored immediately after function calls (like
> currently P2).
>
> I think, C<assign> and restoring P1 immediately would be the most useful
> combination.

Absolutely.

Reply via email to