# Copyright (C) 2001-2005, The Perl Foundation.
# $Id: calling_conventions.pod 12839 2006-05-30 14:34:31Z coke $

=head1 NAME

PIR - calling conventions

=head1 VERSION

0.5

=head1 NOTE ABOUT CHANGES IN PROGRESS

The syntax here is going to stay, but the calling convention is in the
middle of a transition.  Instead of fixed registers, the new
convention allows the user to use any registers in any order, and
converts types as required.  Additional syntax features, like the
C<:flat> adverb for arguments and C<:slurpy> for parameters, will make
sense to explain here once the document as a whole is updated.

One thing that's handy: If you have a list in a PMC and you want it to
be flattened out into a list, append C<:flat> to the argument name in
the C<.arg> directive or in the shortcut parameter list.

=head1 OVERVIEW

This document describes subroutine and method calling conventions.

=head1 DESCRIPTION

As imcc does register allocation, it has to track the life span of
variables. This includes the (possible) data flow in and out of
subroutines.

=head1 Parrot calling conventions - CPS

=head2 Explicitly Calling PASM Subroutines

  .const .Sub $P0 = "_sub_label" 
  $P1 = new .Continuation
  set_addr $P1, ret_addr
  ...
  .local int x
  .local num y
  .local str z
  .pcc_begin
  .arg x
  .arg y
  .arg z
  .pcc_call $P0, $P1	# r = _sub_label(x, y, z)
  ret_addr:
  .local int r  # optional - new result var
  .result r
  .pcc_end

=head2 The Short Way

  ...  # variable decls
  r = _sub_label(x, y, z)
  (r1[, r2 ...]) = _sub_label(x, y, z)
  _sub_label(x, y, z)

Instead of the label a Subroutine object can be used too:

   find_global $P0, "_sub_label"
   $P0(args)

=head2 Subroutines

  .sub _sub_label [Subpragma, ...]
   .param int a # I5
   .param int b # I6
   .param int c # I7
  ...
  .pcc_begin_return
   .return xy   # e.g. I5
  .pcc_end_return
  ...
  .end

An alternative syntaxs allow to express a return in one line.
The surrounded parentheses are mandatory. Besides making
sequence break more conspiscuous, this is necessary to
distinguish this syntax from other uses of the .return directive
that will be probably deprecated.

  .return ( a, b )      # return the values of a and b

  .return ()            # return no value

  .return func_call()   # tail call function

  .return o."meth"()    # tail method call

Similarly, one can yield using the .yield directive

  .yield ( a, b )      # yield with the values of a and b

  .yield ()            # yield with no value


=head2 Subpragma

This is a list of zero or more items with the
following meaning:

=over 4

=item * :main

Define "main" entry point to start execution. If multiple subroutines
are marked as B<:main>, the B<last> marked subroutine is entered.

=item * :load

Run this subroutine during the B<load_library> opcode.
B<:load> is ignored, if another subroutine in that file is marked with
B<:main>. If multiple subs have the B<:load> pragma, the subs are
run in compilation that is source code order.

=item * :anon

Do not install this subroutine in the namespace. Allows the subroutine
name to be reused.

=item * :multi(Type1, Type2...)

Engage in multiple dispatch with the listed types.

=item * :method

Declare subroutine being a method.

=back

Notes:

=over 4

=item * B<pcc_call>

Takes either 2 arguments: the sub and the return continuation, or the
sub only. For the latter case an B<invokecc> gets emitted. Providing
an explicit return continuation is more efficient, if its created
outside of a loop and the call is done inside a loop.

=item * Saved Regs:

Only the top half of registers are preserved currently.

=item * B<.args>, B<.param>, B<.result>, and B<.return> are optional.

=item * B<.param>

The B<.param> declarations must be the first statements in the
sub if any. No other statements are allowed between B<.param> -
not even comments currently.

=item * B<pcc_begin_return>, B<pcc_end_return>

If there is no return value and the return should be the last
instruction of the subroutine, this declaration pair can be omitted.
Parrot provides an B<invoke P1> as last instruction automatically.

=back

=head2 Calling Methods

