docs: move calling convention documentation here

Этот коммит содержится в:
Ayke van Laethem 2018-11-01 11:41:24 +01:00
родитель 85d5fe7643
коммит c7cf6f0e82
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
2 изменённых файлов: 69 добавлений и 30 удалений

Просмотреть файл

@ -5,32 +5,11 @@ import (
"golang.org/x/tools/go/ssa"
)
// This file implements the calling convention used by Go.
// The calling convention is like the C calling convention (or, whatever LLVM
// makes of it) with the following modifications:
// * Struct parameters are fully expanded to individual fields (recursively),
// when the number of fields (combined) is 3 or less.
// Examples:
// {i8*, i32} -> i8*, i32
// {{i8*, i32}, i16} -> i8*, i32, i16
// {{i64}} -> i64
// {} ->
// {i8*, i32, i8, i8} -> {i8*, i32, i8, i8}
// Note that all native Go data types that don't exist in LLVM (string,
// slice, interface, fat function pointer) can be expanded this way, making
// the work of LLVM optimizers easier.
// * Closures have an extra context paramter appended at the end of the
// argument list.
// * Blocking functions have a coroutine pointer prepended to the argument
// list, see src/runtime/scheduler.go for details.
// For a description of the calling convention in prose, see docs/internals.rst
// or the online version of this document:
// https://tinygo.readthedocs.io/en/latest/internals.html#calling-convention
//
// Some further notes:
// * Function pointers are lowered to either a raw function pointer or a
// closure struct: { i8*, function pointer }
// The function pointer type depends on whether the exact same signature is
// used anywhere else in the program for a call that needs a context
// (closures, bound methods). If it isn't, it is lowered to a raw function
// pointer.
// * Defer statements are implemented by transforming the function in the
// following way:
// * Creating an alloca in the entry block that contains a pointer

Просмотреть файл

@ -79,12 +79,12 @@ interface
function pointer
A function pointer has two representations: a literal function pointer and a
tuple of ``{context, function pointer}``. Which representation is chosen
depends on the AnalyseFunctionPointers pass in `ir/passes.go
<https://github.com/aykevl/tinygo/blob/master/ir/passes.go>`_: it tries to
use a raw function pointer but will use a function pointer with context if
there is a closure or bound method somewhere in the program with the exact
same signature.
fat function pointer in the form of ``{context, function pointer}``. Which
representation is chosen depends on the AnalyseFunctionPointers pass in
`ir/passes.go <https://github.com/aykevl/tinygo/blob/master/ir/passes.go>`_:
it tries to use a raw function pointer but will use a fat function pointer
if there is a closure or bound method somewhere in the program with the
exact same signature.
goroutine
A goroutine is a linked list of `LLVM coroutines
@ -101,6 +101,66 @@ goroutine
consumption.
Calling convention
------------------
Go uses a stack-based calling convention and passes a pointer to the argument
list as the first argument in the function. There were/are `plans to switch to a
register-based calling convention <https://github.com/golang/go/issues/18597>`_
but they're now on hold.
.. highlight:: llvm
TinyGo, however, uses a register based calling convention. In fact it is
somewhat compatible with the C calling convention but with a few quirks:
* Struct parameters are split into separate arguments, if the number of fields
(after flattening recursively) is 3 or lower. This is similar to the `Swift
calling convention
<https://github.com/apple/swift/blob/master/docs/CallingConvention.rst#physical-conventions>`_.
In the case of TinyGo, the size of each field does not matter, a field can
even be an array. ::
{i8*, i32} -> i8*, i32
{{i8*, i32}, i16} -> i8*, i32, i16
{{i64}} -> i64
{} ->
{i8*, i32, i8, i8} -> {i8*, i32, i8, i8}
{{i8*, i32, i8}, i8} -> {i8*, i32, i8, i8}
Note that all native Go data types that are lowered to aggregate types in
LLVM are expanded this way: ``string``, slices, interfaces, and fat function
pointers. This avoids some overhead in the C calling convention and makes
the work of the LLVM optimizers easier.
* Some functions have an extra context parameter appended at the end of the
argument list. This only happens when both of these conditions hold:
* The address of the function is taken, for example when passing the
function as function pointer to another function or storing it in a
global variable.
* This function or another function somewhere in the compiled code has the
exact same signature and is used in a closure or bound method. Signature
matching is very strict: it is based on Go types including named types
and return types, although parameter names or the function name itself
are not included in the match.
Whether a function needs this is determined by `FunctionNeedsContext
<https://godoc.org/github.com/aykevl/tinygo/ir#Program.FunctionNeedsContext>`_,
which bases itself on analysis done by AnalyseFunctionPointers.
* Blocking functions have a coroutine pointer prepended to the argument list,
see `src/runtime/scheduler.go
<https://github.com/aykevl/tinygo/blob/master/src/runtime/scheduler.go>`_
for details. Whether a function is blocking is determined by the
AnalyseBlockingRecursive pass.
This calling convention may change in the future. Changes will be documented
here. However, even though it may change, it is expected that function
signatures that only contain integers and pointers will remain stable.
Pipeline
--------