The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

PIR - calling conventions

VERSION

0.1 initial proposal
0.2 initial, checked in
0.3 updated parrot calling conventions and invoke
0.4 methods and shortcuts documented

OVERVIEW

This document describes subroutine and method calling conventions.

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.

Parrot calling conventions - CPS

Explicitely Calling PASM Subroutines

  newsub $P0, .Sub, _sub_label
  newsub $P1, .Continuation, ret_addr
  ...
  .pcc_begin prototyped|non_prototyped
  .arg x        # I5
  .arg y        # I6
  .arg z        # I7
  .pcc_call $P0, $P1    # r = _sub_label(x, y, z)
  ret_addr:
  .local int r  # optional - new result var
  .result r
  .pcc_end

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)

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

Subpragma

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

  • prototyped, non_prototyped

    Specify calling convention

  • @MAIN

    Define "main" entry point to start execution.

  • @LOAD

    Run this subroutine during the load_library opcode. @LOAD is ignored, if another subroutine in that file is marked with @MAIN.

  • method

    Declare subroutine being a method.

Notes:

  • prototyped, non_prototyped

    If a subroutine definition has no prototyped specifier, code gets emitted to receive parameters by both flavors.

  • newsub

    Currently needs the .Class syntax, i.e. a dot in front of the class name.

  • pcc_call

    Takes either 2 arguments: the sub and the return continuation, or the sub only. For the latter case an 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.

  • Saved Regs:

    Only the top half of registers are preserved currently.

  • .args, .param, .result, and .return are optional.

  • .param

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

  • pcc_begin_return, 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 invoke P1 as last instruction automatically.

Getting the Parameter Count

The reserved words argcI, argcS, argcP, and argcN hold the count of passed parameters (or return values) according to docs/pdds/pdd03_calling_conventions.pod. The variable is_prototyped is an alias for I0.

Calling Methods

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

   .local pmc class
   .local pmc obj
   newclass class, "Foo"
   find_type $I0, "Foo"
   new obj, $I0
  .pcc_begin prototyped|non_prototyped
  .arg x        # I5
  .arg y        # I6
  .arg z        # I7
  .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.

Shortcuts

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

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 [ "" ]

NCI

Proposed syntax:

  load_lib $P0, "libname"
  dlfunc $P1, $P0, "funcname", "signature"
  ...
  .pcc_begin prototyped
  .arg x        # I5
  .arg y        # I6
  .arg z        # I7
  .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 pdd03_calling_conventions.pod, saves the registers and invokes the function. The .arg pseudo ops put the given argument into increasing registers of the appropriate type.

Exception handlers

TBD.

Stack calling conventions

Arguments are saved 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 restored 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

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.

Status

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

Invoking subroutines

IMCC tries to keep track of the address where the invoke will branch to, but can only succeed to do so when the set_addr and the 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.

Status

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

Namespaces and lexicals

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

FILES

imcc/imcc.y, imcc/t/syn/bsr.t, imcc/t/syn/pcc.t, imcc/t/syn/objects.t, docs/pdds/pdd03_calling_conventions.pod

AUTHOR

Leopold Toetsch <lt@toetsch.at>