The syntax is very similar to subroutine calls. The call is done with
C<meth_call> which must immediately be preceded by the C<.invocant>:

   .local pmc class
   .local pmc obj
   newclass class, "Foo"
   find_type $I0, "Foo"
   new obj, $I0
  .pcc_begin
  .arg x
  .arg y
  .arg z
  .invocant obj
  .meth_call "_method" [, $P1 ]	# r = obj."_method"(x, y, z)
  .local int r  # optional - new result var
  .result r
  .pcc_end

The return continuation is optional. The method can be a string
constant or a string variable.

=head2 Shortcuts

  r = obj."_method"(args)
  (r1, r2) = obj."_method"(args)
  obj."_method"(args)

=head2 Methods

  .namespace [ "Foo" ]

  .sub _sub_label method [,Subpragma, ...]
   .param int a # I5
   .param int b # I6
   .param int c # I7
   ...
   self."_other_meth"()
  ...
  .pcc_begin_return
   .return xy   # e.g. I5
  .pcc_end_return
  ...
  .end

The variable "self" automatically refers to the invocating object, if the
subroutine declaration contains "method".

Restore namespace to the global namespace:

  .namespace [ "" ]

=head2 NCI

Proposed syntax:

  load_lib $P0, "libname"
  dlfunc $P1, $P0, "funcname", "signature"
  ...
  .pcc_begin
  .arg x
  .arg y
  .arg z
  .nci_call $P1	# r = funcname(x, y, z)
  .local int r  # optional - new result var
  .result r
  .pcc_end

This prepares parameters as described in
F<pdd03_calling_conventions.pod>, saves the registers and invokes the
function.  The B<.arg> pseudo ops put the given argument into
increasing registers of the appropriate type.


=head1 Exception handlers

TBD.

=head1 Stack calling conventions

Arguments are B<save>d in reverse order onto the user stack:

   .arg y	# save args in reversed order
   .arg x
   call _foo	#(r, s) = _foo(x,y)
   .local int r
   .local int s
   .result r	# restore results in order
   .result s	#

and return values are B<restore>d in argument order from there.

The subroutine is responsible for preserving registers.

 .sub _foo		# sub foo(int a, int b)
   saveall
   .param int a         # receive arguments from left to right
   .param int b
   ...

   .return mi		# return (pl, mi), push results
   .return pl		# in reverse order
   restoreall
   ret
 .end

=head2 Rational

Pushing arguments in reversed order on the user stack makes the left
most argument the top of stack entry. This allows for a variable
number of function arguments (and return values), where the left most
argument before a variable number of following arguments is the
argument count.

=head2 Status

Implemented. When the subroutine is in the same compilation unit, the
callee can B<saveall> registers; when the subroutine is in a different
compilation unit, the callee must preserve all used registers.

=head1 Invoking subroutines

IMCC tries to keep track of the address where the B<invoke> will branch
to, but can only succeed to do so when the B<set_addr> and the
B<invoke> opcodes are located together.

  $P10 = new Sub
  $I1 = addr _the_sub
  $P10 = $I1
  invoke $P10   # ok

But not:

    bsr get_addr
    invoke $P10 # error
    ...
  get_addr:
    $P10 = new Sub
    $I1 = addr _the_sub
    $P10 = $I1
    ret

The latter example will very likely lead to an incorrect CFG and thus to
incorrect register allocation.

=head2 Status

Implemented. When the subroutine does B<saveall>/B<restoreall>, the
branch from the B<ret> statement back is ignored in the CFG.

=head1 Namespaces and lexicals

 - Should imcc keep track of pad opcodes?
 - Should imcc even emit such opcodes from e.g. .local directives?

=head1 FILES

F<imcc/imcc.y>, F<t/compilers/imcc/syn/bsr.t>, F<t/compilers/imcc/syn/pcc.t>,
F<t/compilers/imcc/syn/objects.t>, F<docs/pdds/pdd03_calling_conventions.pod>

=head1 AUTHOR

Leopold Toetsch <lt@toetsch.at>

=head1 CHANGES

=over 4

=item 0.5 eliminate {non_,}prototyped distinction

=item 0.4 methods and shortcuts documented

=item 0.3 updated parrot calling conventions and invoke

=item 0.2 initial, checked in

=item 0.1 initial proposal

=back

=cut

# vim: expandtab shiftwidth=4 tw=70:
