aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--compiler/compiler.go7
-rw-r--r--docs/internals.rst15
-rw-r--r--main.go6
3 files changed, 20 insertions, 8 deletions
diff --git a/compiler/compiler.go b/compiler/compiler.go
index 436544d82..bb2ddc61e 100644
--- a/compiler/compiler.go
+++ b/compiler/compiler.go
@@ -3114,9 +3114,11 @@ func (c *Compiler) NonConstGlobals() {
}
}
-// Replace i64 in an external function with a stack-allocated i64*, to work
+// When -wasm-abi flag set to "js" (default),
+// replace i64 in an external function with a stack-allocated i64*, to work
// around the lack of 64-bit integers in JavaScript (commonly used together with
// WebAssembly). Once that's resolved, this pass may be avoided.
+// See also the -wasm-abi= flag
// https://github.com/WebAssembly/design/issues/1172
func (c *Compiler) ExternalInt64AsPtr() error {
int64Type := c.ctx.Int64Type()
@@ -3220,7 +3222,8 @@ func (c *Compiler) ExternalInt64AsPtr() error {
c.builder.SetInsertPointAtEnd(entryBlock)
var callParams []llvm.Value
if fnType.ReturnType() == int64Type {
- return errors.New("todo: i64 return value in exported function")
+ return errors.New("not yet implemented: exported function returns i64 with -wasm-abi=js; " +
+ "see https://tinygo.org/compiler-internals/calling-convention/")
}
for i, origParam := range fn.Params() {
paramValue := externalFn.Param(i)
diff --git a/docs/internals.rst b/docs/internals.rst
index 5cf61d611..14091d9bb 100644
--- a/docs/internals.rst
+++ b/docs/internals.rst
@@ -130,8 +130,8 @@ somewhat compatible with the C calling convention but with a few quirks:
pointers. This avoids some overhead in the C calling convention and makes
the work of the LLVM optimizers easier.
- * The WebAssembly target never exports or imports a ``i64`` (``int64``,
- ``uint64``) parameter. Instead, it replaces them with ``i64*``, allocating
+ * The WebAssembly target by default doesn't export or import ``i64`` (``int64``,
+ ``uint64``) parameters. Instead, it replaces them with ``i64*``, allocating
the value on the stack. In other words, imported functions are called with a
64-bit integer on the stack and exported functions must be called with a
pointer to a 64-bit integer somewhere in linear memory.
@@ -144,10 +144,15 @@ somewhat compatible with the C calling convention but with a few quirks:
calling convention workaround may be removed. Also see `this wasm-bindgen
issue <https://github.com/rustwasm/wasm-bindgen/issues/35>`_.
+ Currently there are also non-browser WebAssembly execution environments
+ that do not have this limitation. Use the `-wasm-abi=generic` flag to remove
+ the behavior described above and enable emitting functions with i64
+ parameters directly.
+
* The WebAssembly target does not return variables directly that cannot be
- handled by JavaScript (``struct``, ``i64``, multiple return values, etc).
- Instead, they are stored into a pointer passed as the first parameter by the
- caller.
+ handled by JavaScript (see above about ``i64``, also ``struct``, multiple
+ return values, etc). Instead, they are stored into a pointer passed as the
+ first parameter by the caller.
This is the calling convention as implemented by LLVM, with the extension
that ``i64`` return values are returned in the same way as aggregate types.
diff --git a/main.go b/main.go
index fb0d72438..6ae182482 100644
--- a/main.go
+++ b/main.go
@@ -36,6 +36,7 @@ type BuildConfig struct {
initInterp bool
cFlags []string
ldFlags []string
+ wasmAbi string
}
// Helper function for Compiler object.
@@ -97,7 +98,8 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
// cannot be represented exactly in JavaScript (JS only has doubles). To
// keep functions interoperable, pass int64 types as pointers to
// stack-allocated values.
- if strings.HasPrefix(spec.Triple, "wasm") {
+ // Use -wasm-abi=generic to disable this behaviour.
+ if config.wasmAbi == "js" && strings.HasPrefix(spec.Triple, "wasm") {
err := c.ExternalInt64AsPtr()
if err != nil {
return err
@@ -507,6 +509,7 @@ func main() {
port := flag.String("port", "/dev/ttyACM0", "flash port")
cFlags := flag.String("cflags", "", "additional cflags for compiler")
ldFlags := flag.String("ldflags", "", "additional ldflags for linker")
+ wasmAbi := flag.String("wasm-abi", "js", "WebAssembly ABI conventions: js (no i64 params) or generic")
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "No command-line arguments supplied.")
@@ -524,6 +527,7 @@ func main() {
debug: !*nodebug,
printSizes: *printSize,
initInterp: *initInterp,
+ wasmAbi: *wasmAbi,
}
if *cFlags != "" {