docs: move calling convention documentation here
Этот коммит содержится в:
родитель
85d5fe7643
коммит
c7cf6f0e82
2 изменённых файлов: 69 добавлений и 30 удалений
|
@ -5,32 +5,11 @@ import (
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This file implements the calling convention used by Go.
|
// For a description of the calling convention in prose, see docs/internals.rst
|
||||||
// The calling convention is like the C calling convention (or, whatever LLVM
|
// or the online version of this document:
|
||||||
// makes of it) with the following modifications:
|
// https://tinygo.readthedocs.io/en/latest/internals.html#calling-convention
|
||||||
// * 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.
|
|
||||||
//
|
//
|
||||||
// Some further notes:
|
// 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
|
// * Defer statements are implemented by transforming the function in the
|
||||||
// following way:
|
// following way:
|
||||||
// * Creating an alloca in the entry block that contains a pointer
|
// * Creating an alloca in the entry block that contains a pointer
|
||||||
|
|
|
@ -79,12 +79,12 @@ interface
|
||||||
|
|
||||||
function pointer
|
function pointer
|
||||||
A function pointer has two representations: a literal function pointer and a
|
A function pointer has two representations: a literal function pointer and a
|
||||||
tuple of ``{context, function pointer}``. Which representation is chosen
|
fat function pointer in the form of ``{context, function pointer}``. Which
|
||||||
depends on the AnalyseFunctionPointers pass in `ir/passes.go
|
representation is chosen depends on the AnalyseFunctionPointers pass in
|
||||||
<https://github.com/aykevl/tinygo/blob/master/ir/passes.go>`_: it tries to
|
`ir/passes.go <https://github.com/aykevl/tinygo/blob/master/ir/passes.go>`_:
|
||||||
use a raw function pointer but will use a function pointer with context if
|
it tries to use a raw function pointer but will use a fat function pointer
|
||||||
there is a closure or bound method somewhere in the program with the exact
|
if there is a closure or bound method somewhere in the program with the
|
||||||
same signature.
|
exact same signature.
|
||||||
|
|
||||||
goroutine
|
goroutine
|
||||||
A goroutine is a linked list of `LLVM coroutines
|
A goroutine is a linked list of `LLVM coroutines
|
||||||
|
@ -101,6 +101,66 @@ goroutine
|
||||||
consumption.
|
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
|
Pipeline
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче