674 Commits

Author SHA1 Message Date
Jake Bailey 5ba8766cbc compiler: implement method-set based AssignableTo and Implements (#5304)
* reflect: implement method-set based AssignableTo and Implements

Based on the design from #4376 by aykevl.
Fixes #4277, fixes #3580.

Co-authored-by: Ayke van Laethem <aykevanlaethem@gmail.com>

* builder: update expected binary sizes for reflect changes

* Make interface checks similar to invoke, allowing typeImplementsMethodSet and method info to be dropped when reflect is not present

* Add more tests that BigGo reflect tests

* Even more pruning

* Add go/token and net/url to passing tests

* Prune even further, I am less happy with this, though

* Update size test now that we are smaller

* Skip some tests

* elide method lists

* format, oops

* fix tests

* Add a panic, pull out constant to keep in sync

* Add debug info

* Remove code that was leftover from a previous refactor

---------

Co-authored-by: Ayke van Laethem <aykevanlaethem@gmail.com>
2026-04-17 21:57:03 +02:00
Jake Bailey 12d41ba0c1 go.mod, compiler: bump minimum Go version to 1.23
This enables gotypesalias=1 by default, which is needed for
generic type aliases to work correctly in go/types.
2026-04-17 19:18:17 +01:00
deadprogram ddacdfacd5 compiler, runtime: fix SyscallN handling for Windows on Go 1.26+
Go 1.26 changed all Windows syscall wrappers in zsyscall_windows.go
to use SyscallN instead of fixed-argument Syscall/Syscall6/etc. The
SyscallN function now has a body that calls an unexported syscalln
function (provided by runtime via //go:linkname).

TinyGo's existing createSyscall compiler builtin used call.Args[2:]
to extract syscall arguments, but for variadic SyscallN the SSA
representation passes args as a slice value (not individual args),
causing call.Args[2:] to be empty -- resulting in zero arguments
being passed to Windows API calls and 0xc0000005 access violations.

Fix this by:
1. Excluding syscall.SyscallN from builtin interception, letting
   Go 1.26's function body compile normally (it calls syscalln)
2. Adding a new createSyscalln compiler builtin that intercepts
   syscall.syscalln and correctly handles the variadic slice:
   - Generates a switch on the arg count n (0-18 cases)
   - Each case loads args from the slice via GEP/Load
   - Wraps calls with SetLastError(0)/GetLastError() as before
   - Handles i386 stdcall conventions
3. Adding runtime stubs for both Go versions:
   - go1.26: syscall.syscalln stub (body intercepted by compiler)
   - pre-go1.26: syscall.SyscallN stub (linker satisfaction)
2026-04-11 12:38:36 +01:00
Damian Gryski f496571747 compiler: add instrinsic for crypto/internal/constanttime.boolToUint8 2026-04-11 12:38:36 +01:00
Nia Waldvogel d8b6b257f4 compiler: simplify createObjectLayout
This simplifies the process of constructing and encoding layout bitmaps.
Instead of creating big integers and merging them, we can create a pre-sized bitmap and set positions within it.

This also changes the encoding logic to allow larger layouts to be encoded inline.
We would previously not encode a layout inline unless the size was less than the width of the data field.
This is overly conservative.
A layout can be encoded inline as long as:
1. The size fits within the size field.
2. All set bits in the bitmap fit into the data field.
2026-04-05 14:14:55 +02:00
Nia Waldvogel a40586d092 compiler: implement copy directly
The compiler now implements the copy builtin directly instead of calling sliceCopy.
The length is calculated with the llvm.umax.* intrinsics, and the move is performed by llvm.memmove.*.
Both of these operations are easily understood by LLVM's optimization passes.
The type's alignment is also provided to llvm.memmove.*, which is useful when rewriting the move.

Interp no longer needs to reimplement sliceCopy.
Some edge case handling was implemented by sliceCopy but not llvm.memmove.*/llvm.memcpy.*.
I copied this over, so copies of external slices should work now.
Volatile moves/copies are now run at runtime by interp.

There is a 4-byte size increase due to some confusing length logic in sendUSBPacket.
I will look at sendUSBPacket in a future PR.
2026-01-05 15:10:31 -05:00
Nia Waldvogel bc9708f51a compiler: fix min/max on floats by using intrinsics
This fixes two edge cases for min/max:
min/max(+0.0, -0.0) = -0.0, +0.0
min/max(number, NaN) = NaN, NaN

The compare and select method does not work here.
I switched to the llvm.minimum/llvm.maximum intrinsics which match the intended behavior.

The integer min/max were also swapped over to using intrinsics.
The compare and select path is now only used by strings.
2026-01-05 19:46:06 +00:00
Nia Waldvogel 266d70816f compiler/runtime: add element layout to sliceAppend
Attach the memory layout of the element type to newly created slices via append when using the precise collector.
2025-12-26 21:27:24 -05:00
Ayke van Laethem b203314c2f machine: make sure DMA buffers do not escape unnecessarily
Writing the pointer of a buffer to memory-mapped I/O will normally cause
it to escape, which forces the compiler to heap-allocate the buffer. But
we do know how long the value stays alive, so we can tell the compiler
to keep it alive exactly until it is not needed anymore - and tell it to
not treat the pointer-to-uintptr cast as escaping.
2025-11-12 18:07:53 +01:00
Nia Waldvogel 852dde671e compiler: use Tarjan's SCC algorithm to detect loops for defer
The compiler needs to know whether a defer is in a loop to determine whether to allocate stack or heap memory.
Previously, this performed a DFS of the CFG every time a defer was found.
This resulted in time complexity jointly proportional to the number of defers and the number of blocks in the function.

Now, the compiler will instead use Tarjan's strongly connected components algorithm to find cycles in linear time.
The search is performed lazily, so this has minimal performance impact on functions without defers.

In order to implement Tarjan's SCC algorithm, additional state needed to be attached to the blocks.
I chose to merge all of the per-block state into a single slice to simplify memory management.
2025-11-10 07:27:40 +01:00
Ayke van Laethem 48d741f68a compiler: emit an error when the actual arch doesn't match GOARCH
See: https://github.com/tinygo-org/tinygo/issues/4959
This makes sure to emit an error instead of generating inline assembly,
which leads to hard-to-debug linker errors. Instead, it will now produce
errors like the following:

    # golang.org/x/sys/unix
    ../../../../pkg/mod/golang.org/x/sys@v0.0.0-20220722155257-8c9f86f7a55f/unix/affinity_linux.go:20:23: system calls are not supported: target emulates a linux/arm system on wasm32
    ../../../../pkg/mod/golang.org/x/sys@v0.0.0-20220722155257-8c9f86f7a55f/unix/fcntl.go:17:29: system calls are not supported: target emulates a linux/arm system on wasm32
    ../../../../pkg/mod/golang.org/x/sys@v0.0.0-20220722155257-8c9f86f7a55f/unix/fcntl.go:32:24: system calls are not supported: target emulates a linux/arm system on wasm32
2025-10-23 10:13:29 +02:00
Ayke van Laethem 26ee3fb93e wasm: fix C realloc and optimize it a bit
- Do not use make([]byte, ...) to allocate, instead call the allocator
    directly with a nil (undefined) layout. This makes sure the precise
    GC will scan the contents of the allocation, since C could very well
    put pointers in there.
  - Simplify the map to use the pointer as the key and the size as the
    value, instead of storing the slices directly in the map.
2025-10-20 12:58:11 +02:00
Ayke van Laethem 7460734522 compiler: mark string parameters as readonly
Strings are readonly, but the compiler doesn't always know this. Marking
them as readonly in the frontend allows the compiler to optimize based
on this knowledge.

This provides some small code size benefits. I didn't measure running
speed.
2025-10-11 23:03:18 +02:00
张之阳 aedaf7d925 machine: fix deprecated AsmFull comment (#5005) 2025-10-04 11:19:01 +02:00
Ayke van Laethem dfbb133ea6 all: add full LLVM 20 support
This switches the Espressif fork from LLVM 19 to LLVM 20, so we can use
the improvements made between those LLVM versions. It also better aligns
with the system-LLVM build method, which currently also defaults to LLVM
20.

Note that this disables the machine outliner for RISC-V. It appears
there's a bug in there somewhere, with the machine outliner enabled the
crypto/elliptic package tests fail with -target=riscv-qemu.
This should ideally be investigated and reported upstream.
2025-09-17 05:28:06 -04:00
deadprogram 79ab77facd fix: correct linter issues exposed by the fix in #4679
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-09-14 08:03:25 -04:00
Michael Smith 663a94fcab feat: enable //go:linkname pragma for globals 2025-09-12 12:53:34 -04:00
Ayke van Laethem 34efc3a381 compiler: implement internal/abi.Escape 2025-08-06 17:08:26 +02:00
Ayke van Laethem 3a2188fc7b runtime/interrupt: add Checkpoint type
This type can be used to jump back to a previous position in a program
from inside an interrupt. This is useful for baremetal systems that
implement wfi but not wfe, and therefore have no easy (race-free) way to
wait until a flag gets changed inside an interrupt. This is an issue on
RISC-V, where this is racy (the interrupt might happen after the check
but before the wfi instruction):

    configureInterrupt()
    for flag.Load() != 0 {
        riscv.Asm("wfi")
    }
2025-06-12 21:04:36 +02:00
Ayke van Laethem 64a30424da runtime: add exportedFuncPtr
This function isn't used yet, but will be used for the "cores" scheduler
for RISC-V.
2025-06-12 21:04:36 +02:00
Ayke van Laethem 2e043c7fbc compiler: add support for GODEBUG=gotypesalias=1
Since we now require Go 1.22, this became a lot simpler (since we can
now refer to `types.Alias` and `types.Unalias`).
2025-05-24 19:49:49 +02:00
Ayke van Laethem aa63f26f36 windows: use MSVCRT.DLL instead of UCRT on i386
This allows the binaries to run on Windows XP, without needing any extra
DLLs. Tested in an x86 Windows XP SP3 virtual machine.
2025-04-22 17:45:29 +02:00
Ayke van Laethem f542717992 windows: add windows/386 support 2025-04-22 17:45:29 +02:00
Damian Gryski 0fdf08d14f add -nobounds (similar to -gcflags=-B) 2025-04-15 12:55:44 +02:00
Ayke van Laethem 5282b4efac runtime: remove unused file func.go
This was used in the past, but we don't use it anymore.
2025-03-17 22:13:17 +01:00
Ayke van Laethem 6c9074772c compiler: crypto/internal/sysrand is allowed to use unsafe signatures
Apparently this package imports `runtime.getRandomData` from the gojs
module. This is not yet implemented, but simply allowing this package to
do such imports gets crypto/sha256 to compile.
2025-03-07 09:09:13 -08:00
Ayke van Laethem 38e3d55e64 all: add Go 1.24 support 2025-02-25 14:41:42 +01:00
Ayke van Laethem ea53ace270 cgo: mangle identifier names
This mangles CGo identifier names to something like "_Cgo_foo" instead
of using literal identifiers like "C.foo". This works around
https://github.com/golang/go/issues/71777.

I don't like this solution, but I hope we'll find a better solution in
the future. In that case we can revert this commit.
2025-02-25 14:41:42 +01:00
deadprogram 17bb1fec44 feature: add buildmode=wasi-legacy to support existing base of users who expected the
older behavior for wasi modules to not return an exit code as if they were reactors.

See #4726 for some details on what this is intended to address.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-02-21 13:06:14 +01:00
Ayke van Laethem 9e9768b51d all: add support for LLVM 19 2025-01-20 06:15:33 +01:00
Ayke van Laethem f246599253 compiler: report error instead of crashing on missing function body
This can happen with generic functions, see:
https://github.com/tinygo-org/tinygo/issues/4486
2024-12-14 13:34:58 +01:00
Ayke van Laethem 26c36d0a2e runtime: lock output in print/println
This ensures that calls to print/println happening in different threads
are not interleaved. It's a task.PMutex, so this should only change
things when threading is used.

This matches the Go compiler, which does the same thing:
https://godbolt.org/z/na5KzE7en

The locks are not recursive, which means that we need to be careful to
not call `print` or `println` inside a runtime.print* implementation,
inside putchar (recursively), and inside signal handlers. Making them
recursive might be useful to do in the future, but it's not really
necessary.
2024-12-01 11:12:00 +01:00
Ayke van Laethem aed555d858 runtime: implement Goexit
This is needed for full support for the testing package
2024-11-30 11:55:22 +01:00
Ayke van Laethem 392a709b77 runtime: use uint32 for the channel state and select index
This uses uint32 instead of uint64. The reason for this is that uint64
atomic operations aren't universally available (especially on 32-bit
architectures). We could also use uintptr, but that seems needlessly
complicated: it's unlikely real-world programs will use more than a
billion select states (2^30).
2024-11-27 12:16:10 +01:00
deadprogram 6601c1b1a6 fix: add updated test output to match recent changes
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-11-20 17:55:04 +01:00
Ayke van Laethem 5ebda89d78 runtime: rewrite channel implementation
This rewrite simplifies the channel implementation considerably, with
34% less LOC. Perhaps the most important change is the removal of the
channel state, which made sense when we had only send and receive
operations but only makes things more compliated when multiple select
operations can be pending on a single channel.

I did this rewrite originally to make it possible to make channels
parallelism-safe. The current implementation is not parallelism-safe,
but it will be easy to make it so (the main additions will be a channel
lock, a global select lock, and an atomic compare-and-swap in
chanQueue.pop).
2024-11-20 14:57:30 +01:00
Ayke van Laethem fd625f7265 compiler: add //go:noescape pragma
This only works on declarations, not definitions. This is intentional:
it follows the upstream Go implemetation.

However, we might want to loosen this requirement at some point: TinyGo
sometimes stores pointers in memory mapped I/O knowing they won't
actually escape, but the compiler doesn't know about this.
2024-11-20 14:07:55 +01:00
Damian Gryski 548fba82e6 compiler: Fix wasmimport -> wasmexport in error message
Fixes #4615
2024-11-20 07:53:02 +01:00
Ayke van Laethem 6d4dfcf72f compiler, runtime: move constants into shared package
Use a single package for certain constants that must be the same between
the compiler and the runtime.

While just using the same values in both places works, this is much more
obvious and harder to mess up. It also avoids the need for comments
pointing to the other location the constant is defined. And having it in
code makes it possible for IDEs to analyze the source.

In the future, more such constants and maybe algorithms can be added.
2024-11-15 10:11:57 +01:00
Ayke van Laethem 449eefdb19 compiler: allow deferred panic
This is rare, but apparently some programs do this:

    defer panic("...")

This is emitted in the IR as a builtin function.
2024-11-01 09:11:38 +01:00
Ayke van Laethem 4e49ba597d interrupt: fix bug in interrupt lowering
The alignment wasn't set, so defaulted to 4 (for a 32-bit int). LLVM saw
this, and therefore assumed that a ptrtoint of the pointer would have
had the lowest bits unset. That's an entirely valid optimization, except
that we are using these globals for arbitrary values (and aren't
actually using these globals).

Fixed by setting alignment to 1. It works, though long-term we should
maybe find a different solution for this.
2024-11-01 09:10:25 +01:00
Randy Reddig 24c11d4ba5 compiler: conform to latest iteration of wasm types proposal (#4501)
compiler: align with current wasm types proposal

https://github.com/golang/go/issues/66984

- Remove int and uint as allowed types in params, results, pointers, or struct fields
- Only allow small integers in pointers, arrays, or struct fields
- enforce structs.HostLayout usage per wasm types proposal
https://github.com/golang/go/issues/66984
- require go1.23 for structs.HostLayout
- use an interface to check if GoVersion() exists
This permits TinyGo to compile with Go 1.21.
- use goenv.Compare instead of WantGoVersion
- testdata/wasmexport: use int32 instead of int
- compiler/testdata: add structs.HostLayout
- compiler/testdata: improve tests for structs.HostLayout
2024-10-22 18:05:04 +02:00
Damian Gryski 951e50c06f compiler: mark stringFromRunes as nocapture/readonly 2024-10-19 11:02:54 +01:00
Damian Gryski 40c9c66c1d compiler: mark stringFromBytes as nocapture/readonly to help escape analysis
Fixes #4525
2024-10-19 11:02:54 +01:00
Ayke d1b7238a36 Truly ignore //export when //go:wasmexport is used (#4500) 2024-10-05 18:53:38 +02:00
Randy Reddig 453a1d35c3 compiler, runtime: enable go:wasmexport for wasip2 (#4499)
* compiler: prefer go:wasmexport over go:export

* runtime, targets/wasip2: enable -buildmode=c-shared for wasip2

* runtime: rename import from wasi_run to wasiclirun (PR feedback)
2024-10-04 17:36:47 -07:00
Ayke 9da8b5c786 wasm: add //go:wasmexport support (#4451)
This adds support for the `//go:wasmexport` pragma as proposed here:
https://github.com/golang/go/issues/65199

It is currently implemented only for wasip1 and wasm-unknown, but it is
certainly possible to extend it to other targets like GOOS=js and
wasip2.
2024-10-04 15:33:47 -07:00
Ayke van Laethem 37460ad60a compiler: support pragmas on generic functions 2024-09-23 09:41:44 +01:00
Ayke van Laethem d4cb92f27c compiler: fix passing weirdly-padded structs to new goroutines
The values were stored in the passed object as the values itself (not
expanded like is common in the calling convention), and read back after
assuming they were expanded. This often works for simple parameters
(int, pointer, etc), but not for more complex parameters. Especially
when there's padding.

Found this while working on `//go:wasmexport`.
2024-09-05 10:53:33 +02:00
Ayke van Laethem ee5bc65c97 compiler: move some code around to make the next bugfix easier
This just makes the next fix easier to read.
2024-09-05 10:53:33 +02:00