Compare commits

...

191 Commits

Author SHA1 Message Date
Ayke van Laethem 63e3c3ec24 all: initial support for LLVM 21 2025-09-23 12:45:42 +02:00
Daniel Esteban 109e0767e7 Added Gopher ARCADE board 2025-09-20 08:35:34 +02:00
Ben Krieger 821f2aeae0 Fix linker errors for runtime.vgetrandom and crypto/internal/sysrand.fatal 2025-09-19 15:32:01 +02:00
Piotr Bocheński 93a11e266f net: update submodule to latest commits
Signed-off-by: Piotr Bocheński <piotr@bochen.ski>
2025-09-19 13:14:12 +02:00
rdon e29e583919 fix: use int64 in ReadTemperature to avoid overflow 2025-09-19 11:30:50 +02:00
Michael Smith 310df7acb5 fix(rp2): reset spinlocks at startup 2025-09-19 02:22:36 -04:00
Michael Smith b9387febe0 fix(rp2): use side-effect-free spinlocks 2025-09-19 02:22:36 -04:00
Michael Smith 3dce224183 fix(rp2): switch spinlock busy loop to wfe 2025-09-19 02:22:36 -04:00
Michael Smith 5d8afa25b8 fix(rp2): disable DBGPAUSE on startup 2025-09-19 02:22:36 -04:00
deadprogram 0dca016749 fix: remove macOS 15 from CI build matrix. It was already being tested by
the test-macos-homebrew job, and it conflicts with the actual build
that we want, which is macOS 14 for backwards-compatibility.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-09-19 01:01:58 -04:00
deadprogram 28a911bcce fix: point the submodule for musl-lib to a mirror in the TinyGo
GitHub org. The git server for git.musl-libc.org is having troubles,
and it also seems like a safer bet to have our own mirror just in case.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-09-19 01:01:58 -04:00
deadprogram eb36120c6e ci: several improvements to the macOS GH actions build including:
- do not install cmake, instead use the version already installed
- add macOS 15 to the CI builds
- update a could of GH actions to latest release
- update Go version being use to Go 1.25.1

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-09-18 08:24:29 -04: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
Matt Mets 2c99692019 Move the directory list into a variable 2025-09-14 08:03:25 -04:00
Matt Mets 0ca0aad7ce Fix for #4678: top-level 'make lint' wasn't working
The revive command seems to have had a syntax error in the file
input glob. It appears to have been broken in a way that did not
result in a return code being set. This change uses 'find' to
build the input to the linter.

Note that it is expected to fail the CI script, because it is
uncovering some existing lint issues that were not being caught.
2025-09-14 08:03:25 -04:00
Michael Smith 3ddba4e620 fix: add TryLock to sync.RWMutex 2025-09-13 11:04:07 -04:00
luoliwoshang eab3dceb48 fix/typo:makeESPFirmwareImage 2025-09-12 14:04:22 -04:00
Michael Smith 663a94fcab feat: enable //go:linkname pragma for globals 2025-09-12 12:53:34 -04:00
Michael Smith 373ca88f14 fix: expand RTT debugger compatibility 2025-09-12 12:53:34 -04:00
Ayke van Laethem be33de1086 GNUmakefile: shrink TinyGo binaries on Linux
With these flags, the TinyGo binary gets 18.8MB (11.6%) smaller. That
seems like a quite useful win for such a small change!

This is only for Linux for now. MacOS and Windows can be tested later,
the flags for those probably need to be modified.

Originally inspired by:
https://discourse.llvm.org/t/state-of-the-art-for-reducing-executable-size-with-heavily-optimized-program/87952/18
There are some other flags like -Wl,--pack-dyn-relocs=relr that did not
shrink binary size in my testing, so I've left them out.

This also switches the linker to prefer mold or lld over the default
linker, since the system linker is usually ld.bfd which is very slow.
(Also, for some reason mold produces smaller binaries than lld).
2025-09-12 05:29:08 -04:00
deadprogram e5bdfb0962 fix: increase the timeout for chromedp to connect to the headless browser used for running
the wasm tests.

Also add favicon link to avoid extra fetches during test runs.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-09-11 08:34:38 -04:00
deadprogram e80c6c48a1 chore: create separate go.mod file for testing dependencies for wasm tests
that use Chromium headless browser to avoid use of older incompatible version.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-09-11 08:34:38 -04:00
Thomas Kohler 381644a0c0 machine,nrf528: stop the bus only once on I2C bus error and ensures the first error is returned
In some cases, e.g nothing connected on the bus, repeated resume-stop sequences can lead to the bus never reaching the stop state, hanging Tx.
This change ensures the resume-stop sequence is submitted once on error. It also moves the error code read to before the sequence to ensure it's valid.

Fixes: #4998
2025-09-09 12:49:29 -04:00
luoliwoshang 13bb59c334 ci:uninstall cmake before install 2025-09-09 06:39:26 -04:00
Ayke van Laethem 632e5f9872 rp2040: allow writing to the UART inside interrupts
Writing to the UART takes time and that may not be a good idea inside an
interrupt, but it is essential for debugging sometimes (especially since
USB-CDC typically doesn't work inside an interrupt).

This fixes UART support in interrupts for the RP2040 at least. You can
test it with `-serial=uart` and connecting a USB-UART adapter to the
right pins.
2025-09-03 10:50:10 -04:00
sago35 37531930b8 chore: update version for 0.40 development cycle 2025-09-02 07:14:45 -04:00
deadprogram 3869f76887 all: prepare for release 0.39.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-08-19 14:03:57 +02:00
deadprogram 3e76703ff5 targets: set default stanck size to 8k for rp2040/rp2350 based boards where this was not already the case.
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-08-18 12:23:51 +02:00
deadprogram deb48dd5f0 fix: update version of clang to 17 to accomodate latest Go 1.25 docker base image
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-08-14 15:01:07 +02:00
deadprogram 73fa5cd7bc fix: disable test-newest since CircleCI seems unable to download due to rate-limits on Dockerhub
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-08-14 11:30:27 +02:00
deadprogram 1be7582106 chore: update all CI builds to test Go 1.25 release
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-08-14 11:30:27 +02:00
deadprogram d5b7cdbca3 net: update to latest tinygo net package
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-08-12 18:34:27 +02:00
Michael Smith c769262398 feat: add metro-rp2350 board definition (#4989)
* feat: add metro-rp2350 board definition
* chore: add smoke test
2025-08-10 09:32:16 +02:00
Michael Smith 64caab1ade feat: enable multi-core scheduler for rp2350 2025-08-08 13:09:38 +02:00
Elias Naur 78914382c3 runtime: ensure time.Sleep(d) sleeps at least d
Account for the sleep queue base time in the computation of the wakeup
time.

Tested with the following program on pico2.

  func main() {
  	go func() {
  		for i := range 60 {
  			const delay = 20 * time.Millisecond
  			before := time.Now()
  			time.Sleep(delay)
  			if d := time.Since(before); true || d < delay {
  				log.Println(i, "actual", d, "delay", delay)
  			}
  		}
  	}()
  	time.Sleep(500 * time.Millisecond)
  	log.Println("******** done sleeping ********")
  	select {}
  }

Without this change, the program would print lines such as:

  17 actual 15.494ms delay 20ms
  18 actual 15.49ms delay 20ms
  19 actual 15.585ms delay 20ms
  20 actual 15.493ms delay 20ms
  21 actual 15.494ms delay 20ms
  22 actual 15.487ms delay 20ms
  23 actual 15.498ms delay 20ms
  ******** done sleeping ********
  24 actual 15.548ms delay 20ms
  25 actual 20.011ms delay 20ms
  26 actual 20.01ms delay 20ms
  27 actual 20.011ms delay 20ms
  28 actual 20.015ms delay 20ms

Note that while more than one sleeping goroutine is in the timer queue,
the sleep duration is 5ms short.
2025-08-08 01:32:42 +02:00
あーるどん 15e37ff927 flash: add -o flag support to save built binary (Fixes #4937) (#4942)
* Add -o flag support to flash command. Fixes #4937
* Remove empty outpath check in validateOutputFormat
---------
Co-authored-by: rdon <you@example.com>
2025-08-07 23:38:15 +02:00
deadprogram 91234060be chore: update all CI builds to test Go 1.25rc3
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-08-07 12:31:23 +02:00
Ayke van Laethem b33b6ce293 all: add Go 1.25 support 2025-08-06 17:08:26 +02:00
Ayke van Laethem 8911abbc6d runtime: stub out weak pointer support 2025-08-06 17:08:26 +02:00
Ayke van Laethem bc77922d47 testing: stub out testing.B.Loop
This gets the path package tests to pass, so we can move ahead with Go
1.25. It should be implemented in the future at some point (that, or
we'll use the upstream testing package instead).
2025-08-06 17:08:26 +02:00
Ayke van Laethem 34efc3a381 compiler: implement internal/abi.Escape 2025-08-06 17:08:26 +02:00
Ayke van Laethem 5c46efb4d1 runtime: implement dummy AddCleanup 2025-08-06 17:08:26 +02:00
Ayke van Laethem d6343d9d5c sync: implement sync.Swap 2025-08-06 17:08:26 +02:00
Ayke van Laethem e368551919 reflect: implement Method.IsExported 2025-08-06 17:08:26 +02:00
Ayke van Laethem 8b4624a420 ci: rename some jobs to avoid churn on every Go/LLVM version bump 2025-08-06 17:08:26 +02:00
Ayke van Laethem 9fd1b7b1a8 ci: make the goroutines test less racy
Since we switched to OS threads for goroutines, the
testdata/goroutines.go test has been flaky. Not surprising, if threads
need to be scheduled within 1ms on a busy CI system. This PR makes the
test a bit less flaky (hopefully) by increasing the time to 100ms.
2025-08-06 16:13:04 +02:00
Ayke van Laethem a38829c692 internal/task: use -stack-size flag when starting a new thread
Found this bug while trying to use the upstream testing package instead
of our own. The io/fs package wasn't passing, because the test was run
in a separate goroutine (and therefore a separate thread, with its own
stack) instead of all in the same thread with our own stack
creation/switching implementation.
2025-08-05 20:32:59 +02:00
Ayke van Laethem 1dbc6c83c4 internal/task: add SA_RESTART flag to GC interrupts
This makes sure system calls like read don't return EINTR but instead
restart the call on an interrupt. This is by far the more sensible
option, the default POSIX behavior of returning EINTR is extremely
error-prone.

Found this bug while trying to use the upstream testing package instead
of our own.
2025-08-05 14:09:03 +02:00
Ayke van Laethem 9a6071920f main: show the compiler erro (if any) for tinygo test -c
This fixes the bug that if there was a compiler error, it was silently
ignored.
2025-08-05 07:33:26 +02:00
Dmitrii Sharshakov 0964176b4d chore: correct GOOS=js name in error messages for WASM 2025-08-03 11:47:57 +02:00
Elliott Sales de Andrade 1ffa9a4adf Makefile: Install missing dlmalloc files
Running tests against an installed TinyGoRoot fails with:
```
=== CONT  TestBuild/WebAssembly/gc.go-boehm
    main_test.go:441: wasi-libc: did not find any files for pattern builder.filePattern{glob:"dlmalloc/src/dlmalloc.c", exclude:[]string(nil)}
```
because these files are not there, and are required with Boehm GC.
2025-07-31 12:26:56 +02:00
Damian Gryski 8c5886060f internal/gclayout: make gclayout values constants
The previous versions calculated at init() prevented `interp` from running
in many cases, increasing compile times due to the increased need to revert
the partially interpreted results and also increasing binary runtime because
fewer optimizations had happened during interp.
2025-07-22 18:57:55 +02:00
Elliott Sales de Andrade 3bb092d4d4 Add flag to skip Renesas SVD builds
Much like the STMicro SVDs, Renesas SVDs are fully proprietary and not
under an FOSS license.
2025-07-20 12:15:38 +02:00
Ayke van Laethem 20e62dea6f stm32: add support for the STM32L031G6U6 2025-07-17 16:35:05 +02:00
Elias Naur 1b5d312c68 tests: de-flake goroutines test 2025-07-17 15:40:01 +02:00
diwamoto 435ddc5f2d machine: add international keys 2025-07-16 17:30:54 +02:00
张之阳 1de1f87c6b Docs: Clarify build verification step for macOS users 2025-07-12 09:23:08 +02:00
Ayke van Laethem 778164c98e machine: remove some unnecessary "// peripherals:" comments
These things are specified in the shared chip Go file, not in the board
pin aliases.
2025-07-11 10:28:38 +02:00
Ayke van Laethem b3da00ac1f machine: add I2C pin comments
Similar to PWM, I2C can only be used on some pins. To automatically
generate this information per board, we need to add extra comments that
can then be interpreted by doc-gen for the tinygo.org website.
2025-07-11 10:28:38 +02:00
Ayke van Laethem e454ad1b61 machine: standardize I2C errors with "i2c:" prefix
This probably looks better anyway.
2025-07-11 09:25:48 +02:00
Ayke van Laethem f845b469b1 machine: make I2C usable in the simulator
This fixes/improves a few issues with I2C support:

  * Validate I2C pins, so only pins that are supported by the hardware
    can be used (similar to how it's done with PWM).
  * Add address to Tx API (without it, the simulator can't really
    simulate I2C).
  * Add frequency when configuring. Not currently used, but might be
    useful in the future and adding it now avoids possibly breaking
    changes.

This is a breaking change, but since the simulator doesn't support I2C
yet that seems fine to me. (It does in my local changes, but those need
to be cleaned up before I can push them).
2025-07-11 09:25:48 +02:00
deadprogram 35adbffa54 fix: additional params to create chromium browser for testing
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-07-10 11:47:37 +02:00
emricks 01f3d3eb59 fix: add SPI and I2C to teensy 4.1 (#4943)
* fix: add SPI and I2C to teensy 4.1
* fix: add SPI3 variables back
* fix: formatting

Signed-off-by: Emrick Sorensen <emrickishere@gmail.com>
2025-07-04 08:46:48 +02:00
Ayke van Laethem 0e43146d32 darwin: add threading support and use it by default 2025-06-30 09:07:54 +02:00
Ayke van Laethem 93f40992c1 internal/task: a few small correctness fixes
This shouldn't affect Linux or MacOS, but it's good to have them fixed.
2025-06-30 09:07:54 +02:00
Elias Naur c6b47fe6a0 rp2: use the correct channel mask for rp2350 ADC; hold lock during read (#4938) 2025-06-29 15:20:58 -03:00
Elias Naur 536deaa00a rp2: disable digital input for analog inputs
This is what the Pico SDK does[0] and may fix #4936.

[0] https://github.com/raspberrypi/pico-sdk/blob/ee68c78d0afae2b69c03ae1a72bf5cc267a2d94c/src/rp2_common/hardware_adc/include/hardware/adc.h#L101
2025-06-28 09:34:06 +02:00
deadprogram df1d639deb chore: update version for 0.39 development cycle
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-06-21 19:13:13 +02:00
deadprogram 733a17d470 all: prepare for release 0.38.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-06-14 07:51:48 +02:00
micchie 330f8c7c50 Use diskutil on macOS to extract volume name and path for FAT mounts (#4928)
* Use diskutil on macOS to extract volume name and path for FAT mounts
* Improve FAT mount detection on macOS by parsing diskutil output into a map
* Simplify conditional check
2025-06-14 06:27:38 +02:00
Ayke van Laethem e238eb2242 rp2040: add multicore support 2025-06-13 16:19:10 +02:00
Ayke van Laethem 5625f68d51 runtime: don't lock the print output inside interrupts
This should avoid a deadlock when trying to print inside an interrupt,
if the interrupted code is also printing (and therefore has the print
lock taken).
2025-06-13 16:19:10 +02:00
Ayke van Laethem f7d8502572 runtime: don't try to interrupt other cores before they are started
The GC shouldn't try to interrupt other cores before they are started.
For example, it would be possible for the GC to run in a package
initializer (which is currently run on a single core). That would
suggest questionable program design, but it is something that should
work. So this commit makes sure the GC only tries to scan the stack of
other cores when those other cores have in fact started.
2025-06-13 16:19:10 +02:00
Ayke van Laethem e395c94e5f runtime: implement NumCPU for the multicore scheduler
I forgot to add it in the first PR, here:
https://github.com/tinygo-org/tinygo/pull/4851
2025-06-13 16:19:10 +02:00
Ayke van Laethem c08b2dfe06 wasm: add Boehm GC support
This adds support for `-gc=boehm` on `-target=wasip1` and `-target=wasm`
(in a browser or NodeJS). Notably it does *not* add Boehm GC support for
`-target=wasip2`, since that target doesn't have a real libc.
2025-06-13 14:42:23 +02:00
Ayke van Laethem 9c3b706533 main: add "cores" and "threads" schedulers to help text
This was missing before.
2025-06-13 11:33:05 +02:00
Ayke van Laethem 60f8a62978 all: add support for multicore scheduler
This commit adds support for a scheduler that runs a scheduler on all
available cores. It is meant to be used on baremetal systems with a
fixed number of cores, such as the RP2040.

The initial implementation adds support for multicore scheduling to the
riscv-qemu target as a convenient testing target. This means that this
new multicore scheduler is tested in CI, including a bunch of standard
library tests (`make tinygo-test-baremetal`). This should ensure the new
scheduler is reasonably well tested before trying to use it on
harder-to-debug targets like the RP2040.
2025-06-12 21:04:36 +02:00
Ayke van Laethem 0c7c2926f9 runtime: refactor obtaining the system stack
The system stack is only needed when we're not on it. So we can directly
call task.SystemStack() without problems.

This also saves a tiny bit of binary size.
2025-06-12 21:04:36 +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 525c41bac9 sync: fix TestMutexConcurrent test
Accessing the same variable from multiple goroutines is unsafe, and will
fail with parallelism. A lightweight way to avoid issues is by using
atomic variables.
2025-06-12 21:04:36 +02:00
Piotr Bocheński 83de8ff77d net: update submodule to latest commits
And fix module definition pointing to `dev` branch by default.

Signed-off-by: Piotr Bocheński <piotr@bochen.ski>
2025-06-12 14:02:44 +02:00
Ayke van Laethem 170a069132 riscv32: use gdb binary as a fallback
At least on my system (Fedora 42) the standard gdb binary is capable of
debugging riscv-qemu binaries (running inside qemu-system-riscv32).
2025-06-11 14:29:20 +02:00
Ömer Faruk IRMAK f19b288717 runtime/debug: add GC related stubs 2025-06-11 09:57:46 +02:00
Ömer Faruk IRMAK 7c54dbc61f metrics: flesh out some of the metric types 2025-06-11 09:57:46 +02:00
Ömer Faruk IRMAK 1976d9e3fe reflect: Chan related stubs 2025-06-11 09:57:46 +02:00
Michael Smith 87153e9a02 usb: add USB mass storage class support 2025-06-11 07:46:02 +02:00
Michael Smith ba274008d5 machine: implement usb receive message throttling 2025-06-11 07:46:02 +02:00
Michael Smith b059de857c machine: declare usb endpoints per-platform 2025-06-11 07:46:02 +02:00
deadprogram 1880e82da6 build: go back to using MinoruSekine/setup-scoop for Windows CI builds
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-06-10 19:08:00 +02:00
Ella Fox 888d957f60 machine: Add board support for BigTreeTech SKR Pico (#4842)
* machine: add support for BTT SKR Pico
Adds support for the BigTreeTech SKR Pico 3D-printer mainboard.
This board uses the RP2040.
* Fix build tag
* Add I2C defaults
* Run UART test instead of blinky1
* Use NoPin for I2C and SPI on BTT SKR Pico
* Cleanup comments
* Don't use ADC pin names
2025-06-01 18:15:57 +02:00
Mateusz Nowak f69c579005 machine/samd21: implement watchdog 2025-05-25 10:01:43 +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
Elias Naur 3f4f4e0ead flake.*: upgrade to nixpkgs 25.05, LLVM 20
Add a work around for #4819.
2025-05-24 13:56:01 +02:00
Mateusz Nowak 5c35bad590 machine/samd51: write to flash memory in 512 byte long chunks 2025-05-24 11:45:29 +02:00
Rolf Sommerhalder c1bff3dad0 Fix DMA to SPI transmits on RP2350 (#4903)
* Fix DMA to SPI transfers on RP2350

DMA DREQ line numbers for "flow control" between SPI bus and DMA channels on RP2350 differ from RP2040.
Tested with st7789 driver for Pico-1.14-LCD from Waveshare on Pico 2W. Without this fix func st7789.tx() blocks indefinitely while attempting to use DMA to SPI transfers.

* Add definitions for DMA DREQ "handshake" lines

Specific for RP2350, missing in generated src/device/rp/rp2350.go

* Add definitions for DMA DREQ "handshake" lines

Specific for RP2040, missing in generated src/device/rp/rp2040.go

* Complete table

* Complete table

* Remove redundant DMA_ prefix

* Correct name of Datasheet

* Correct name of Datasheet

* Refactor

Move global definitions to device/rp/

* Refactor

* Refactor

* Refacture

* Refacture

* Fix comments

* go fmt

* rename new non-generated files
2025-05-24 10:16:58 +02:00
Mateusz Nowak 3eeffca841 machine/samd21: write to flash memory in 64 byte long chunks 2025-05-23 11:29:53 +02:00
Ayke van Laethem cb5f7ad3fd interp: fix copy() from/to external buffers
This includes copying from a //go:embed slice for example. The slice
with data is not available at interp time.

See: https://github.com/tinygo-org/tinygo/issues/4895
2025-05-22 14:46:41 +02:00
Elias Naur 704489ed6d runtime: update comment
I forgot to change the comment in PR #4890.
2025-05-22 09:29:50 +02:00
Ayke van Laethem 9ca6f72583 wasm: refactor/modify stub signal handling
This commit changes signal handling in a few ways:

  * It stubs signals for all wasm targets (not just wasi) and baremetal,
    since none of those have traditional POSIX signals. And moves the
    code for that into a single file, instead of duplicating it.
  * It removes the stub for signal_ignored since the value `false` might
    be wrong in some cases and it doesn't usually seem to be called (it
    is not called in tsgo). Should be trivial to re-add if it is shown
    to be needed.
  * It adds a stub for `os/signal.signalWaitUntilIdle` which _is_ called
    by tsgo.
2025-05-21 20:04:05 +02:00
Ayke van Laethem 584098dfda machine: don't inline RTT WriteByte everywhere
With `-opt=2`, WriteByte gets inlined everywhere a println statement
exists. This blows up binary size for very little gain. In my case, the
binary size roughly doubled. Instead, don't inline it so that the binary
size remains somewhat reasonable. This might slow down WriteByte a tiny
bit, but likely not by any significant amount.
2025-05-21 16:49:21 +02:00
Elias Naur 180662f038 runtime: avoid an allocation in (*time.Timer).Reset 2025-05-16 12:36:14 +02:00
Elias Naur 2da9d26e21 machine/rp2: unexport machine-specific errors
Errors are part of API, and the exported rp2 errors seemed arbitrary.
For example, the very particular ErrRP2040I2CDisable was exported, but
errI2CWriteTimeout (which is defined on all platforms) is not.

While here, remove "RP2040" from an error name and make the messages
consistent and idiomatic.
2025-05-12 12:11:01 +02:00
Elias Naur d840971c42 machine: [rp2] discount scheduling delays in I2C timeouts (#4876)
The `gosched` call introduce arbitrary long delays in general, and in
TinyGo particular because the goroutine scheduler is cooperative and
doesn't preempt busy (e.g. compute-heavy) goroutines.

Before this change, the timeout logic would read, simplified:

  deadline := now() + timeout
  startTX()
	for !txDone() {
	   if now() > deadline { return timeoutError }
		 gosched() // (1)
	}
  startRx() // (2)
	for !rxDone() {
	   // (3)
	   if now() > deadline { return timeoutError }
		 gosched()
	}

What could happen in a busy system is:

- The gosched marked (1) would push now() to be > than deadline.
- startRx is called (2), but the call to rxDone immediately after would
report it not yet done.
- The check marked (3) would fail, even though only a miniscule amount
of time has passed between startRx and the check.

This change ensures that the timeout clock discounts time spent in
`gosched`. The logic now reads, around every call to `gosched`:

  deadline := now() + timeout
  startTX()
	for !txDone() {
	   if now() > deadline { return timeoutError }
		 before := now()
		 gosched()
		 deadline += now() - before
	}

I tested this change by simulating a busy goroutine:

	go func() {
		for {
      // Busy.
			before := time.Now()
			for time.Since(before) < 100*time.Millisecond {
			}
      // Sleep.
			time.Sleep(100 * time.Millisecond)
		}
	}()

and testing that I2C transfers would no longer time out.
2025-05-06 21:42:16 -03:00
Damian Gryski ba3b3e8938 runtime: stub runtime signal functions for os/signal on wasip1 2025-05-06 13:20:30 +02:00
Elias Naur c4ef38fbf9 go.*: upgrade golang.org/x/tools to v0.30.0, Go to 1.22
Fixes #4884 by upgrading the ssa package.

The fix is in v0.26.0, which also bumps the minimum Go to 1.22. The
latest x/tools module still depending on 1.22 is v0.30.0.
2025-05-06 10:05:20 +02:00
Ayke van Laethem edaf877056 machine: use pointer receiver in simulated PWM peripherals
I only discovered this issue after a while. All the baremetal PWM
implementations use pointers to a PWM instance, instead of the PWM
instance itself. For consistency (and because it's a better idea in
general), the simulated PWMs need to work the same.
2025-05-01 15:08:08 +02:00
Damian Gryski 45743406d0 os: handle relative and abs paths in Executable() 2025-05-01 10:53:49 +02:00
Damian Gryski 5428bfd270 runtime,os: add os.Executable() for Darwin 2025-05-01 10:53:49 +02:00
Ayke van Laethem 72b19555dc machine: add simulated PWM/timer peripherals
I will soon use these as part of the TinyGo tour, to explain the PWM
peripherals on common chips.
2025-04-30 19:44:34 +02:00
Ayke van Laethem 612a38e363 wasm: don't block //go:wasmexport because of running goroutines
This fixes bug https://github.com/tinygo-org/tinygo/issues/4874.
2025-04-29 14:19:17 +02:00
deadprogram 0c2ab895b7 targets: add target for Microbit v2 with SoftDevice S140 support for both peripheral and central
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-04-26 15:39:50 +00:00
deadprogram 8d5b7710cf fix: use OpenOCD flash method on microbit v2 when using Nordic Semi SoftDevice
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-04-26 15:39:39 +00:00
Ayke van Laethem de532643b1 main: add StartPos and EndPos to -json build output
This is useful for the TinyGo Playground: with this change it can show
the error span like in an IDE, instead of just the (single) error
position. Errors become a bit more readable as a result.
2025-04-24 09:24:52 +02:00
Ayke van Laethem c2765e9eca main: change -json flag to match upstream Go
This changes the -json flag for build/run/flash/gdb etc commands to not
print `compileopts.Config` but instead match upstream Go and print build
errors in a structured way.

For more details, see the proposal:
https://github.com/golang/go/issues/62067
2025-04-23 12:39:23 +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
Ayke van Laethem 922ba6a4a3 all: add support for LLVM 20
This adds support for the 'go install' case, where we link against the
system LLVM (Homebrew, Linux distro version, etc). This does not have an
effect on `make`, which still uses LLVM 19 for now.

The main reason for doing this is because newer distros like Fedora 42
and Homebrew have switched to LLVM 20, so switching to this newer
version helps those people. (I'm one of those people, I'm on Fedora 42).

There are two small changes for WebAssembly included:

  * nontrapping-fptoint was enabled in the wasmbuiltin library used for
    wasm-unknown. This matches wasm-unknown which already had this
    enabled, so it doesn't add any new instructions.
  * bulk-memory was enabled in wasi-libc. This was previously enabled in
    all the other WebAssembly targets (wasm, wasip1, wasip2) so this
    does't add any new instructions. I think it was also enabled in the
    wasi-libc build before
    https://github.com/tinygo-org/tinygo/pull/4820 but I don't know for
    sure.
2025-04-22 16:31:19 +02:00
Michael Smith febb3906db machine/rp2: expose usb endpoint stall handling 2025-04-17 10:15:44 +02:00
Elias Naur 0f06f59c6e device/arm: clear pending interrupts before enabling them
Without this change, a pending interrupt would spuriously trigger
immediately after enabling. This happens if an interrupt is triggered
during flashing (e.g. by DMA), which survives the subsequent reset.

This behaviour matches e.g. `machine.irqSet` in machine_rp2_rp2350.go.

See 7f970a45, whose symptoms were likely caused by spurious interrupts.
2025-04-16 09:43:23 +02:00
Damian Gryski 0fdf08d14f add -nobounds (similar to -gcflags=-B) 2025-04-15 12:55:44 +02:00
Michael Smith 133e32c1c4 machine/rp2: merge common usb code (#4856)
* machine/rp2: merge common usb code
* chore: add note on noinline reason
2025-04-15 11:07:47 +02:00
Ayke van Laethem 41e501aaf4 runtime: move timeUnit to a single place
The timeUnit is now the same type everywhere. Move it to a single place
and add some documentation to it.
2025-04-15 09:23:23 +02:00
Ayke van Laethem abc373dc73 wasm: use int64 instead of float64 for the timeUnit
This makes wasm consistent with all the other targets, where timeUnit is
already int64.
2025-04-15 09:23:23 +02:00
Ayke van Laethem 02c5c4213c runtime: implement NumCPU for -scheduler=threads
For the threads scheduler, it makes sense to have NumCPU available.
For all other schedulers, the number of available CPUs is practically
limited to one by the scheduler (even though the system might have more
CPUs).
2025-04-13 14:59:19 +02:00
Ayke van Laethem 25b83920b6 ci: try to fix race condition in testdata/goroutines.go
A race condition was possible because the 'acquire' goroutine might not
have started in 4 milliseconds which changed the ordering of the test.

This patch fixes it by making sure the goroutine has started (and locked
the mutex) before continuing with the test.
2025-04-12 18:35:56 +02:00
Ayke van Laethem 3f8a110e4a runtime: move mainExited boolean
This variable is only necessary on the cooperative and none scheduler.
It is not used on the threads scheduler.

The reason for moving is that the upcoming multicore baremetal scheduler
also needs mainExited but of a different type: an atomic variable
instead of a plain boolean.
2025-04-12 13:34:57 +02:00
Ayke van Laethem 95ee572b4d internal/task: rename tinygo_pause to tinygo_task_exit
This is more descriptive: the call is to exit a task, not to pause it.
This also makes it more obvious that there's an optimization
opportunity: to free the stack explicitly after the goroutine returns
(or to keep it as a cache for the next stack allocation).
2025-04-12 13:34:57 +02:00
Ayke van Laethem 120d17c124 runtime: map every goroutine to a new OS thread
This is not a scheduler in the runtime, instead every goroutine is
mapped to a single OS thread - meaning 1:1 scheduling.

While this may not perform well (or at all) for large numbers of
threads, it greatly simplifies many things in the runtime. For example,
blocking syscalls can be called directly instead of having to use epoll
or similar. Also, we don't need to do anything special to call C code -
the default stack is all we need.
2025-04-11 15:18:41 +02:00
Ayke van Laethem 193f91b870 sync: implement RWMutex using futexes
Somewhat surprisingly, this results in smaller code than the old code
with the cooperative (tasks) scheduler. Probably because the new RWMutex
is also simpler.
2025-04-11 15:18:41 +02:00
Ayke van Laethem f9ed15f857 runtime: refactor timerQueue
Move common functions to scheduler.go. They will be used both from the
cooperative and from the threads scheduler.
2025-04-11 15:18:41 +02:00
Ayke van Laethem 870f00222d runtime: make conservative and precise GC MT-safe
Using a global lock may be slow, but it is certainly simple and safe.
If this global lock becomes a bottleneck, we can of course look into
making the GC truly support multithreading.
2025-04-11 15:18:41 +02:00
Ayke van Laethem 5b243f652c internal/task: implement atomic primitives for preemptive scheduling 2025-04-11 15:18:41 +02:00
Ayke van Laethem 789b5c6b78 compileopts: add library version to cached library path
This may be a bit of a weird place to put the library path, but
otherwise it's difficult to get the pathname for the Config.CFlags
function. So I've put it here.

This should help to avoid stale library caches. The idea is to increment
it every time something changes to a library that means it needs to be
recompiled. It's a manual process.
2025-04-10 11:59:46 +02:00
Ayke van Laethem dcf609defb riscv-qemu: actually sleep in time.Sleep()
Instead of just incrementing the timestamp, this causes the system to
actually sleep when calling time.Sleep. The direct effect is that this
works as expected:

    $ tinygo run -target=riscv-qemu examples/serial
    hello world!
    hello world!
    hello world!
    [..etc]

This commit also adds a bare bones handler for exceptions (such as
invalid memory writes), since we're adding an interrupt handler anyway.

While this patch doesn't add that much functionality, having interrupt
support is going to be needed for multicore support on riscv-qemu. My
plan is to first add this support to riscv-qemu (based on the earlier
work I did for the RP2040 and demoed at FOSDEM 2025) and once the basics
are in place and fully tested we can extend this support to the RP2040.
Writing for QEMU first makes it much easier to debug any issues that
will come up.
2025-04-05 08:57:26 +02:00
Ayke van Laethem 4bce85dc09 riscv: define CSR constants and use them where possible 2025-04-05 08:57:26 +02:00
Caleb Champlin 8a73502f11 reflect: Add SliceOf, ArrayOf, StructOf, MapOf, FuncOf 2025-04-04 15:23:07 +02:00
Ayke van Laethem 632357ffb9 builder: build wasi-libc inside TinyGo
Instead of relying on a build when TinyGo is being built, do it like all
other libraries when it is needed.

This brings a few benefits:

  * No more running `make wasi-libc` on the command line as a special
    case for WebAssembly. The generic `git submodule update --init` step
    is now enough for wasi-libc.
  * It becomes much easier to customize the build per system. For
    example: include/exclude malloc as needed, disable/enable bulk
    memory operations per target, etc.
2025-04-04 13:14:04 +02:00
Ayke van Laethem 4c54aa20da builder: simplify bdwgc libc dependency
Header files are built immediately, not in a separate job, so no
dependency is needed here. All we need is a flag whether to add flags
for that given libc.
2025-04-04 13:14:04 +02:00
Ayke van Laethem 8486e07377 builder: don't use precompiled libraries
We used these libraries in the past, but stopped doing so a while ago.
This is a small cleanup to remove support for these entirely.
2025-04-04 13:14:04 +02:00
deadprogram 91e20a53e0 fix: display all of the current GC options for the -gc flag
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-04-01 13:54:37 +02:00
Ayke van Laethem 9e42c8459e Makefile: only detect ccache command when needed 2025-04-01 10:10:11 +02:00
Ayke van Laethem 627743432a Makefile: create random filename inside rule
Don't create the temporary name in advance (which needs a subprocess
call), only do that when needed inside the report-stdlib-tests-pass
rule.
2025-04-01 10:10:11 +02:00
Ayke van Laethem 5d92d4dc98 Makefile: don't set GOROOT
This *should* not be needed. Using the right `go` binary should do the
job. It might break if users have explicitly set GOROOT (in which case
they probably need to fix that).

This avoids a subprocess call inside `make`.
2025-04-01 10:10:11 +02:00
Ayke van Laethem 682b3a9523 Makefile: call uname at most once
Instead of calling it 5 times, call it only once on Unix-like systems
(Linux, MacOS) and avoid it entirely on Windows.

The main benefit of this is that it avoids a ton of overhead doing
subprocess calls, which are very slow on Windows (~0.2s on my system).
2025-04-01 10:10:11 +02:00
Ayke van Laethem fdf075a7f9 Makefile: only read NodeJS version when it is needed
Most make commands don't need to check for the NodeJS version, so only
do it when needed.

This avoids the following error on Windows for example when NodeJS is
not installed:

    /usr/bin/sh: line 1: node: command not found
    which: no node in (/c/Users/Ayke/bin:/clangarm64/bin:/usr/local/bin:/usr/bin:/usr/bin:/mingw64/bin:/usr/bin:/c/Users/Ayke/bin:/c/Users/Ayke/.vscode-server/cli/servers/Stable-e54c774e0add60467559eb0d1e229c6452cf8447/server/bin/remote-cli:/c/WINDOWS/system32:/c/WINDOWS:/c/WINDOWS/System32/Wbem:/c/WINDOWS/System32/WindowsPowerShell/v1.0:/c/WINDOWS/System32/OpenSSH:/cmd:/c/Users/Ayke/scoop/apps/mingw-mstorsjo-llvm-ucrt/current/bin:/c/Users/Ayke/scoop/apps/python/current/Scripts:/c/Users/Ayke/scoop/apps/python/current:/c/Users/Ayke/go/bin:/c/Users/Ayke/scoop/shims:/c/Users/Ayke/AppData/Local/Microsoft/WindowsApps:/usr/bin/vendor_perl:/usr/bin/core_perl)

Also, some users have been confused by the error message even though in
most cases it is harmless and can be ignored.
2025-03-25 18:58:08 +01:00
Ayke van Laethem 95a7d065ca darwin: support Boehm GC (and use by default)
This mostly required some updates to macos-minimal-sdk to add the needed
header files and symbols.
2025-03-25 12:33:13 +01:00
deadprogram c1c074f170 version: update to 0.38.0-dev
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-03-24 09:25:32 +01:00
Ayke van Laethem 429c01556b cgo: *actually* fix build warnings on Windows ARM
See: https://github.com/tinygo-org/tinygo/pull/4628

This removes the comment, which actually fixes the issue. #4628 was
incorrect.
2025-03-23 08:13:57 +01:00
Ayke van Laethem ee76822fe6 arm64: remove unnecessary .section directive
This directive caused the code to be put in a non-executable area on
Windows which caused a segmentation fault. This patch fixes the issue by
removing `.section` directives, fixing windows/arm64 support.
2025-03-23 07:23:24 +01:00
Ayke van Laethem b9bf0aa0da windows: add support for the Boehm-Demers-Weiser GC
A few small changes were needed to make this work. In particular, I
found a critical bug (see the previous commit) that needed to be fixed
to make this work on Windows.
2025-03-22 19:40:56 +01:00
Ayke van Laethem fd3976b5bb windows: fix wrong register for first parameter
I'm surprised this worked as long as it did, since it looks like the
goroutine stack did not get scanned. Or maybe the RCX register contained
the stack pointer by accident. In any case, it now uses the correct
register (RCX instead of RDI on Windows) for passing the stack pointer
as the first parameter.
2025-03-22 19:40:56 +01:00
Ayke van Laethem 48f145c4df compileopts: enable support for GOARCH=wasm in tinygo test
Support for GOARCH=wasm was only available for `tinygo build`, not for
any of the other subcommands (`test`, `run`, etc). With this PR, these
subcommands should work again for supported values of GOOS.

This fixes the following error for example:

    $ make tinygo-test-wasip1
    GOOS=wasip1 GOARCH=wasm /home/ayke/bin/tinygo test cmp compress/lzw compress/zlib [...etc]
    cannot resolve packages: GOARCH=wasm but GOOS is unset. Please set GOOS to wasm, wasip1, or wasip2.
    make: *** [GNUmakefile:489: tinygo-test-wasip1] Error 1
2025-03-22 08:54:30 +01:00
Carlos Henrique Guardão Gandarez 5a34c64fbe Remove duplicated error handling 2025-03-20 07:04:42 -07:00
deadprogram 3e60eeb368 Prepare for release 0.37.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-03-19 07:32:48 +01:00
Randy Reddig e5a8d69300 internal/wasm-tools: update to go.bytecodealliance.org@v0.6.2 2025-03-18 15:40:46 +01:00
Randy Reddig 4f8672c9ab internal/cm: change error type from struct{string}
This is a temporary fix until cm@v0.2.2 is released, and package internal/cm and internal/wasi can be regenerated.

See #4810 for more information.
2025-03-18 15:40:46 +01:00
Randy Reddig a7416e7300 internal/wasi: remove x bit from generated files 2025-03-18 15:40:46 +01:00
Randy Reddig d63d8e0899 internal/wasm-tools, internal/cm: udpate to go.bytecodealliance.org@v0.6.1 and cm@v0.2.1 2025-03-18 15:40:46 +01:00
Randy Reddig 8e009de8a8 internal/cm: remove go.mod file 2025-03-18 15:40:46 +01:00
Randy Reddig d6527ece02 internal/cm: exclude certain files when copying package 2025-03-18 15:40:46 +01:00
Randy Reddig 211425c3e9 internal/wasi: regenerate WASI 0.2 bindings
Use go.bytecodealliance.org/cmd/wit-bindgen-go@v0.6.0
2025-03-18 15:40:46 +01:00
Randy Reddig 429aea8e74 internal/cm: update to go.bytecodealliance.org/cm@v0.2.0 2025-03-18 15:40:46 +01:00
Randy Reddig 7755780a49 GNUmakefile, internal/wasm-tools: update to go.bytecodealliance.org@v0.6.0 2025-03-18 15:40:46 +01:00
Ayke van Laethem 3a7c25f987 all: add the Boehm-Demers-Weiser GC on Linux
This adds support for the well-known Boehm GC. It's significantly faster
than our own naive GC and could be used as an alternative on bigger
systems.

In the future, this GC might also be supported on WebAssembly with some
extra work. Right now it's Linux only (though Windows/MacOS shouldn't be
too difficult to add).
2025-03-18 10:31:38 +01:00
Ayke van Laethem a4cbe3326e runtime: only allocate heap memory when needed
For example, with -gc=none and -gc=leaking, no heap needs to be
allocated when initializing the runtime. And some GCs (like -gc=custom)
are responsible for allocating the heap themselves.
2025-03-18 10:31:38 +01: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
Randy Reddig 6a25fd494e reflect, internal/reflectlite: add Value.SetIter{Key,Value} and MapIter.Reset
Fixes #4790. Depends on #4787 (merge that first).
2025-03-17 20:44:20 +01:00
Randy Reddig d95c1b5982 reflect: remove unused go:linkname functions 2025-03-17 18:23:28 +01:00
Randy Reddig 24eed9e376 reflect: remove strconv.go 2025-03-17 18:23:28 +01:00
Randy Reddig c2af1d183e reflect: panic on Type.CanSeq[2] instead of returning false
PR feedback.
2025-03-17 18:23:28 +01:00
Randy Reddig 64651115c2 reflect: Value.Seq iteration value types should match
Implementation of https://github.com/golang/go/issues/71905

194696f1d1f6e5609f96d0fb0192595e7e0f5b90
2025-03-17 18:23:28 +01:00
Randy Reddig b6c3d142db reflect: copy reflect iter tests from upstream Go 2025-03-17 18:23:28 +01:00
Randy Reddig fafe80704f loader, iter, reflect: use build tags for package iter and iter methods on reflect.Value 2025-03-17 18:23:28 +01:00
Randy Reddig a2be2f3330 loader, iter: add shim for go1.22 and earlier 2025-03-17 18:23:28 +01:00
Randy Reddig 05fc49a0cf internal/reflectlite: remove old reflect.go 2025-03-17 18:23:28 +01:00
Randy Reddig 417aa4312e internal/reflectlite, reflect: move StringHeader and SliceHeader back to package reflect 2025-03-17 18:23:28 +01:00
Randy Reddig bf88cdea90 transform: cherry-pick from #4774 2025-03-17 18:23:28 +01:00
Randy Reddig c8d0b87a67 internal/reflectlite, reflect: handle different StructField 2025-03-17 18:23:28 +01:00
Randy Reddig 99a618385b runtime: use package reflectlite 2025-03-17 18:23:28 +01:00
Randy Reddig 9e143efd73 reflect: add Go 1.24 iter.Seq[2] methods 2025-03-17 18:23:28 +01:00
Randy Reddig d5c70a1cd3 reflect, internal/reflectlite: embed reflectlite types into reflect types 2025-03-17 18:23:28 +01:00
Ayke van Laethem bbb2b0c95b builder: use a separate module for command-line set strings
Strings that are set via the command line (as in -ldflags="-X ...") are
now created in a separate module to avoid type renaming issues. LLVM
sometimes renames types or merges types that are structurally the same,
and putting these strings in a separate module avoids this issue (and
lets llvm.LinkModules deal with the difference).

This fixes https://github.com/tinygo-org/tinygo/issues/4810.
2025-03-17 07:13:32 -07:00
Michael Smith 4768c7d431 machine/rp2350: add flash support for rp2350 (#4803)
* machine/rp2350: add flash support for rp2350
* combine duplicate files
* clean things up and group by source file
* add stubbed out xip cache clean func if needed in the future
* update flash_enable_xip_via_boot2
* remove unused macros and fix inconsistent formatting
* make flash size configurable like rp2040
* add missing flash size configs
* retain big Go CGo compatibility per #4103
* clarify CS0_SIZE source and remove single-use typedef
2025-03-16 09:45:53 +01:00
あーるどん 4f7c64cb24 fix(rp2040): replace loop counter with hw timer for USB SetAddressReq… (#4796)
* fix(rp2040/rp2350): replace loop counter with hw timer for USB SetAddressRequest timeout.

* fix code format.

---------

Co-authored-by: rdon <you@example.com>
2025-03-13 16:39:43 +01:00
Ayke van Laethem ff2a79de7c riscv-qemu: increase stack size
Bumping the stack size to 8kb (previous was 4kb) gets most remaining
tests to pass on baremetal.
2025-03-13 06:43:39 -07:00
soypat 04c7057ea6 add goroutine benchmark to examples 2025-03-11 13:10:41 -07:00
Ron Evans f76e8d2812 fix: ensure use of pointers for SPI interface on atsam21/atsam51 and other machines/boards that were missing implementation. (#4798)
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-03-11 12:50:31 -03:00
deadprogram bcdc5e0097 chore: update version to 0.37.0-dev
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-03-11 07:24:17 -07:00
deadprogram 2bee29959b refactor: use *SPI everywhere to make consistant for implementations.
Fixes #4663 "in reverse" by making SPI a pointer everywhere, as discussed
in the comments.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-03-11 06:06:31 -07:00
417 changed files with 14606 additions and 8071 deletions
+12 -20
View File
@@ -73,14 +73,6 @@ commands:
- go-cache-v4-{{ checksum "go.mod" }}
- llvm-source-linux
- run: go install -tags=llvm<<parameters.llvm>> .
- restore_cache:
keys:
- wasi-libc-sysroot-systemclang-v7
- run: make wasi-libc
- save_cache:
key: wasi-libc-sysroot-systemclang-v7
paths:
- lib/wasi-libc/sysroot
- when:
condition: <<parameters.fmt-check>>
steps:
@@ -100,28 +92,28 @@ commands:
- /go/pkg/mod
jobs:
test-llvm15-go119:
test-oldest:
# This tests our lowest supported versions of Go and LLVM, to make sure at
# least the smoke tests still pass.
docker:
- image: golang:1.19-bullseye
- image: golang:1.22-bullseye
steps:
- test-linux:
llvm: "15"
# "make lint" fails before go 1.21 because internal/tools/go.mod specifies packages that require go 1.21
fmt-check: false
resource_class: large
test-llvm19-go124:
test-newest:
# This tests the latest supported LLVM version when linking against system
# libraries.
docker:
- image: golang:1.24-bullseye
- image: golang:1.25-bullseye
steps:
- test-linux:
llvm: "19"
llvm: "21"
resource_class: large
workflows:
test-all:
jobs:
# This tests our lowest supported versions of Go and LLVM, to make sure at
# least the smoke tests still pass.
- test-llvm15-go119
# This tests LLVM 19 support when linking against system libraries.
- test-llvm19-go124
- test-oldest
# disable this test, since CircleCI seems unable to download due to rate-limits on Dockerhub.
# - test-newest
+13 -22
View File
@@ -30,22 +30,22 @@ jobs:
run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
submodules: true
- name: Extract TinyGo version
id: version
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
- name: Install Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: '1.24'
go-version: '1.25.1'
cache: true
- name: Restore LLVM source cache
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-19-${{ matrix.os }}-v1
key: llvm-source-20-${{ matrix.os }}-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -70,7 +70,7 @@ jobs:
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-19-${{ matrix.os }}-v1
key: llvm-build-20-${{ matrix.os }}-v2
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -79,7 +79,7 @@ jobs:
rm -rf llvm-project
make llvm-source
# install dependencies
HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake ninja
HOMEBREW_NO_AUTO_UPDATE=1 brew install ninja
# build!
make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
@@ -89,19 +89,10 @@ jobs:
with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build
- name: Cache wasi-libc sysroot
uses: actions/cache@v4
id: cache-wasi-libc
with:
key: wasi-libc-sysroot-${{ matrix.os }}-v1
path: lib/wasi-libc/sysroot
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
- name: make gen-device
run: make -j3 gen-device
- name: Test TinyGo
run: make test GOTESTFLAGS="-short"
run: make test GOTESTFLAGS="-only-current-os"
- name: Build TinyGo release tarball
run: make release -j3
- name: Test stdlib packages
@@ -126,7 +117,7 @@ jobs:
runs-on: macos-latest
strategy:
matrix:
version: [16, 17, 18, 19]
version: [16, 17, 18, 19, 20, 21]
steps:
- name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@master
@@ -139,19 +130,19 @@ jobs:
run: |
brew install llvm@${{ matrix.version }}
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Install Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: '1.24'
go-version: '1.25.1'
cache: true
- name: Build TinyGo (LLVM ${{ matrix.version }})
run: go install -tags=llvm${{ matrix.version }}
- name: Check binary
run: tinygo version
- name: Build TinyGo (default LLVM)
if: matrix.version == 19
if: matrix.version == 21
run: go install
- name: Check binary
if: matrix.version == 19
if: matrix.version == 21
run: tinygo version
+11 -29
View File
@@ -18,7 +18,7 @@ jobs:
# statically linked binary.
runs-on: ubuntu-latest
container:
image: golang:1.24-alpine
image: golang:1.25-alpine
outputs:
version: ${{ steps.version.outputs.version }}
steps:
@@ -26,7 +26,7 @@ jobs:
# tar: needed for actions/cache@v4
# git+openssh: needed for checkout (I think?)
# ruby: needed to install fpm
run: apk add tar git openssh make g++ ruby-dev
run: apk add tar git openssh make g++ ruby-dev mold
- name: Work around CVE-2022-24765
# We're not on a multi-user machine, so this is safe.
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
@@ -48,7 +48,7 @@ jobs:
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-19-linux-alpine-v1
key: llvm-source-20-linux-alpine-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -73,7 +73,7 @@ jobs:
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-19-linux-alpine-v1
key: llvm-build-20-linux-alpine-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -104,15 +104,6 @@ jobs:
run: |
apk add cmake samurai python3
make binaryen STATIC=1
- name: Cache wasi-libc
uses: actions/cache@v4
id: cache-wasi-libc
with:
key: wasi-libc-sysroot-linux-alpine-v2
path: lib/wasi-libc/sysroot
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
- name: Install fpm
run: |
gem install --version 4.0.7 public_suffix
@@ -146,7 +137,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
go-version: '1.25.0'
cache: true
- name: Install wasmtime
uses: bytecodealliance/actions/wasmtime/setup@v1
@@ -190,7 +181,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
go-version: '1.25.0'
cache: true
- name: Install Node.js
uses: actions/setup-node@v4
@@ -206,7 +197,7 @@ jobs:
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-19-linux-asserts-v1
key: llvm-source-20-linux-asserts-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -231,7 +222,7 @@ jobs:
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-19-linux-asserts-v1
key: llvm-build-20-linux-asserts-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -258,15 +249,6 @@ jobs:
- name: Build Binaryen
if: steps.cache-binaryen.outputs.cache-hit != 'true'
run: make binaryen
- name: Cache wasi-libc
uses: actions/cache@v4
id: cache-wasi-libc
with:
key: wasi-libc-sysroot-linux-asserts-v6
path: lib/wasi-libc/sysroot
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
- run: make gen-device -j4
- name: Test TinyGo
run: make ASSERT=1 test
@@ -316,13 +298,13 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
go-version: '1.25.0'
cache: true
- name: Restore LLVM source cache
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-19-linux-v1
key: llvm-source-20-linux-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -347,7 +329,7 @@ jobs:
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-19-linux-${{ matrix.goarch }}-v3
key: llvm-build-20-linux-${{ matrix.goarch }}-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
+2 -2
View File
@@ -35,8 +35,8 @@ jobs:
uses: docker/metadata-action@v5
with:
images: |
tinygo/llvm-19
ghcr.io/${{ github.repository_owner }}/llvm-19
tinygo/llvm-20
ghcr.io/${{ github.repository_owner }}/llvm-20
tags: |
type=sha,format=long
type=raw,value=latest
+3 -3
View File
@@ -22,14 +22,14 @@ jobs:
run: sudo apt-get remove llvm-18
- name: Checkout
uses: actions/checkout@v4
- name: Pull musl
- name: Pull musl, bdwgc
run: |
git submodule update --init lib/musl
git submodule update --init lib/musl lib/bdwgc
- name: Restore LLVM source cache
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-19-linux-nix-v1
key: llvm-source-20-linux-nix-v1
path: |
llvm-project/compiler-rt
- name: Download LLVM source
+5 -5
View File
@@ -2,11 +2,11 @@
# still works after checking out the dev branch (that is, when going from LLVM
# 16 to LLVM 17 for example, both Clang 16 and Clang 17 are installed).
echo 'deb https://apt.llvm.org/noble/ llvm-toolchain-noble-19 main' | sudo tee /etc/apt/sources.list.d/llvm.list
echo 'deb https://apt.llvm.org/noble/ llvm-toolchain-noble-21 main' | sudo tee /etc/apt/sources.list.d/llvm.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install --no-install-recommends -y \
llvm-19-dev \
clang-19 \
libclang-19-dev \
lld-19
llvm-21-dev \
clang-21 \
libclang-21-dev \
lld-21
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
uses: actions/cache@v4
id: cache-llvm-source
with:
key: llvm-source-19-sizediff-v1
key: llvm-source-20-sizediff-v1
path: |
llvm-project/compiler-rt
- name: Download LLVM source
+10 -19
View File
@@ -23,7 +23,7 @@ jobs:
minimum-size: 8GB
maximum-size: 24GB
disk-root: "C:"
- uses: brechtm/setup-scoop@v2
- uses: MinoruSekine/setup-scoop@v4
with:
scoop_update: 'false'
- name: Install Dependencies
@@ -41,13 +41,13 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
go-version: '1.25.0'
cache: true
- name: Restore cached LLVM source
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-19-windows-v1
key: llvm-source-20-windows-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -72,7 +72,7 @@ jobs:
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-19-windows-v1
key: llvm-build-20-windows-v2
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -91,15 +91,6 @@ jobs:
with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build
- name: Cache wasi-libc sysroot
uses: actions/cache@v4
id: cache-wasi-libc
with:
key: wasi-libc-sysroot-v5
path: lib/wasi-libc/sysroot
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
- name: Cache Go cache
uses: actions/cache@v4
with:
@@ -114,7 +105,7 @@ jobs:
run: make -j3 gen-device
- name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-short"
run: make test GOTESTFLAGS="-only-current-os"
- name: Build TinyGo release tarball
shell: bash
run: make build/release -j4
@@ -144,7 +135,7 @@ jobs:
minimum-size: 8GB
maximum-size: 24GB
disk-root: "C:"
- uses: brechtm/setup-scoop@v2
- uses: MinoruSekine/setup-scoop@v4
with:
scoop_update: 'false'
- name: Install Dependencies
@@ -156,7 +147,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
go-version: '1.25.0'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v4
@@ -186,7 +177,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
go-version: '1.25.0'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v4
@@ -210,7 +201,7 @@ jobs:
minimum-size: 8GB
maximum-size: 24GB
disk-root: "C:"
- uses: brechtm/setup-scoop@v2
- uses: MinoruSekine/setup-scoop@v4
with:
scoop_update: 'false'
- name: Install Dependencies
@@ -222,7 +213,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
go-version: '1.25.0'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v4
+4 -2
View File
@@ -22,7 +22,7 @@
url = https://github.com/tinygo-org/stm32-svd
[submodule "lib/musl"]
path = lib/musl
url = git://git.musl-libc.org/musl
url = https://github.com/tinygo-org/musl-libc.git
[submodule "lib/binaryen"]
path = lib/binaryen
url = https://github.com/WebAssembly/binaryen.git
@@ -35,7 +35,9 @@
[submodule "src/net"]
path = src/net
url = https://github.com/tinygo-org/net.git
branch = dev
[submodule "lib/wasi-cli"]
path = lib/wasi-cli
url = https://github.com/WebAssembly/wasi-cli
[submodule "lib/bdwgc"]
path = lib/bdwgc
url = https://github.com/ivmai/bdwgc.git
+8 -2
View File
@@ -85,11 +85,17 @@ Try running TinyGo:
./build/tinygo help
Also, make sure the `tinygo` binary really is statically linked. Check this
using `ldd` (not to be confused with `lld`):
Also, make sure the `tinygo` binary really is statically linked. The command to check for
dynamic dependencies differs depending on your operating system.
On Linux, use `ldd` (not to be confused with `lld`):
ldd ./build/tinygo
On macOS, use otool -L:
otool -L ./build/tinygo
The result should not contain libclang or libLLVM.
## Make a release tarball
+200
View File
@@ -1,3 +1,203 @@
0.39.0
---
* **general**
- all: add Go 1.25 support
- net: update to latest tinygo net package
- docs: clarify build verification step for macOS users
- Add flag to skip Renesas SVD builds
* **build**
- Makefile: install missing dlmalloc files
- flash: add -o flag support to save built binary (Fixes #4937) (#4942)
- fix: update version of clang to 17 to accommodate latest Go 1.25 docker base image
* **ci**
- chore: update all CI builds to test Go 1.25 release
- fix: disable test-newest since CircleCI seems unable to download due to rate-limits on Dockerhub
- ci: rename some jobs to avoid churn on every Go/LLVM version bump
- ci: make the goroutines test less racy
- tests: de-flake goroutines test
* **compiler**
- compiler: implement internal/abi.Escape
* **main**
- main: show the compiler error (if any) for `tinygo test -c`
- chore: correct GOOS=js name in error messages for WASM
* **machine**
- machine: add international keys
- machine: remove some unnecessary "// peripherals:" comments
- machine: add I2C pin comments
- machine: standardize I2C errors with "i2c:" prefix
- machine: make I2C usable in the simulator
- fix: add SPI and I2C to teensy 4.1 (#4943)
- `rp2`: use the correct channel mask for rp2350 ADC; hold lock during read (#4938)
- `rp2`: disable digital input for analog inputs
* **runtime**
- runtime: ensure time.Sleep(d) sleeps at least d
- runtime: stub out weak pointer support
- runtime: implement dummy AddCleanup
- runtime: enable multi-core scheduler for rp2350
- `internal/task`: use -stack-size flag when starting a new thread
- `internal/task`: add SA_RESTART flag to GC interrupts
- `internal/task`: a few small correctness fixes
- `internal/gclayout`: make gclayout values constants
- darwin: add threading support and use it by default
* **standard library**
- `sync`: implement sync.Swap
- `reflect`: implement Method.IsExported
* **testing**
- testing: stub out testing.B.Loop
* **targets**
- `stm32`: add support for the STM32L031G6U6
- add metro-rp2350 board definition (#4989)
- `rp2040/rp2350`: set the default stack size to 8k for rp2040/rp2350 based boards where this was not already the case
0.38.0
---
* **general**
- `go.*`: upgrade `golang.org/x/tools` to v0.30.0
- `all`: add support for LLVM 20
* **build**
- go back to using MinoruSekine/setup-scoop for Windows CI builds
- `flake.*`: upgrade to nixpkgs 25.05, LLVM 20
- `Makefile`: only detect ccache command when needed
- `Makefile`: create random filename inside rule
- `Makefile`: don't set GOROOT
- `Makefile`: call uname at most once
- `Makefile`: only read NodeJS version when it is needed
* **compiler**
- add support for `GODEBUG=gotypesalias=1`
- `interp`: fix `copy()` from/to external buffers
- add `-nobounds` (similar to `-gcflags=-B`)
- `compileopts`: add library version to cached library path
- `builder`: build wasi-libc inside TinyGo
- `builder`: simplify bdwgc libc dependency
- `builder`: don't use precompiled libraries
- `compileopts`: enable support for `GOARCH=wasm` in `tinygo test`
* **fixes**
- `rp2350`: Fix DMA to SPI transmits on RP2350 (#4903)
- `microbit v2`: use OpenOCD flash method on microbit v2 when using Nordic Semi SoftDevice
- `main`: display all of the current GC options for the `-gc` flag
- Remove duplicated error handling
- `sync`: fix `TestMutexConcurrent` test
- fix race condition in `testdata/goroutines.go`
- fix build warnings on Windows ARM
* **machine**
- `usb`: add USB mass storage class support
- implement usb receive message throttling
- declare usb endpoints per-platform
- `samd21`: implement watchdog
- `samd51`: write to flash memory in 512 byte long chunks
- `samd21`: write to flash memory in 64 byte long chunks
- don't inline RTT `WriteByte` everywhere
- `rp2`: unexport machine-specific errors
- `rp2`: discount scheduling delays in I2C timeouts (#4876)
- use pointer receiver in simulated PWM peripherals
- add simulated PWM/timer peripherals
- `rp2`: expose usb endpoint stall handling
- `arm`: clear pending interrupts before enabling them
- `rp2`: merge common usb code (#4856)
* **main**
- add "cores" and "threads" schedulers to help text
- add `StartPos` and `EndPos` to `-json` build output
- change `-json` flag to match upstream Go
* **runtime**
- don't lock the print output inside interrupts
- don't try to interrupt other cores before they are started
- implement `NumCPU` for the multicore scheduler
- add support for multicore scheduler
- refactor obtaining the system stack
- `interrupt`: add `Checkpoint` type
- add `exportedFuncPtr`
- avoid an allocation in `(*time.Timer).Reset`
- stub runtime signal functions for `os/signal` on wasip1
- move `timeUnit` to a single place
- implement `NumCPU` for `-scheduler=threads`
- move `mainExited` boolean
- `internal/task`: rename `tinygo_pause` to `tinygo_task_exit`
- map every goroutine to a new OS thread
- refactor `timerQueue`
- make conservative and precise GC MT-safe
- `internal/task`: implement atomic primitives for preemptive scheduling
- Use diskutil on macOS to extract volume name and path for FAT mounts #4928
* **standard library**
- `net`: update submodule to latest commits
- `runtime/debug`: add GC related stubs
- `metrics`: flesh out some of the metric types
- `reflect`: Chan related stubs
- `os`: handle relative and abs paths in `Executable()`
- `os`: add `os.Executable()` for Darwin
- `sync`: implement `RWMutex` using futexes
- `reflect`: Add `SliceOf`, `ArrayOf`, `StructOf`, `MapOf`, `FuncOf`
* **targets**
- `rp2040`: add multicore support
- `riscv32`: use `gdb` binary as a fallback
- add target for Microbit v2 with SoftDevice S140 support for both peripheral and central
- `windows`: use MSVCRT.DLL instead of UCRT on i386
- `windows`: add windows/386 support
- `arm64`: remove unnecessary `.section` directive
- `riscv-qemu`: actually sleep in `time.Sleep()`
- `riscv`: define CSR constants and use them where possible
- `darwin`: support Boehm GC (and use by default)
- `windows`: add support for the Boehm-Demers-Weiser GC
- `windows`: fix wrong register for first parameter
* **wasm**
- add Boehm GC support
- refactor/modify stub signal handling
- don't block `//go:wasmexport` because of running goroutines
- use `int64` instead of `float64` for the `timeUnit`
* **boards**
- Add board support for BigTreeTech SKR Pico (#4842)
0.37.0
---
* **general**
- add the Boehm-Demers-Weiser GC on Linux
* **ci**
- add more tests for wasm and baremetal
* **compiler**
- crypto/internal/sysrand is allowed to use unsafe signatures
* **examples**
- add goroutine benchmark to examples
* **fixes**
- ensure use of pointers for SPI interface on atsam21/atsam51 and other machines/boards that were missing implementation (#4798)
- replace loop counter with hw timer for USB SetAddressReq on rp2040 (#4796)
* **internal**
- update to go.bytecodealliance.org@v0.6.2 in GNUmakefile and internal/wasm-tools
- exclude certain files when copying package in internal/cm
- update to go.bytecodealliance.org/cm@v0.2.2 in internal/cm
- remove old reflect.go in internal/reflectlite
* **loader**
- use build tags for package iter and iter methods on reflect.Value in loader, iter, reflect
- add shim for go1.22 and earlier in loader, iter
* **machine**
- bump rp2040 to 200MHz (#4768)
- correct register address for Pin.SetInterrupt for rp2350 (#4782)
- don't block the rp2xxx UART interrupt handler
- fix RP2040 Pico board on the playground
- add flash support for rp2350 (#4803)
* **os**
- add stub Symlink for wasm
* **refactor**
- use *SPI everywhere to make consistent for implementations. Fixes #4663 "in reverse" by making SPI a pointer everywhere, as discussed in the comments.
* **reflect**
- add Value.SetIter{Key,Value} and MapIter.Reset in reflect, internal/reflectlite
- embed reflectlite types into reflect types in reflect, internal/reflectlite
- add Go 1.24 iter.Seq[2] methods
- copy reflect iter tests from upstream Go
- panic on Type.CanSeq[2] instead of returning false
- remove strconv.go
- remove unused go:linkname functions
* **riscv-qemu**
- add VirtIO RNG device
- increase stack size
* **runtime**
- only allocate heap memory when needed
- remove unused file func.go
- use package reflectlite
* **transform**
- cherry-pick from #4774
0.36.0
---
* **general**
+3 -3
View File
@@ -1,8 +1,8 @@
# tinygo-llvm stage obtains the llvm source for TinyGo
FROM golang:1.24 AS tinygo-llvm
FROM golang:1.25 AS tinygo-llvm
RUN apt-get update && \
apt-get install -y apt-utils make cmake clang-15 ninja-build && \
apt-get install -y apt-utils make cmake clang-17 ninja-build && \
rm -rf \
/var/lib/apt/lists/* \
/var/log/* \
@@ -33,7 +33,7 @@ RUN cd /tinygo/ && \
# tinygo-compiler copies the compiler build over to a base Go container (without
# all the build tools etc).
FROM golang:1.24 AS tinygo-compiler
FROM golang:1.25 AS tinygo-compiler
# Copy tinygo build.
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
+132 -60
View File
@@ -8,13 +8,20 @@ LLVM_PROJECTDIR ?= llvm-project
CLANG_SRC ?= $(LLVM_PROJECTDIR)/clang
LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
ifeq ($(OS),Windows_NT)
# avoid calling uname on Windows
uname := Windows_NT
else
uname := $(shell uname -s)
endif
# Try to autodetect LLVM build tools.
# Versions are listed here in descending priority order.
LLVM_VERSIONS = 19 18 17 16 15
errifempty = $(if $(1),$(1),$(error $(2)))
detect = $(shell which $(call errifempty,$(firstword $(foreach p,$(2),$(shell command -v $(p) 2> /dev/null && echo $(p)))),failed to locate $(1) at any of: $(2)))
toolSearchPathsVersion = $(1)-$(2)
ifeq ($(shell uname -s),Darwin)
ifeq ($(uname),Darwin)
# Also explicitly search Brew's copy, which is not in PATH by default.
BREW_PREFIX := $(shell brew --prefix)
toolSearchPathsVersion += $(BREW_PREFIX)/opt/llvm@$(2)/bin/$(1)-$(2) $(BREW_PREFIX)/opt/llvm@$(2)/bin/$(1)
@@ -27,7 +34,6 @@ LLVM_NM ?= $(call findLLVMTool,llvm-nm)
# Go binary and GOROOT to select
GO ?= go
export GOROOT = $(shell $(GO) env GOROOT)
# Flags to pass to go test.
GOTESTFLAGS ?=
@@ -38,14 +44,10 @@ TINYGO ?= $(call detect,tinygo,tinygo $(CURDIR)/build/tinygo)
# Check for ccache if the user hasn't set it to on or off.
ifeq (, $(CCACHE))
# Use CCACHE for LLVM if possible
ifneq (, $(shell command -v ccache 2> /dev/null))
CCACHE := ON
else
CCACHE := OFF
endif
LLVM_OPTION += '-DLLVM_CCACHE_BUILD=$(if $(shell command -v ccache 2> /dev/null),ON,OFF)'
else
LLVM_OPTION += '-DLLVM_CCACHE_BUILD=$(CCACHE)'
endif
LLVM_OPTION += '-DLLVM_CCACHE_BUILD=$(CCACHE)'
# Allow enabling LLVM assertions
ifeq (1, $(ASSERT))
@@ -77,6 +79,26 @@ ifeq (1, $(STATIC))
BINARYEN_OPTION += -DCMAKE_CXX_FLAGS="-static" -DCMAKE_C_FLAGS="-static"
endif
# Optimize the binary size for Linux.
# These flags may work on other platforms, but have only been tested on Linux.
ifeq ($(uname),Linux)
HAS_MOLD := $(shell command -v ld.mold 2> /dev/null)
HAS_LLD := $(shell command -v ld.lld 2> /dev/null)
LLVM_CFLAGS := -ffunction-sections -fdata-sections -fvisibility=hidden
LLVM_LDFLAGS := -Wl,--gc-sections
ifneq ($(HAS_MOLD),)
# Mold might be slightly faster.
LLVM_LDFLAGS += -fuse-ld=mold -Wl,--icf=all
else ifneq ($(HAS_LLD),)
# LLD is more commonly available.
LLVM_LDFLAGS += -fuse-ld=lld -Wl,--icf=all
endif
LLVM_OPTION += \
-DCMAKE_C_FLAGS="$(LLVM_CFLAGS)" \
-DCMAKE_CXX_FLAGS="$(LLVM_CFLAGS)"
CGO_LDFLAGS += $(LLVM_LDFLAGS)
endif
# Cross compiling support.
ifneq ($(CROSS),)
CC = $(CROSS)-gcc
@@ -127,14 +149,14 @@ ifeq ($(OS),Windows_NT)
USE_SYSTEM_BINARYEN ?= 1
else ifeq ($(shell uname -s),Darwin)
else ifeq ($(uname),Darwin)
MD5SUM ?= md5
CGO_LDFLAGS += -lxar
USE_SYSTEM_BINARYEN ?= 1
else ifeq ($(shell uname -s),FreeBSD)
else ifeq ($(uname),FreeBSD)
MD5SUM ?= md5
START_GROUP = -Wl,--start-group
END_GROUP = -Wl,--end-group
@@ -185,7 +207,10 @@ fmt-check: ## Warn if any source needs reformatting
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-kendryte gen-device-nxp gen-device-rp gen-device-renesas ## Generate microcontroller-specific sources
gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-kendryte gen-device-nxp gen-device-rp ## Generate microcontroller-specific sources
ifneq ($(RENESAS), 0)
gen-device: gen-device-renesas
endif
ifneq ($(STM32), 0)
gen-device: gen-device-stm32
endif
@@ -238,7 +263,7 @@ gen-device-renesas: build/gen-device-svd
GO111MODULE=off $(GO) fmt ./src/device/renesas
$(LLVM_PROJECTDIR)/llvm:
git clone -b xtensa_release_19.1.2 --depth=1 https://github.com/espressif/llvm-project $(LLVM_PROJECTDIR)
git clone -b tinygo_20.x --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
llvm-source: $(LLVM_PROJECTDIR)/llvm ## Get LLVM sources
# Configure LLVM.
@@ -259,40 +284,34 @@ build/wasm-opt$(EXE):
cp lib/binaryen/bin/wasm-opt$(EXE) build/wasm-opt$(EXE)
endif
# Build wasi-libc sysroot
.PHONY: wasi-libc
wasi-libc: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a
lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
cd lib/wasi-libc && $(MAKE) -j4 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC="$(CLANG)" AR=$(LLVM_AR) NM=$(LLVM_NM)
# Generate WASI syscall bindings
WASM_TOOLS_MODULE=github.com/bytecodealliance/wasm-tools-go
WASM_TOOLS_MODULE=go.bytecodealliance.org
.PHONY: wasi-syscall
wasi-syscall: wasi-cm
rm -rf ./src/internal/wasi/*
go run -modfile ./internal/wasm-tools/go.mod $(WASM_TOOLS_MODULE)/cmd/wit-bindgen-go generate --versioned -o ./src/internal -p internal --cm internal/cm ./lib/wasi-cli/wit
# Copy package cm into src/internal/cm
.PHONY: wasi-cm
wasi-cm:
# rm -rf ./src/internal/cm
rsync -rv --delete --exclude '*_test.go' $(shell go list -modfile ./internal/wasm-tools/go.mod -m -f {{.Dir}} $(WASM_TOOLS_MODULE))/cm ./src/internal/
rm -rf ./src/internal/cm/*
rsync -rv --delete --exclude go.mod --exclude '*_test.go' --exclude '*_json.go' --exclude '*.md' --exclude LICENSE $(shell go list -modfile ./internal/wasm-tools/go.mod -m -f {{.Dir}} $(WASM_TOOLS_MODULE)/cm)/ ./src/internal/cm
# Check for Node.js used during WASM tests.
NODEJS_VERSION := $(word 1,$(subst ., ,$(shell node -v | cut -c 2-)))
MIN_NODEJS_VERSION=18
.PHONY: check-nodejs-version
check-nodejs-version:
ifeq (, $(shell which node))
@echo "Install NodeJS version 18+ to run tests."; exit 1;
endif
@if [ $(NODEJS_VERSION) -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version 18+ to run tests."; exit 1; fi
@# Check whether NodeJS is available.
@if ! command -v node 2>&1 >/dev/null; then echo "Install NodeJS version ${MIN_NODEJS_VERSION}+ to run tests."; exit 1; fi
@# Check whether the version is high enough.
@if [ "`node -v | sed 's/v\([0-9]\+\).*/\\1/g'`" -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version $(MIN_NODEJS_VERSION)+ to run tests."; exit 1; fi
tinygo: ## Build the TinyGo compiler
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " $(MAKE) llvm-source"; echo " $(MAKE) $(LLVM_BUILDDIR)"; exit 1; fi
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" .
test: wasi-libc check-nodejs-version
test: check-nodejs-version
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags "byollvm osusergo" $(GOTESTPKGS)
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
@@ -431,22 +450,15 @@ TEST_PACKAGES_NONWASM = \
# (just like wasm).
# * picolibc math functions apparently are less precise, the math package
# fails on baremetal.
# * Some packages fail or hang for an unknown reason, this should be
# investigated and fixed.
TEST_PACKAGES_BAREMETAL = $(filter-out $(TEST_PACKAGES_NONBAREMETAL), $(TEST_PACKAGES_FAST))
TEST_PACKAGES_NONBAREMETAL = \
$(TEST_PACKAGES_NONWASM) \
crypto/elliptic \
math \
reflect \
encoding/asn1 \
encoding/base32 \
go/ast \
$(nil)
# Report platforms on which each standard library package is known to pass tests
jointmp := $(shell echo /tmp/join.$$$$)
report-stdlib-tests-pass:
$(eval jointmp := $(shell echo /tmp/join.$$$$))
@for t in $(TEST_PACKAGES_DARWIN); do echo "$$t darwin"; done | sort > $(jointmp).darwin
@for t in $(TEST_PACKAGES_LINUX); do echo "$$t linux"; done | sort > $(jointmp).linux
@for t in $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW); do echo "$$t darwin linux wasi windows"; done | sort > $(jointmp).portable
@@ -455,11 +467,11 @@ report-stdlib-tests-pass:
@rm $(jointmp).*
# Standard library packages that pass tests quickly on the current platform
ifeq ($(shell uname),Darwin)
ifeq ($(uname),Darwin)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_DARWIN)
TEST_IOFS := true
endif
ifeq ($(shell uname),Linux)
ifeq ($(uname),Linux)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_LINUX)
TEST_IOFS := true
endif
@@ -468,11 +480,15 @@ TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
TEST_IOFS := false
endif
TEST_SKIP_FLAG := -skip='TestExtraMethods|TestParseAndBytesRoundTrip/P256/Generic'
# Test known-working standard library packages.
# TODO: parallelize, and only show failing tests (no implied -v flag).
.PHONY: tinygo-test
tinygo-test:
$(TINYGO) test $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
@# TestExtraMethods: used by many crypto packages and uses reflect.Type.Method which is not implemented.
@# TestParseAndBytesRoundTrip/P256/Generic: relies on t.Skip() which is not implemented
$(TINYGO) test $(TEST_SKIP_FLAG) $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
@# io/fs requires os.ReadDir, not yet supported on windows or wasi. It also
@# requires a large stack-size. Hence, io/fs is only run conditionally.
@# For more details, see the comments on issue #3143.
@@ -480,7 +496,7 @@ ifeq ($(TEST_IOFS),true)
$(TINYGO) test -stack-size=6MB io/fs
endif
tinygo-test-fast:
$(TINYGO) test $(TEST_PACKAGES_HOST)
$(TINYGO) test $(TEST_SKIP_FLAG) $(TEST_PACKAGES_HOST)
tinygo-bench:
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
tinygo-bench-fast:
@@ -488,18 +504,18 @@ tinygo-bench-fast:
# Same thing, except for wasi rather than the current platform.
tinygo-test-wasm:
$(TINYGO) test -target wasm $(TEST_PACKAGES_WASM)
$(TINYGO) test -target wasm $(TEST_SKIP_FLAG) $(TEST_PACKAGES_WASM)
tinygo-test-wasi:
$(TINYGO) test -target wasip1 $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
$(TINYGO) test -target wasip1 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
tinygo-test-wasip1:
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_SKIP_FLAG) $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
tinygo-test-wasip1-fast:
$(TINYGO) test -target=wasip1 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
$(TINYGO) test -target=wasip1 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
tinygo-test-wasip2-slow:
$(TINYGO) test -target=wasip2 $(TEST_PACKAGES_SLOW)
$(TINYGO) test -target=wasip2 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_SLOW)
tinygo-test-wasip2-fast:
$(TINYGO) test -target=wasip2 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
$(TINYGO) test -target=wasip2 $(TEST_SKIP_FLAG) $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
tinygo-test-wasip2-sum-slow:
TINYGO=$(TINYGO) \
@@ -525,16 +541,16 @@ tinygo-bench-wasip2-fast:
# Run tests on riscv-qemu since that one provides a large amount of memory.
tinygo-test-baremetal:
$(TINYGO) test -target riscv-qemu $(TEST_PACKAGES_BAREMETAL)
$(TINYGO) test -target riscv-qemu $(TEST_SKIP_FLAG) $(TEST_PACKAGES_BAREMETAL)
# Test external packages in a large corpus.
test-corpus:
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml
test-corpus-fast:
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus -short . -corpus=testdata/corpus.yaml
test-corpus-wasi: wasi-libc
test-corpus-wasi:
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml -target=wasip1
test-corpus-wasip2: wasi-libc
test-corpus-wasip2:
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml -target=wasip2
.PHONY: testchdir
@@ -637,8 +653,12 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit-v2-s113v7 examples/microbit-blink
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit-v2-s140v7 examples/microbit-blink
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nrf52840-mdk examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=btt-skr-pico examples/uart
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10031 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=reelboard examples/blinky1
@@ -775,6 +795,8 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=gopher-badge examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=gopher-arcade examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=thumby examples/echo
@@ -785,6 +807,8 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pico-plus2 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=metro-rp2350 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=waveshare-rp2040-tiny examples/echo
@$(MD5SUM) test.hex
# test pwm
@@ -801,6 +825,10 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/usb-midi
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pico examples/usb-storage
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pico2 examples/usb-storage
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nrf52840-s140v6-uf2-generic examples/machinetest
@$(MD5SUM) test.hex
ifneq ($(STM32), 0)
@@ -840,6 +868,8 @@ ifneq ($(STM32), 0)
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=mksnanov3 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32l0x1 examples/serial
@$(MD5SUM) test.hex
endif
$(TINYGO) build -size short -o test.hex -target=atmega328pb examples/blinkm
@$(MD5SUM) test.hex
@@ -910,7 +940,7 @@ endif
$(TINYGO) build -size short -o test.hex -target=hw-651 examples/machinetest
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=hw-651-s110v8 examples/machinetest
@$(MD5SUM) test.hex
@$(MD5SUM) test.hex
ifneq ($(WASM), 0)
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
@@ -943,15 +973,17 @@ endif
wasmtest:
$(GO) test ./tests/wasm
cd ./tests/wasm && $(GO) test .
build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binaryen)
build/release: tinygo gen-device $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binaryen)
@mkdir -p build/release/tinygo/bin
@mkdir -p build/release/tinygo/lib/bdwgc
@mkdir -p build/release/tinygo/lib/clang/include
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
@mkdir -p build/release/tinygo/lib/macos-minimal-sdk
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-crt/crt
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-crt/math
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-crt/stdio
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
@mkdir -p build/release/tinygo/lib/musl/arch
@mkdir -p build/release/tinygo/lib/musl/crt
@@ -959,7 +991,8 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
@mkdir -p build/release/tinygo/lib/nrfx
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libc
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libm
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-bottom-half/headers
@mkdir -p build/release/tinygo/lib/wasi-libc/dlmalloc
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-bottom-half
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@mkdir -p build/release/tinygo/lib/wasi-cli/
@@ -968,6 +1001,7 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
ifneq ($(USE_SYSTEM_BINARYEN),1)
@cp -p build/wasm-opt$(EXE) build/release/tinygo/bin
endif
@cp -rp lib/bdwgc/* build/release/tinygo/lib/bdwgc
@cp -p $(abspath $(CLANG_SRC))/lib/Headers/*.h build/release/tinygo/lib/clang/include
@cp -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/CMSIS
@cp -rp lib/CMSIS/README.md build/release/tinygo/lib/CMSIS
@@ -981,6 +1015,8 @@ endif
@cp -rp lib/musl/crt/crt1.c build/release/tinygo/lib/musl/crt
@cp -rp lib/musl/COPYRIGHT build/release/tinygo/lib/musl
@cp -rp lib/musl/include build/release/tinygo/lib/musl
@cp -rp lib/musl/src/conf build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/ctype build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/env build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/errno build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/exit build/release/tinygo/lib/musl/src
@@ -995,19 +1031,29 @@ endif
@cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/misc build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/multibyte build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/sched build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/signal build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/stdio build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/stdlib build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/string build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/thread build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/time build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/unistd build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/process build/release/tinygo/lib/musl/src
@cp -rp lib/mingw-w64/mingw-w64-crt/crt/pseudo-reloc.c build/release/tinygo/lib/mingw-w64/mingw-w64-crt/crt
@cp -rp lib/mingw-w64/mingw-w64-crt/def-include build/release/tinygo/lib/mingw-w64/mingw-w64-crt
@cp -rp lib/mingw-w64/mingw-w64-crt/gdtoa build/release/tinygo/lib/mingw-w64/mingw-w64-crt
@cp -rp lib/mingw-w64/mingw-w64-crt/include build/release/tinygo/lib/mingw-w64/mingw-w64-crt
@cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/api-ms-win-crt-* build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
@cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/advapi32.def.in build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
@cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/kernel32.def.in build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
@cp -rp lib/mingw-w64/mingw-w64-crt/stdio/ucrt_* build/release/tinygo/lib/mingw-w64/mingw-w64-crt/stdio
@cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/msvcrt.def.in build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
@cp -rp lib/mingw-w64/mingw-w64-crt/math/x86 build/release/tinygo/lib/mingw-w64/mingw-w64-crt/math
@cp -rp lib/mingw-w64/mingw-w64-crt/misc build/release/tinygo/lib/mingw-w64/mingw-w64-crt
@cp -rp lib/mingw-w64/mingw-w64-crt/stdio build/release/tinygo/lib/mingw-w64/mingw-w64-crt
@cp -rp lib/mingw-w64/mingw-w64-headers/crt/ build/release/tinygo/lib/mingw-w64/mingw-w64-headers
@cp -rp lib/mingw-w64/mingw-w64-headers/defaults/include build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
@cp -rp lib/mingw-w64/mingw-w64-headers/include build/release/tinygo/lib/mingw-w64/mingw-w64-headers
@cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx
@cp -rp lib/picolibc/newlib/libc/ctype build/release/tinygo/lib/picolibc/newlib/libc
@cp -rp lib/picolibc/newlib/libc/include build/release/tinygo/lib/picolibc/newlib/libc
@@ -1017,15 +1063,37 @@ endif
@cp -rp lib/picolibc/newlib/libm/common build/release/tinygo/lib/picolibc/newlib/libm
@cp -rp lib/picolibc/newlib/libm/math build/release/tinygo/lib/picolibc/newlib/libm
@cp -rp lib/picolibc-stdio.c build/release/tinygo/lib
@cp -rp lib/wasi-libc/libc-bottom-half/headers/public build/release/tinygo/lib/wasi-libc/libc-bottom-half/headers
@cp -rp lib/wasi-libc/dlmalloc/src build/release/tinygo/lib/wasi-libc/dlmalloc
@cp -rp lib/wasi-libc/libc-bottom-half/cloudlibc build/release/tinygo/lib/wasi-libc/libc-bottom-half
@cp -rp lib/wasi-libc/libc-bottom-half/headers build/release/tinygo/lib/wasi-libc/libc-bottom-half
@cp -rp lib/wasi-libc/libc-bottom-half/sources build/release/tinygo/lib/wasi-libc/libc-bottom-half
@cp -rp lib/wasi-libc/libc-top-half/headers build/release/tinygo/lib/wasi-libc/libc-top-half
@cp -rp lib/wasi-libc/libc-top-half/musl/arch/generic build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
@cp -rp lib/wasi-libc/libc-top-half/musl/arch/wasm32 build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
@cp -rp lib/wasi-libc/libc-top-half/musl/include build/release/tinygo/lib/wasi-libc/libc-top-half/musl
@cp -rp lib/wasi-libc/libc-top-half/musl/src/conf build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/dirent build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/env build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/errno build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/exit build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/fcntl build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/fenv build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/include build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/internal build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/legacy build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/locale build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/math build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/misc build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/multibyte build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/network build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/stat build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/stdio build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/stdlib build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/string build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/include build/release/tinygo/lib/wasi-libc/libc-top-half/musl
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
@cp -rp lib/wasi-libc/libc-top-half/musl/src/thread build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/time build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/musl/src/unistd build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@cp -rp lib/wasi-libc/libc-top-half/sources build/release/tinygo/lib/wasi-libc/libc-top-half
@cp -rp lib/wasi-cli/wit build/release/tinygo/lib/wasi-cli/wit
@cp -rp llvm-project/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt-builtins
@cp -rp llvm-project/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
@@ -1052,6 +1120,7 @@ endif
tools:
cd internal/tools && go generate -tags tools ./
LINTDIRS=src/os/ src/reflect/
.PHONY: lint
lint: tools ## Lint source tree
revive -version
@@ -1059,7 +1128,10 @@ lint: tools ## Lint source tree
# revive.toml isn't flexible enough to filter out just one kind of error from a checker, so do it with grep here.
# Can't use grep with friendly formatter. Plain output isn't too bad, though.
# Use 'grep .' to get rid of stray blank line
revive -config revive.toml compiler/... src/{os,reflect}/*.go | grep -v "should have comment or be unexported" | grep '.' | awk '{print}; END {exit NR>0}'
revive -config revive.toml compiler/... $$( find $(LINTDIRS) -type f -name '*.go' ) \
| grep -v "should have comment or be unexported" \
| grep '.' \
| awk '{print}; END {exit NR>0}'
SPELLDIRSCMD=find . -depth 1 -type d | egrep -wv '.git|lib|llvm|src'; find src -depth 1 | egrep -wv 'device|internal|net|vendor'; find src/internal -depth 1 -type d | egrep -wv src/internal/wasi
.PHONY: spell
+15
View File
@@ -3,6 +3,7 @@ package builder
import (
"bytes"
"debug/elf"
"debug/macho"
"debug/pe"
"encoding/binary"
"errors"
@@ -62,6 +63,20 @@ func makeArchive(arfile *os.File, objs []string) error {
fileIndex int
}{symbol.Name, i})
}
} else if dbg, err := macho.NewFile(objfile); err == nil {
for _, symbol := range dbg.Symtab.Syms {
// See mach-o/nlist.h
if symbol.Type&0x0e != 0xe { // (symbol.Type & N_TYPE) != N_SECT
continue // undefined symbol
}
if symbol.Type&0x01 == 0 { // (symbol.Type & N_EXT) == 0
continue // internal symbol (static, etc)
}
symbolTable = append(symbolTable, struct {
name string
fileIndex int
}{symbol.Name, i})
}
} else if dbg, err := pe.NewFile(objfile); err == nil {
for _, symbol := range dbg.Symbols {
if symbol.StorageClass != 2 {
+88
View File
@@ -0,0 +1,88 @@
package builder
// The well-known conservative Boehm-Demers-Weiser GC.
// This file provides a way to compile this GC for use with TinyGo.
import (
"path/filepath"
"strings"
"github.com/tinygo-org/tinygo/goenv"
)
var BoehmGC = Library{
name: "bdwgc",
cflags: func(target, headerPath string) []string {
libdir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/bdwgc")
flags := []string{
// use a modern environment
"-DUSE_MMAP", // mmap is available
"-DUSE_MUNMAP", // return memory to the OS using munmap
"-DGC_BUILTIN_ATOMIC", // use compiler intrinsics for atomic operations
"-DNO_EXECUTE_PERMISSION", // don't make the heap executable
// specific flags for TinyGo
"-DALL_INTERIOR_POINTERS", // scan interior pointers (needed for Go)
"-DIGNORE_DYNAMIC_LOADING", // we don't support dynamic loading at the moment
"-DNO_GETCONTEXT", // musl doesn't support getcontext()
"-DGC_DISABLE_INCREMENTAL", // don't mess with SIGSEGV and such
// Use a minimal environment.
"-DNO_MSGBOX_ON_ERROR", // don't call MessageBoxA on Windows
"-DDONT_USE_ATEXIT",
"-DNO_GETENV",
// Special flag to work around the lack of __data_start in ld.lld.
// TODO: try to fix this in LLVM/lld directly so we don't have to
// work around it anymore.
"-DGC_DONT_REGISTER_MAIN_STATIC_DATA",
// Do not scan the stack. We have our own mechanism to do this.
"-DSTACK_NOT_SCANNED",
// Assertions can be enabled while debugging GC issues.
//"-DGC_ASSERTIONS",
// We use our own way of dealing with threads (that is a bit hacky).
// See src/runtime/gc_boehm.go.
//"-DGC_THREADS",
//"-DTHREAD_LOCAL_ALLOC",
"-I" + libdir + "/include",
}
return flags
},
needsLibc: true,
sourceDir: func() string {
return filepath.Join(goenv.Get("TINYGOROOT"), "lib/bdwgc")
},
librarySources: func(target string, _ bool) ([]string, error) {
sources := []string{
"allchblk.c",
"alloc.c",
"blacklst.c",
"dbg_mlc.c",
"dyn_load.c",
"finalize.c",
"headers.c",
"mach_dep.c",
"malloc.c",
"mark.c",
"mark_rts.c",
"misc.c",
"new_hblk.c",
"obj_map.c",
"os_dep.c",
"reclaim.c",
}
if strings.Split(target, "-")[2] == "windows" {
// Due to how the linker on Windows works (that doesn't allow
// undefined functions), we need to include these extra files.
sources = append(sources,
"mallocx.c",
"ptr_chck.c",
)
}
return sources, nil
},
}
+65 -54
View File
@@ -14,7 +14,6 @@ import (
"fmt"
"go/types"
"hash/crc32"
"io/fs"
"math/bits"
"os"
"os/exec"
@@ -149,16 +148,17 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
var libcDependencies []*compileJob
switch config.Target.Libc {
case "darwin-libSystem":
job := makeDarwinLibSystemJob(config, tmpdir)
libcDependencies = append(libcDependencies, job)
libcJob := makeDarwinLibSystemJob(config, tmpdir)
libcDependencies = append(libcDependencies, libcJob)
case "musl":
job, unlock, err := libMusl.load(config, tmpdir)
var unlock func()
libcJob, unlock, err := libMusl.load(config, tmpdir)
if err != nil {
return BuildResult{}, err
}
defer unlock()
libcDependencies = append(libcDependencies, dummyCompileJob(filepath.Join(filepath.Dir(job.result), "crt1.o")))
libcDependencies = append(libcDependencies, job)
libcDependencies = append(libcDependencies, dummyCompileJob(filepath.Join(filepath.Dir(libcJob.result), "crt1.o")))
libcDependencies = append(libcDependencies, libcJob)
case "picolibc":
libcJob, unlock, err := libPicolibc.load(config, tmpdir)
if err != nil {
@@ -167,11 +167,12 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
defer unlock()
libcDependencies = append(libcDependencies, libcJob)
case "wasi-libc":
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
if _, err := os.Stat(path); errors.Is(err, fs.ErrNotExist) {
return BuildResult{}, errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?")
libcJob, unlock, err := libWasiLibc.load(config, tmpdir)
if err != nil {
return BuildResult{}, err
}
libcDependencies = append(libcDependencies, dummyCompileJob(path))
defer unlock()
libcDependencies = append(libcDependencies, libcJob)
case "wasmbuiltins":
libcJob, unlock, err := libWasmBuiltins.load(config, tmpdir)
if err != nil {
@@ -180,12 +181,12 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
defer unlock()
libcDependencies = append(libcDependencies, libcJob)
case "mingw-w64":
job, unlock, err := libMinGW.load(config, tmpdir)
libcJob, unlock, err := libMinGW.load(config, tmpdir)
if err != nil {
return BuildResult{}, err
}
defer unlock()
libcDependencies = append(libcDependencies, job)
libcDependencies = append(libcDependencies, libcJob)
libcDependencies = append(libcDependencies, makeMinGWExtraLibs(tmpdir, config.GOARCH())...)
case "":
// no library specified, so nothing to do
@@ -213,6 +214,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
MaxStackAlloc: config.MaxStackAlloc(),
NeedsStackObjects: config.NeedsStackObjects(),
Debug: !config.Options.SkipDWARF, // emit DWARF except when -internal-nodwarf is passed
Nobounds: config.Options.Nobounds,
PanicStrategy: config.PanicStrategy(),
}
@@ -449,8 +451,15 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
if global.IsNil() {
return errors.New("global not found: " + globalName)
}
globalType := global.GlobalValueType()
if globalType.TypeKind() != llvm.StructTypeKind || globalType.StructName() != "runtime._string" {
// Verify this is indeed a string. This is needed so
// that makeGlobalsModule can just create the right
// globals of string type without checking.
return fmt.Errorf("%s: not a string", globalName)
}
name := global.Name()
newGlobal := llvm.AddGlobal(mod, global.GlobalValueType(), name+".tmp")
newGlobal := llvm.AddGlobal(mod, globalType, name+".tmp")
global.ReplaceAllUsesWith(newGlobal)
global.EraseFromParentAsGlobal()
newGlobal.SetName(name)
@@ -538,6 +547,15 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
}
}
// Insert values from -ldflags="-X ..." into the IR.
// This is a separate module, so that the "runtime._string" type
// doesn't need to match precisely. LLVM tends to rename that type
// sometimes, leading to errors. But linking in a separate module
// works fine. See:
// https://github.com/tinygo-org/tinygo/issues/4810
globalsMod := makeGlobalsModule(ctx, globalValues, machine)
llvm.LinkModules(mod, globalsMod)
// Create runtime.initAll function that calls the runtime
// initializer of each package.
llvmInitFn := mod.NamedFunction("runtime.initAll")
@@ -590,7 +608,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
// Run all optimization passes, which are much more effective now
// that the optimizer can see the whole program at once.
err := optimizeProgram(mod, config, globalValues)
err := optimizeProgram(mod, config)
if err != nil {
return err
}
@@ -693,6 +711,16 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
linkerDependencies = append(linkerDependencies, job)
}
// The Boehm collector is stored in a separate C library.
if config.GC() == "boehm" {
job, unlock, err := BoehmGC.load(config, tmpdir)
if err != nil {
return BuildResult{}, err
}
defer unlock()
linkerDependencies = append(linkerDependencies, job)
}
// Add jobs to compile extra files. These files are in C or assembly and
// contain things like the interrupt vector table and low level operations
// such as stack switching.
@@ -1018,7 +1046,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
// Special format for the ESP family of chips (parsed by the ROM
// bootloader).
result.Binary = filepath.Join(tmpdir, "main"+outext)
err := makeESPFirmareImage(result.Executable, result.Binary, outputBinaryFormat)
err := makeESPFirmwareImage(result.Executable, result.Binary, outputBinaryFormat)
if err != nil {
return result, err
}
@@ -1145,7 +1173,7 @@ func createEmbedObjectFile(data, hexSum, sourceFile, sourceDir, tmpdir string, c
// optimizeProgram runs a series of optimizations and transformations that are
// needed to convert a program to its final form. Some transformations are not
// optional and must be run as the compiler expects them to run.
func optimizeProgram(mod llvm.Module, config *compileopts.Config, globalValues map[string]map[string]string) error {
func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA())
if err != nil {
return err
@@ -1163,12 +1191,6 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config, globalValues m
}
}
// Insert values from -ldflags="-X ..." into the IR.
err = setGlobalValues(mod, globalValues)
if err != nil {
return err
}
// Run most of the whole-program optimizations (including the whole
// O0/O1/O2/Os/Oz optimization pipeline).
errs := transform.Optimize(mod, config)
@@ -1182,10 +1204,19 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config, globalValues m
return nil
}
// setGlobalValues sets the global values from the -ldflags="-X ..." compiler
// option in the given module. An error may be returned if the global is not of
// the expected type.
func setGlobalValues(mod llvm.Module, globals map[string]map[string]string) error {
func makeGlobalsModule(ctx llvm.Context, globals map[string]map[string]string, machine llvm.TargetMachine) llvm.Module {
mod := ctx.NewModule("cmdline-globals")
targetData := machine.CreateTargetData()
defer targetData.Dispose()
mod.SetDataLayout(targetData.String())
stringType := ctx.StructCreateNamed("runtime._string")
uintptrType := ctx.IntType(targetData.PointerSize() * 8)
stringType.StructSetBody([]llvm.Type{
llvm.PointerType(ctx.Int8Type(), 0),
uintptrType,
}, false)
var pkgPaths []string
for pkgPath := range globals {
pkgPaths = append(pkgPaths, pkgPath)
@@ -1201,24 +1232,6 @@ func setGlobalValues(mod llvm.Module, globals map[string]map[string]string) erro
for _, name := range names {
value := pkg[name]
globalName := pkgPath + "." + name
global := mod.NamedGlobal(globalName)
if global.IsNil() || !global.Initializer().IsNil() {
// The global either does not exist (optimized away?) or has
// some value, in which case it has already been initialized at
// package init time.
continue
}
// A strin is a {ptr, len} pair. We need these types to build the
// initializer.
initializerType := global.GlobalValueType()
if initializerType.TypeKind() != llvm.StructTypeKind || initializerType.StructName() == "" {
return fmt.Errorf("%s: not a string", globalName)
}
elementTypes := initializerType.StructElementTypes()
if len(elementTypes) != 2 {
return fmt.Errorf("%s: not a string", globalName)
}
// Create a buffer for the string contents.
bufInitializer := mod.Context().ConstString(value, false)
@@ -1229,22 +1242,20 @@ func setGlobalValues(mod llvm.Module, globals map[string]map[string]string) erro
buf.SetLinkage(llvm.PrivateLinkage)
// Create the string value, which is a {ptr, len} pair.
zero := llvm.ConstInt(mod.Context().Int32Type(), 0, false)
ptr := llvm.ConstGEP(bufInitializer.Type(), buf, []llvm.Value{zero, zero})
if ptr.Type() != elementTypes[0] {
return fmt.Errorf("%s: not a string", globalName)
}
length := llvm.ConstInt(elementTypes[1], uint64(len(value)), false)
initializer := llvm.ConstNamedStruct(initializerType, []llvm.Value{
ptr,
length := llvm.ConstInt(uintptrType, uint64(len(value)), false)
initializer := llvm.ConstNamedStruct(stringType, []llvm.Value{
buf,
length,
})
// Set the initializer. No initializer should be set at this point.
// Create the string global.
global := llvm.AddGlobal(mod, stringType, globalName)
global.SetInitializer(initializer)
global.SetAlignment(targetData.PrefTypeAlignment(stringType))
}
}
return nil
return mod
}
// functionStackSizes keeps stack size information about a single function
+1
View File
@@ -67,6 +67,7 @@ func TestClangAttributes(t *testing.T) {
{GOOS: "linux", GOARCH: "mipsle", GOMIPS: "softfloat"},
{GOOS: "darwin", GOARCH: "amd64"},
{GOOS: "darwin", GOARCH: "arm64"},
{GOOS: "windows", GOARCH: "386"},
{GOOS: "windows", GOARCH: "amd64"},
{GOOS: "windows", GOARCH: "arm64"},
} {
+11 -1
View File
@@ -3,6 +3,7 @@ package builder
import (
"os"
"path/filepath"
"strings"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
@@ -201,6 +202,11 @@ var avrBuiltins = []string{
"avr/udivmodqi4.S",
}
// Builtins needed specifically for windows/386.
var windowsI386Builtins = []string{
"i386/chkstk.S", // also _alloca
}
// libCompilerRT is a library with symbols required by programs compiled with
// LLVM. These symbols are for operations that cannot be emitted with a single
// instruction or a short sequence of instructions for that target.
@@ -220,7 +226,7 @@ var libCompilerRT = Library{
// Development build.
return filepath.Join(goenv.Get("TINYGOROOT"), "lib/compiler-rt-builtins")
},
librarySources: func(target string) ([]string, error) {
librarySources: func(target string, _ bool) ([]string, error) {
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
switch compileopts.CanonicalArchName(target) {
case "arm":
@@ -229,6 +235,10 @@ var libCompilerRT = Library{
builtins = append(builtins, avrBuiltins...)
case "x86_64", "aarch64", "riscv64": // any 64-bit arch
builtins = append(builtins, genericBuiltins128...)
case "i386":
if strings.Split(target, "-")[2] == "windows" {
builtins = append(builtins, windowsI386Builtins...)
}
}
return builtins, nil
},
+13 -8
View File
@@ -144,8 +144,6 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
.Default(llvm::DebugCompressionType::None);
}
Opts.RelaxELFRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
Opts.SSE2AVX = Args.hasArg(OPT_msse2avx);
if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
@@ -236,6 +234,9 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.EmitCompactUnwindNonCanonical =
Args.hasArg(OPT_femit_compact_unwind_non_canonical);
Opts.Crel = Args.hasArg(OPT_crel);
Opts.ImplicitMapsyms = Args.hasArg(OPT_mmapsyms_implicit);
Opts.X86RelaxRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
Opts.X86Sse2Avx = Args.hasArg(OPT_msse2avx);
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
@@ -294,8 +295,9 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical;
MCOptions.MCSaveTempLabels = Opts.SaveTemporaryLabels;
MCOptions.Crel = Opts.Crel;
MCOptions.X86RelaxRelocations = Opts.RelaxELFRelocations;
MCOptions.X86Sse2Avx = Opts.SSE2AVX;
MCOptions.ImplicitMapSyms = Opts.ImplicitMapsyms;
MCOptions.X86RelaxRelocations = Opts.X86RelaxRelocations;
MCOptions.X86Sse2Avx = Opts.X86Sse2Avx;
MCOptions.CompressDebugSections = Opts.CompressDebugSections;
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
@@ -343,10 +345,6 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
std::unique_ptr<MCObjectFileInfo> MOFI(
TheTarget->createMCObjectFileInfo(Ctx, PIC));
if (Opts.DarwinTargetVariantTriple)
MOFI->setDarwinTargetVariantTriple(*Opts.DarwinTargetVariantTriple);
if (!Opts.DarwinTargetVariantSDKVersion.empty())
MOFI->setDarwinTargetVariantSDKVersion(Opts.DarwinTargetVariantSDKVersion);
Ctx.setObjectFileInfo(MOFI.get());
if (Opts.GenDwarfForAssembly)
@@ -428,6 +426,13 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
Str.reset(TheTarget->createMCObjectStreamer(
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI));
Str.get()->initSections(Opts.NoExecStack, *STI);
if (T.isOSBinFormatMachO() && T.isOSDarwin()) {
Triple *TVT = Opts.DarwinTargetVariantTriple
? &*Opts.DarwinTargetVariantTriple
: nullptr;
Str->emitVersionForTarget(T, VersionTuple(), TVT,
Opts.DarwinTargetVariantSDKVersion);
}
}
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
+10 -5
View File
@@ -45,10 +45,6 @@ struct AssemblerInvocation {
LLVM_PREFERRED_TYPE(bool)
unsigned GenDwarfForAssembly : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned RelaxELFRelocations : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned SSE2AVX : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned Dwarf64 : 1;
unsigned DwarfVersion;
std::string DwarfDebugFlags;
@@ -117,6 +113,13 @@ struct AssemblerInvocation {
LLVM_PREFERRED_TYPE(bool)
unsigned Crel : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned ImplicitMapsyms : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned X86RelaxRelocations : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned X86Sse2Avx : 1;
/// The name of the relocation model to use.
std::string RelocationModel;
@@ -148,7 +151,6 @@ public:
ShowInst = 0;
ShowEncoding = 0;
RelaxAll = 0;
SSE2AVX = 0;
NoExecStack = 0;
FatalWarnings = 0;
NoWarn = 0;
@@ -160,6 +162,9 @@ public:
EmitDwarfUnwind = EmitDwarfUnwindType::Default;
EmitCompactUnwindNonCanonical = false;
Crel = false;
ImplicitMapsyms = 0;
X86RelaxRelocations = 0;
X86Sse2Avx = 0;
}
static bool CreateFromArgs(AssemblerInvocation &Res,
+1 -1
View File
@@ -60,7 +60,7 @@ bool tinygo_clang_driver(int argc, char **argv) {
}
// Create the actual diagnostics engine.
Clang->createDiagnostics();
Clang->createDiagnostics(*llvm::vfs::getRealFileSystem());
if (!Clang->hasDiagnostics()) {
return false;
}
+1 -1
View File
@@ -26,7 +26,7 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
// Version range supported by TinyGo.
const minorMin = 19
const minorMax = 24
const minorMax = 25
// Check that we support this Go toolchain version.
gorootMajor, gorootMinor, err := goenv.GetGorootVersion()
+2 -2
View File
@@ -23,7 +23,7 @@ type espImageSegment struct {
data []byte
}
// makeESPFirmareImage converts an input ELF file to an image file for an ESP32 or
// makeESPFirmwareImage converts an input ELF file to an image file for an ESP32 or
// ESP8266 chip. This is a special purpose image format just for the ESP chip
// family, and is parsed by the on-chip mask ROM bootloader.
//
@@ -31,7 +31,7 @@ type espImageSegment struct {
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format
// https://github.com/espressif/esp-idf/blob/8fbb63c2a701c22ccf4ce249f43aded73e134a34/components/bootloader_support/include/esp_image_format.h#L58
// https://github.com/espressif/esptool/blob/master/esptool.py
func makeESPFirmareImage(infile, outfile, format string) error {
func makeESPFirmwareImage(infile, outfile, format string) error {
inf, err := elf.Open(infile)
if err != nil {
return err
+25 -12
View File
@@ -15,6 +15,9 @@ import (
// Library is a container for information about a single C library, such as a
// compiler runtime or libc.
//
// Note: whenever a library gets changed, the version in compileopts/config.go
// probably also needs to be incremented.
type Library struct {
// The library name, such as compiler-rt or picolibc.
name string
@@ -25,11 +28,17 @@ type Library struct {
// cflags returns the C flags specific to this library
cflags func(target, headerPath string) []string
// cflagsForFile returns additional C flags for a particular source file.
cflagsForFile func(path string) []string
// needsLibc is set to true if this library needs libc headers.
needsLibc bool
// The source directory.
sourceDir func() string
// The source files, relative to sourceDir.
librarySources func(target string) ([]string, error)
librarySources func(target string, libcNeedsMalloc bool) ([]string, error)
// The source code for the crt1.o file, relative to sourceDir.
crt1Source string
@@ -44,13 +53,8 @@ type Library struct {
// As a side effect, this call creates the library header files if they didn't
// exist yet.
func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJob, abortLock func(), err error) {
outdir, precompiled := config.LibcPath(l.name)
outdir := config.LibraryPath(l.name)
archiveFilePath := filepath.Join(outdir, "lib.a")
if precompiled {
// Found a precompiled library for this OS/architecture. Return the path
// directly.
return dummyCompileJob(archiveFilePath), func() {}, nil
}
// Create a lock on the output (if supported).
// This is a bit messy, but avoids a deadlock because it is ordered consistently with other library loads within a build.
@@ -181,6 +185,9 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
args = append(args, "-mfpu=vfpv2")
}
}
if l.needsLibc {
args = append(args, config.LibcCFlags()...)
}
var once sync.Once
@@ -219,12 +226,13 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
// Create jobs to compile all sources. These jobs are depended upon by the
// archive job above, so must be run first.
paths, err := l.librarySources(target)
paths, err := l.librarySources(target, config.LibcNeedsMalloc())
if err != nil {
return nil, nil, err
}
for _, path := range paths {
// Strip leading "../" parts off the path.
path := path
cleanpath := path
for strings.HasPrefix(cleanpath, "../") {
cleanpath = cleanpath[3:]
@@ -233,11 +241,14 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
objpath := filepath.Join(dir, cleanpath+".o")
os.MkdirAll(filepath.Dir(objpath), 0o777)
objs = append(objs, objpath)
job.dependencies = append(job.dependencies, &compileJob{
objfile := &compileJob{
description: "compile " + srcpath,
run: func(*compileJob) error {
var compileArgs []string
compileArgs = append(compileArgs, args...)
if l.cflagsForFile != nil {
compileArgs = append(compileArgs, l.cflagsForFile(path)...)
}
compileArgs = append(compileArgs, "-o", objpath, srcpath)
if config.Options.PrintCommands != nil {
config.Options.PrintCommands("clang", compileArgs...)
@@ -248,7 +259,8 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
}
return nil
},
})
}
job.dependencies = append(job.dependencies, objfile)
}
// Create crt1.o job, if needed.
@@ -257,7 +269,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
// won't make much of a difference in speed).
if l.crt1Source != "" {
srcpath := filepath.Join(sourceDir, l.crt1Source)
job.dependencies = append(job.dependencies, &compileJob{
crt1Job := &compileJob{
description: "compile " + srcpath,
run: func(*compileJob) error {
var compileArgs []string
@@ -277,7 +289,8 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
}
return os.Rename(tmpfile.Name(), filepath.Join(outdir, "crt1.o"))
},
})
}
job.dependencies = append(job.dependencies, crt1Job)
}
ok = true
+87 -33
View File
@@ -30,25 +30,62 @@ var libMinGW = Library{
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/mingw-w64") },
cflags: func(target, headerPath string) []string {
mingwDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/mingw-w64")
return []string{
flags := []string{
"-nostdlibinc",
"-isystem", mingwDir + "/mingw-w64-crt/include",
"-isystem", mingwDir + "/mingw-w64-headers/crt",
"-isystem", mingwDir + "/mingw-w64-headers/include",
"-I", mingwDir + "/mingw-w64-headers/defaults/include",
"-I" + headerPath,
}
if strings.Split(target, "-")[0] == "i386" {
flags = append(flags,
"-D__MSVCRT_VERSION__=0x700", // Microsoft Visual C++ .NET 2002
"-D_WIN32_WINNT=0x0501", // target Windows XP
"-D_CRTBLD",
"-Wno-pragma-pack",
)
}
return flags
},
librarySources: func(target string) ([]string, error) {
librarySources: func(target string, _ bool) ([]string, error) {
// These files are needed so that printf and the like are supported.
sources := []string{
"mingw-w64-crt/stdio/ucrt_fprintf.c",
"mingw-w64-crt/stdio/ucrt_fwprintf.c",
"mingw-w64-crt/stdio/ucrt_printf.c",
"mingw-w64-crt/stdio/ucrt_snprintf.c",
"mingw-w64-crt/stdio/ucrt_sprintf.c",
"mingw-w64-crt/stdio/ucrt_vfprintf.c",
"mingw-w64-crt/stdio/ucrt_vprintf.c",
"mingw-w64-crt/stdio/ucrt_vsnprintf.c",
"mingw-w64-crt/stdio/ucrt_vsprintf.c",
var sources []string
if strings.Split(target, "-")[0] == "i386" {
// Old 32-bit x86 systems use msvcrt.dll.
sources = []string{
"mingw-w64-crt/crt/pseudo-reloc.c",
"mingw-w64-crt/gdtoa/dmisc.c",
"mingw-w64-crt/gdtoa/gdtoa.c",
"mingw-w64-crt/gdtoa/gmisc.c",
"mingw-w64-crt/gdtoa/misc.c",
"mingw-w64-crt/math/x86/exp2.S",
"mingw-w64-crt/math/x86/trunc.S",
"mingw-w64-crt/misc/___mb_cur_max_func.c",
"mingw-w64-crt/misc/lc_locale_func.c",
"mingw-w64-crt/misc/mbrtowc.c",
"mingw-w64-crt/misc/strnlen.c",
"mingw-w64-crt/misc/wcrtomb.c",
"mingw-w64-crt/misc/wcsnlen.c",
"mingw-w64-crt/stdio/acrt_iob_func.c",
"mingw-w64-crt/stdio/mingw_lock.c",
"mingw-w64-crt/stdio/mingw_pformat.c",
"mingw-w64-crt/stdio/mingw_vfprintf.c",
"mingw-w64-crt/stdio/mingw_vsnprintf.c",
}
} else {
// Anything somewhat modern (amd64, arm64) uses UCRT.
sources = []string{
"mingw-w64-crt/stdio/ucrt_fprintf.c",
"mingw-w64-crt/stdio/ucrt_fwprintf.c",
"mingw-w64-crt/stdio/ucrt_printf.c",
"mingw-w64-crt/stdio/ucrt_snprintf.c",
"mingw-w64-crt/stdio/ucrt_sprintf.c",
"mingw-w64-crt/stdio/ucrt_vfprintf.c",
"mingw-w64-crt/stdio/ucrt_vprintf.c",
"mingw-w64-crt/stdio/ucrt_vsnprintf.c",
"mingw-w64-crt/stdio/ucrt_vsprintf.c",
}
}
return sources, nil
},
@@ -63,27 +100,41 @@ var libMinGW = Library{
func makeMinGWExtraLibs(tmpdir, goarch string) []*compileJob {
var jobs []*compileJob
root := goenv.Get("TINYGOROOT")
// Normally all the api-ms-win-crt-*.def files are all compiled to a single
// .lib file. But to simplify things, we're going to leave them as separate
// files.
for _, name := range []string{
"kernel32.def.in",
"api-ms-win-crt-conio-l1-1-0.def",
"api-ms-win-crt-convert-l1-1-0.def.in",
"api-ms-win-crt-environment-l1-1-0.def",
"api-ms-win-crt-filesystem-l1-1-0.def",
"api-ms-win-crt-heap-l1-1-0.def",
"api-ms-win-crt-locale-l1-1-0.def",
"api-ms-win-crt-math-l1-1-0.def.in",
"api-ms-win-crt-multibyte-l1-1-0.def",
"api-ms-win-crt-private-l1-1-0.def.in",
"api-ms-win-crt-process-l1-1-0.def",
"api-ms-win-crt-runtime-l1-1-0.def.in",
"api-ms-win-crt-stdio-l1-1-0.def",
"api-ms-win-crt-string-l1-1-0.def",
"api-ms-win-crt-time-l1-1-0.def",
"api-ms-win-crt-utility-l1-1-0.def",
} {
var libs []string
if goarch == "386" {
libs = []string{
// x86 uses msvcrt.dll instead of UCRT for compatibility with old
// Windows versions.
"advapi32.def.in",
"kernel32.def.in",
"msvcrt.def.in",
}
} else {
// Use the modernized UCRT on new systems.
// Normally all the api-ms-win-crt-*.def files are all compiled to a
// single .lib file. But to simplify things, we're going to leave them
// as separate files.
libs = []string{
"advapi32.def.in",
"kernel32.def.in",
"api-ms-win-crt-conio-l1-1-0.def",
"api-ms-win-crt-convert-l1-1-0.def.in",
"api-ms-win-crt-environment-l1-1-0.def",
"api-ms-win-crt-filesystem-l1-1-0.def",
"api-ms-win-crt-heap-l1-1-0.def",
"api-ms-win-crt-locale-l1-1-0.def",
"api-ms-win-crt-math-l1-1-0.def.in",
"api-ms-win-crt-multibyte-l1-1-0.def",
"api-ms-win-crt-private-l1-1-0.def.in",
"api-ms-win-crt-process-l1-1-0.def",
"api-ms-win-crt-runtime-l1-1-0.def.in",
"api-ms-win-crt-stdio-l1-1-0.def",
"api-ms-win-crt-string-l1-1-0.def",
"api-ms-win-crt-time-l1-1-0.def",
"api-ms-win-crt-utility-l1-1-0.def",
}
}
for _, name := range libs {
outpath := filepath.Join(tmpdir, filepath.Base(name)+".lib")
inpath := filepath.Join(root, "lib/mingw-w64/mingw-w64-crt/lib-common/"+name)
job := &compileJob{
@@ -93,6 +144,9 @@ func makeMinGWExtraLibs(tmpdir, goarch string) []*compileJob {
defpath := inpath
var archDef, emulation string
switch goarch {
case "386":
archDef = "-DDEF_I386"
emulation = "i386pe"
case "amd64":
archDef = "-DDEF_X64"
emulation = "i386pep"
+49 -31
View File
@@ -12,6 +12,45 @@ import (
"github.com/tinygo-org/tinygo/goenv"
)
// Create the alltypes.h file from the appropriate alltypes.h.in files.
func buildMuslAllTypes(arch, muslDir, outputBitsDir string) error {
// Create the file alltypes.h.
f, err := os.Create(filepath.Join(outputBitsDir, "alltypes.h"))
if err != nil {
return err
}
infiles := []string{
filepath.Join(muslDir, "arch", arch, "bits", "alltypes.h.in"),
filepath.Join(muslDir, "include", "alltypes.h.in"),
}
for _, infile := range infiles {
data, err := os.ReadFile(infile)
if err != nil {
return err
}
lines := strings.Split(string(data), "\n")
for _, line := range lines {
if strings.HasPrefix(line, "TYPEDEF ") {
matches := regexp.MustCompile(`TYPEDEF (.*) ([^ ]*);`).FindStringSubmatch(line)
value := matches[1]
name := matches[2]
line = fmt.Sprintf("#if defined(__NEED_%s) && !defined(__DEFINED_%s)\ntypedef %s %s;\n#define __DEFINED_%s\n#endif\n", name, name, value, name, name)
}
if strings.HasPrefix(line, "STRUCT ") {
matches := regexp.MustCompile(`STRUCT * ([^ ]*) (.*);`).FindStringSubmatch(line)
name := matches[1]
value := matches[2]
line = fmt.Sprintf("#if defined(__NEED_struct_%s) && !defined(__DEFINED_struct_%s)\nstruct %s %s;\n#define __DEFINED_struct_%s\n#endif\n", name, name, name, value, name)
}
_, err := f.WriteString(line + "\n")
if err != nil {
return err
}
}
}
return f.Close()
}
var libMusl = Library{
name: "musl",
makeHeaders: func(target, includeDir string) error {
@@ -24,41 +63,13 @@ var libMusl = Library{
arch := compileopts.MuslArchitecture(target)
muslDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib", "musl")
// Create the file alltypes.h.
f, err := os.Create(filepath.Join(bits, "alltypes.h"))
err = buildMuslAllTypes(arch, muslDir, bits)
if err != nil {
return err
}
infiles := []string{
filepath.Join(muslDir, "arch", arch, "bits", "alltypes.h.in"),
filepath.Join(muslDir, "include", "alltypes.h.in"),
}
for _, infile := range infiles {
data, err := os.ReadFile(infile)
if err != nil {
return err
}
lines := strings.Split(string(data), "\n")
for _, line := range lines {
if strings.HasPrefix(line, "TYPEDEF ") {
matches := regexp.MustCompile(`TYPEDEF (.*) ([^ ]*);`).FindStringSubmatch(line)
value := matches[1]
name := matches[2]
line = fmt.Sprintf("#if defined(__NEED_%s) && !defined(__DEFINED_%s)\ntypedef %s %s;\n#define __DEFINED_%s\n#endif\n", name, name, value, name, name)
}
if strings.HasPrefix(line, "STRUCT ") {
matches := regexp.MustCompile(`STRUCT * ([^ ]*) (.*);`).FindStringSubmatch(line)
name := matches[1]
value := matches[2]
line = fmt.Sprintf("#if defined(__NEED_struct_%s) && !defined(__DEFINED_struct_%s)\nstruct %s %s;\n#define __DEFINED_struct_%s\n#endif\n", name, name, name, value, name)
}
f.WriteString(line + "\n")
}
}
f.Close()
// Create the file syscall.h.
f, err = os.Create(filepath.Join(bits, "syscall.h"))
f, err := os.Create(filepath.Join(bits, "syscall.h"))
if err != nil {
return err
}
@@ -110,29 +121,36 @@ var libMusl = Library{
return cflags
},
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/musl/src") },
librarySources: func(target string) ([]string, error) {
librarySources: func(target string, _ bool) ([]string, error) {
arch := compileopts.MuslArchitecture(target)
globs := []string{
"conf/*.c",
"ctype/*.c",
"env/*.c",
"errno/*.c",
"exit/*.c",
"fcntl/*.c",
"internal/defsysinfo.c",
"internal/intscan.c",
"internal/libc.c",
"internal/shgetc.c",
"internal/syscall_ret.c",
"internal/vdso.c",
"legacy/*.c",
"locale/*.c",
"linux/*.c",
"locale/*.c",
"malloc/*.c",
"malloc/mallocng/*.c",
"mman/*.c",
"math/*.c",
"misc/*.c",
"multibyte/*.c",
"sched/*.c",
"signal/" + arch + "/*.s",
"signal/*.c",
"stdio/*.c",
"stdlib/*.c",
"string/*.c",
"thread/" + arch + "/*.s",
"thread/*.c",
+1 -1
View File
@@ -43,7 +43,7 @@ var libPicolibc = Library{
}
},
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib") },
librarySources: func(target string) ([]string, error) {
librarySources: func(target string, _ bool) ([]string, error) {
sources := append([]string(nil), picolibcSources...)
if !strings.HasPrefix(target, "avr") {
// Small chips without long jumps can't compile many files (printf,
+1 -1
View File
@@ -490,7 +490,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
continue
}
if section.Type == elf.SHT_NOBITS {
if section.Name == ".stack" {
if strings.HasPrefix(section.Name, ".stack") {
// TinyGo emits stack sections on microcontroller using the
// ".stack" name.
// This is a bit ugly, but I don't think there is a way to
+3 -3
View File
@@ -42,9 +42,9 @@ func TestBinarySize(t *testing.T) {
// This is a small number of very diverse targets that we want to test.
tests := []sizeTest{
// microcontrollers
{"hifive1b", "examples/echo", 4560, 280, 0, 2268},
{"microbit", "examples/serial", 2916, 388, 8, 2272},
{"wioterminal", "examples/pininterrupt", 7359, 1489, 116, 6912},
{"hifive1b", "examples/echo", 3884, 280, 0, 2268},
{"microbit", "examples/serial", 2924, 388, 8, 2272},
{"wioterminal", "examples/pininterrupt", 7365, 1491, 116, 6912},
// TODO: also check wasm. Right now this is difficult, because
// wasm binaries are run through wasm-opt and therefore the
+284
View File
@@ -0,0 +1,284 @@
package builder
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/tinygo-org/tinygo/goenv"
)
var libWasiLibc = Library{
name: "wasi-libc",
makeHeaders: func(target, includeDir string) error {
bits := filepath.Join(includeDir, "bits")
err := os.Mkdir(bits, 0777)
if err != nil {
return err
}
muslDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib", "wasi-libc/libc-top-half/musl")
err = buildMuslAllTypes("wasm32", muslDir, bits)
if err != nil {
return err
}
// See MUSL_OMIT_HEADERS in the Makefile.
omitHeaders := map[string]struct{}{
"syslog.h": {},
"wait.h": {},
"ucontext.h": {},
"paths.h": {},
"utmp.h": {},
"utmpx.h": {},
"lastlog.h": {},
"elf.h": {},
"link.h": {},
"pwd.h": {},
"shadow.h": {},
"grp.h": {},
"mntent.h": {},
"netdb.h": {},
"resolv.h": {},
"pty.h": {},
"dlfcn.h": {},
"setjmp.h": {},
"ulimit.h": {},
"wordexp.h": {},
"spawn.h": {},
"termios.h": {},
"libintl.h": {},
"aio.h": {},
"stdarg.h": {},
"stddef.h": {},
"pthread.h": {},
}
for _, glob := range [][2]string{
{"libc-bottom-half/headers/public/*.h", ""},
{"libc-bottom-half/headers/public/wasi/*.h", "wasi"},
{"libc-top-half/musl/arch/wasm32/bits/*.h", "bits"},
{"libc-top-half/musl/include/*.h", ""},
{"libc-top-half/musl/include/netinet/*.h", "netinet"},
{"libc-top-half/musl/include/sys/*.h", "sys"},
} {
matches, _ := filepath.Glob(filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc", glob[0]))
outDir := filepath.Join(includeDir, glob[1])
os.MkdirAll(outDir, 0o777)
for _, match := range matches {
name := filepath.Base(match)
if _, ok := omitHeaders[name]; ok {
continue
}
data, err := os.ReadFile(match)
if err != nil {
return err
}
err = os.WriteFile(filepath.Join(outDir, name), data, 0o666)
if err != nil {
return err
}
}
}
return nil
},
cflags: func(target, headerPath string) []string {
libcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc")
return []string{
"-Werror",
"-Wall",
"-std=gnu11",
"-nostdlibinc",
"-mnontrapping-fptoint", "-msign-ext", "-mbulk-memory",
"-Wno-null-pointer-arithmetic", "-Wno-unused-parameter", "-Wno-sign-compare", "-Wno-unused-variable", "-Wno-unused-function", "-Wno-ignored-attributes", "-Wno-missing-braces", "-Wno-ignored-pragmas", "-Wno-unused-but-set-variable", "-Wno-unknown-warning-option",
"-Wno-parentheses", "-Wno-shift-op-parentheses", "-Wno-bitwise-op-parentheses", "-Wno-logical-op-parentheses", "-Wno-string-plus-int", "-Wno-dangling-else", "-Wno-unknown-pragmas",
"-DNDEBUG",
"-D__wasilibc_printscan_no_long_double",
"-D__wasilibc_printscan_full_support_option=\"long double support is disabled\"",
"-DBULK_MEMORY_THRESHOLD=32", // default threshold in wasi-libc
"-isystem", headerPath,
"-I" + libcDir + "/libc-top-half/musl/src/include",
"-I" + libcDir + "/libc-top-half/musl/src/internal",
"-I" + libcDir + "/libc-top-half/musl/arch/wasm32",
"-I" + libcDir + "/libc-top-half/musl/arch/generic",
"-I" + libcDir + "/libc-top-half/headers/private",
}
},
cflagsForFile: func(path string) []string {
if strings.HasPrefix(path, "libc-bottom-half"+string(os.PathSeparator)) {
libcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc")
return []string{
"-I" + libcDir + "/libc-bottom-half/headers/private",
"-I" + libcDir + "/libc-bottom-half/cloudlibc/src/include",
"-I" + libcDir + "/libc-bottom-half/cloudlibc/src",
}
}
return nil
},
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc") },
librarySources: func(target string, libcNeedsMalloc bool) ([]string, error) {
type filePattern struct {
glob string
exclude []string
}
// See: LIBC_TOP_HALF_MUSL_SOURCES in the Makefile
globs := []filePattern{
// Top half: mostly musl sources.
{glob: "libc-top-half/sources/*.c"},
{glob: "libc-top-half/musl/src/conf/*.c"},
{glob: "libc-top-half/musl/src/internal/*.c", exclude: []string{
"procfdname.c", "syscall.c", "syscall_ret.c", "vdso.c", "version.c",
}},
{glob: "libc-top-half/musl/src/locale/*.c", exclude: []string{
"dcngettext.c", "textdomain.c", "bind_textdomain_codeset.c"}},
{glob: "libc-top-half/musl/src/math/*.c", exclude: []string{
"__signbit.c", "__signbitf.c", "__signbitl.c",
"__fpclassify.c", "__fpclassifyf.c", "__fpclassifyl.c",
"ceilf.c", "ceil.c",
"floorf.c", "floor.c",
"truncf.c", "trunc.c",
"rintf.c", "rint.c",
"nearbyintf.c", "nearbyint.c",
"sqrtf.c", "sqrt.c",
"fabsf.c", "fabs.c",
"copysignf.c", "copysign.c",
"fminf.c", "fmaxf.c",
"fmin.c", "fmax.c,",
}},
{glob: "libc-top-half/musl/src/multibyte/*.c"},
{glob: "libc-top-half/musl/src/stdio/*.c", exclude: []string{
"vfwscanf.c", "vfwprintf.c", // long double is unsupported
"__lockfile.c", "flockfile.c", "funlockfile.c", "ftrylockfile.c",
"rename.c",
"tmpnam.c", "tmpfile.c", "tempnam.c",
"popen.c", "pclose.c",
"remove.c",
"gets.c"}},
{glob: "libc-top-half/musl/src/stdlib/*.c"},
{glob: "libc-top-half/musl/src/string/*.c", exclude: []string{
"strsignal.c"}},
// Bottom half: connect top half to WASI equivalents.
{glob: "libc-bottom-half/cloudlibc/src/libc/*/*.c"},
{glob: "libc-bottom-half/cloudlibc/src/libc/sys/*/*.c"},
{glob: "libc-bottom-half/sources/*.c"},
}
// We're using the Boehm GC, so we need a heap implementation in the libc.
if libcNeedsMalloc {
globs = append(globs, filePattern{glob: "dlmalloc/src/dlmalloc.c"})
}
// See: LIBC_TOP_HALF_MUSL_SOURCES in the Makefile
sources := []string{
"libc-top-half/musl/src/misc/a64l.c",
"libc-top-half/musl/src/misc/basename.c",
"libc-top-half/musl/src/misc/dirname.c",
"libc-top-half/musl/src/misc/ffs.c",
"libc-top-half/musl/src/misc/ffsl.c",
"libc-top-half/musl/src/misc/ffsll.c",
"libc-top-half/musl/src/misc/fmtmsg.c",
"libc-top-half/musl/src/misc/getdomainname.c",
"libc-top-half/musl/src/misc/gethostid.c",
"libc-top-half/musl/src/misc/getopt.c",
"libc-top-half/musl/src/misc/getopt_long.c",
"libc-top-half/musl/src/misc/getsubopt.c",
"libc-top-half/musl/src/misc/uname.c",
"libc-top-half/musl/src/misc/nftw.c",
"libc-top-half/musl/src/errno/strerror.c",
"libc-top-half/musl/src/network/htonl.c",
"libc-top-half/musl/src/network/htons.c",
"libc-top-half/musl/src/network/ntohl.c",
"libc-top-half/musl/src/network/ntohs.c",
"libc-top-half/musl/src/network/inet_ntop.c",
"libc-top-half/musl/src/network/inet_pton.c",
"libc-top-half/musl/src/network/inet_aton.c",
"libc-top-half/musl/src/network/in6addr_any.c",
"libc-top-half/musl/src/network/in6addr_loopback.c",
"libc-top-half/musl/src/fenv/fenv.c",
"libc-top-half/musl/src/fenv/fesetround.c",
"libc-top-half/musl/src/fenv/feupdateenv.c",
"libc-top-half/musl/src/fenv/fesetexceptflag.c",
"libc-top-half/musl/src/fenv/fegetexceptflag.c",
"libc-top-half/musl/src/fenv/feholdexcept.c",
"libc-top-half/musl/src/exit/exit.c",
"libc-top-half/musl/src/exit/atexit.c",
"libc-top-half/musl/src/exit/assert.c",
"libc-top-half/musl/src/exit/quick_exit.c",
"libc-top-half/musl/src/exit/at_quick_exit.c",
"libc-top-half/musl/src/time/strftime.c",
"libc-top-half/musl/src/time/asctime.c",
"libc-top-half/musl/src/time/asctime_r.c",
"libc-top-half/musl/src/time/ctime.c",
"libc-top-half/musl/src/time/ctime_r.c",
"libc-top-half/musl/src/time/wcsftime.c",
"libc-top-half/musl/src/time/strptime.c",
"libc-top-half/musl/src/time/difftime.c",
"libc-top-half/musl/src/time/timegm.c",
"libc-top-half/musl/src/time/ftime.c",
"libc-top-half/musl/src/time/gmtime.c",
"libc-top-half/musl/src/time/gmtime_r.c",
"libc-top-half/musl/src/time/timespec_get.c",
"libc-top-half/musl/src/time/getdate.c",
"libc-top-half/musl/src/time/localtime.c",
"libc-top-half/musl/src/time/localtime_r.c",
"libc-top-half/musl/src/time/mktime.c",
"libc-top-half/musl/src/time/__tm_to_secs.c",
"libc-top-half/musl/src/time/__month_to_secs.c",
"libc-top-half/musl/src/time/__secs_to_tm.c",
"libc-top-half/musl/src/time/__year_to_secs.c",
"libc-top-half/musl/src/time/__tz.c",
"libc-top-half/musl/src/fcntl/creat.c",
"libc-top-half/musl/src/dirent/alphasort.c",
"libc-top-half/musl/src/dirent/versionsort.c",
"libc-top-half/musl/src/env/__stack_chk_fail.c",
"libc-top-half/musl/src/env/clearenv.c",
"libc-top-half/musl/src/env/getenv.c",
"libc-top-half/musl/src/env/putenv.c",
"libc-top-half/musl/src/env/setenv.c",
"libc-top-half/musl/src/env/unsetenv.c",
"libc-top-half/musl/src/unistd/posix_close.c",
"libc-top-half/musl/src/stat/futimesat.c",
"libc-top-half/musl/src/legacy/getpagesize.c",
"libc-top-half/musl/src/thread/thrd_sleep.c",
}
basepath := goenv.Get("TINYGOROOT") + "/lib/wasi-libc/"
for _, pattern := range globs {
matches, err := filepath.Glob(basepath + pattern.glob)
if err != nil {
// From the documentation:
// > Glob ignores file system errors such as I/O errors reading
// > directories. The only possible returned error is
// > ErrBadPattern, when pattern is malformed.
// So the only possible error is when the (statically defined)
// pattern is wrong. In other words, a programming bug.
return nil, fmt.Errorf("wasi-libc: could not glob source dirs: %w", err)
}
if len(matches) == 0 {
return nil, fmt.Errorf("wasi-libc: did not find any files for pattern %#v", pattern)
}
excludeSet := map[string]struct{}{}
for _, exclude := range pattern.exclude {
excludeSet[exclude] = struct{}{}
}
for _, match := range matches {
if _, ok := excludeSet[filepath.Base(match)]; ok {
continue
}
relpath, err := filepath.Rel(basepath, match)
if err != nil {
// Not sure if this is even possible.
return nil, err
}
sources = append(sources, relpath)
}
}
return sources, nil
},
}
+3 -1
View File
@@ -29,6 +29,8 @@ var libWasmBuiltins = Library{
"-Wall",
"-std=gnu11",
"-nostdlibinc",
"-mnontrapping-fptoint", // match wasm-unknown (default on in LLVM 20)
"-mno-bulk-memory", // same here
"-isystem", libcDir + "/libc-top-half/musl/arch/wasm32",
"-isystem", libcDir + "/libc-top-half/musl/arch/generic",
"-isystem", libcDir + "/libc-top-half/musl/src/internal",
@@ -39,7 +41,7 @@ var libWasmBuiltins = Library{
}
},
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc") },
librarySources: func(target string) ([]string, error) {
librarySources: func(target string, _ bool) ([]string, error) {
return []string{
// memory builtins needed for llvm.memcpy.*, llvm.memmove.*, and
// llvm.memset.* LLVM intrinsics.
+5 -1
View File
@@ -21,6 +21,10 @@ import (
)
/*
// Hide a warning in LLVM 21 that doesn't apply to us (appears to be a side
// effect of how CGo processes C header files).
#cgo CFLAGS: -Wno-deprecated-declarations
#include <clang-c/Index.h> // If this fails, libclang headers aren't available. Please take a look here: https://tinygo.org/docs/guides/build/
#include <llvm/Config/llvm-config.h>
#include <stdlib.h>
@@ -71,7 +75,7 @@ unsigned tinygo_clang_Cursor_isMacroFunctionLike(GoCXCursor c);
// libclang.go:68:5: note: previous declaration is here
// See: https://github.com/golang/go/issues/49721
#if defined(_WIN32)
#define CGO_DECL // __declspec(dllexport)
#define CGO_DECL __declspec(dllexport)
#else
#define CGO_DECL
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build !byollvm && !llvm15 && !llvm16 && !llvm17 && !llvm18
//go:build !byollvm && llvm19
package cgo
+15
View File
@@ -0,0 +1,15 @@
//go:build !byollvm && llvm20
package cgo
/*
#cgo linux CFLAGS: -I/usr/include/llvm-20 -I/usr/include/llvm-c-20 -I/usr/lib/llvm-20/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@20/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@20/include
#cgo freebsd CFLAGS: -I/usr/local/llvm20/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-20/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@20/lib -lclang
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@20/lib -lclang
#cgo freebsd LDFLAGS: -L/usr/local/llvm20/lib -lclang
*/
import "C"
+15
View File
@@ -0,0 +1,15 @@
//go:build !byollvm && !llvm15 && !llvm16 && !llvm17 && !llvm18 && !llvm19 && !llvm20
package cgo
/*
#cgo linux CFLAGS: -I/usr/include/llvm-21 -I/usr/include/llvm-c-21 -I/usr/lib/llvm-21/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@21/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@21/include
#cgo freebsd CFLAGS: -I/usr/local/llvm21/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-21/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@21/lib -lclang
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@21/lib -lclang
#cgo freebsd LDFLAGS: -L/usr/local/llvm21/lib -lclang
*/
import "C"
+118 -65
View File
@@ -8,12 +8,24 @@ import (
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"github.com/google/shlex"
"github.com/tinygo-org/tinygo/goenv"
)
// Library versions. Whenever an existing library is changed, this number should
// be added/increased so that existing caches are invalidated.
//
// (This is a bit of a layering violation, this should really be part of the
// builder.Library struct but that's hard to do since we want to know the
// library path in advance in several places).
var libVersions = map[string]int{
"musl": 3,
"bdwgc": 2,
}
// Config keeps all configuration affecting the build in a single struct.
type Config struct {
Options *Options
@@ -99,6 +111,11 @@ func (c *Config) BuildTags() []string {
"math_big_pure_go", // to get math/big to work
"gc." + c.GC(), "scheduler." + c.Scheduler(), // used inside the runtime package
"serial." + c.Serial()}...) // used inside the machine package
switch c.Scheduler() {
case "threads", "cores":
default:
tags = append(tags, "tinygo.unicore")
}
for i := 1; i <= c.GoMinorVersion; i++ {
tags = append(tags, fmt.Sprintf("go1.%d", i))
}
@@ -122,7 +139,7 @@ func (c *Config) GC() string {
// that can be traced by the garbage collector.
func (c *Config) NeedsStackObjects() bool {
switch c.GC() {
case "conservative", "custom", "precise":
case "conservative", "custom", "precise", "boehm":
for _, tag := range c.BuildTags() {
if tag == "tinygo.wasm" {
return true
@@ -247,10 +264,18 @@ func MuslArchitecture(triple string) string {
return CanonicalArchName(triple)
}
// LibcPath returns the path to the libc directory. The libc path will be either
// a precompiled libc shipped with a TinyGo build, or a libc path in the cache
// directory (which might not yet be built).
func (c *Config) LibcPath(name string) (path string, precompiled bool) {
// Returns true if the libc needs to include malloc, for the libcs where this
// matters.
func (c *Config) LibcNeedsMalloc() bool {
if c.GC() == "boehm" && c.Target.Libc == "wasi-libc" {
return true
}
return false
}
// LibraryPath returns the path to the library build directory. The path will be
// a library path in the cache directory (which might not yet be built).
func (c *Config) LibraryPath(name string) string {
archname := c.Triple()
if c.CPU() != "" {
archname += "-" + c.CPU()
@@ -261,18 +286,24 @@ func (c *Config) LibcPath(name string) (path string, precompiled bool) {
if c.Target.SoftFloat {
archname += "-softfloat"
}
if name == "bdwgc" {
// Boehm GC is compiled against a particular libc.
archname += "-" + c.Target.Libc
}
// Try to load a precompiled library.
precompiledDir := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", archname, name)
if _, err := os.Stat(precompiledDir); err == nil {
// Found a precompiled library for this OS/architecture. Return the path
// directly.
return precompiledDir, true
// Append a version string, if this library has a version.
if v, ok := libVersions[name]; ok {
archname += "-v" + strconv.Itoa(v)
}
options := ""
if c.LibcNeedsMalloc() {
options += "+malloc"
}
// No precompiled library found. Determine the path name that will be used
// in the build cache.
return filepath.Join(goenv.Get("GOCACHE"), name+"-"+archname), false
return filepath.Join(goenv.Get("GOCACHE"), name+options+"-"+archname)
}
// DefaultBinaryExtension returns the default extension for binaries, such as
@@ -315,59 +346,7 @@ func (c *Config) CFlags(libclang bool) []string {
"-resource-dir="+resourceDir,
)
}
switch c.Target.Libc {
case "darwin-libSystem":
root := goenv.Get("TINYGOROOT")
cflags = append(cflags,
"-nostdlibinc",
"-isystem", filepath.Join(root, "lib/macos-minimal-sdk/src/usr/include"),
)
case "picolibc":
root := goenv.Get("TINYGOROOT")
picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc")
path, _ := c.LibcPath("picolibc")
cflags = append(cflags,
"-nostdlibinc",
"-isystem", filepath.Join(path, "include"),
"-isystem", filepath.Join(picolibcDir, "include"),
"-isystem", filepath.Join(picolibcDir, "tinystdio"),
"-D__PICOLIBC_ERRNO_FUNCTION=__errno_location",
)
case "musl":
root := goenv.Get("TINYGOROOT")
path, _ := c.LibcPath("musl")
arch := MuslArchitecture(c.Triple())
cflags = append(cflags,
"-nostdlibinc",
"-isystem", filepath.Join(path, "include"),
"-isystem", filepath.Join(root, "lib", "musl", "arch", arch),
"-isystem", filepath.Join(root, "lib", "musl", "arch", "generic"),
"-isystem", filepath.Join(root, "lib", "musl", "include"),
)
case "wasi-libc":
root := goenv.Get("TINYGOROOT")
cflags = append(cflags,
"-nostdlibinc",
"-isystem", root+"/lib/wasi-libc/sysroot/include")
case "wasmbuiltins":
// nothing to add (library is purely for builtins)
case "mingw-w64":
root := goenv.Get("TINYGOROOT")
path, _ := c.LibcPath("mingw-w64")
cflags = append(cflags,
"-nostdlibinc",
"-isystem", filepath.Join(path, "include"),
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "crt"),
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "defaults", "include"),
"-D_UCRT",
)
case "":
// No libc specified, nothing to add.
default:
// Incorrect configuration. This could be handled in a better way, but
// usually this will be found by developers (not by TinyGo users).
panic("unknown libc: " + c.Target.Libc)
}
cflags = append(cflags, c.LibcCFlags()...)
// Always emit debug information. It is optionally stripped at link time.
cflags = append(cflags, "-gdwarf-4")
// Use the same optimization level as TinyGo.
@@ -394,6 +373,80 @@ func (c *Config) CFlags(libclang bool) []string {
return cflags
}
// LibcCFlags returns the C compiler flags for the configured libc.
// It only uses flags that are part of the libc path (triple, cpu, abi, libc
// name) so it can safely be used to compile another C library.
func (c *Config) LibcCFlags() []string {
switch c.Target.Libc {
case "darwin-libSystem":
root := goenv.Get("TINYGOROOT")
return []string{
"-nostdlibinc",
"-isystem", filepath.Join(root, "lib/macos-minimal-sdk/src/usr/include"),
}
case "picolibc":
root := goenv.Get("TINYGOROOT")
picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc")
path := c.LibraryPath("picolibc")
return []string{
"-nostdlibinc",
"-isystem", filepath.Join(path, "include"),
"-isystem", filepath.Join(picolibcDir, "include"),
"-isystem", filepath.Join(picolibcDir, "tinystdio"),
"-D__PICOLIBC_ERRNO_FUNCTION=__errno_location",
}
case "musl":
root := goenv.Get("TINYGOROOT")
path := c.LibraryPath("musl")
arch := MuslArchitecture(c.Triple())
return []string{
"-nostdlibinc",
"-isystem", filepath.Join(path, "include"),
"-isystem", filepath.Join(root, "lib", "musl", "arch", arch),
"-isystem", filepath.Join(root, "lib", "musl", "arch", "generic"),
"-isystem", filepath.Join(root, "lib", "musl", "include"),
}
case "wasi-libc":
path := c.LibraryPath("wasi-libc")
return []string{
"-nostdlibinc",
"-isystem", filepath.Join(path, "include"),
}
case "wasmbuiltins":
// nothing to add (library is purely for builtins)
return nil
case "mingw-w64":
root := goenv.Get("TINYGOROOT")
path := c.LibraryPath("mingw-w64")
cflags := []string{
"-nostdlibinc",
"-isystem", filepath.Join(path, "include"),
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "crt"),
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "include"),
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "defaults", "include"),
}
if c.GOARCH() == "386" {
cflags = append(cflags,
"-D__MSVCRT_VERSION__=0x700", // Microsoft Visual C++ .NET 2002
"-D_WIN32_WINNT=0x0501", // target Windows XP
)
} else {
cflags = append(cflags,
"-D_UCRT",
"-D_WIN32_WINNT=0x0a00", // target Windows 10
)
}
return cflags
case "":
// No libc specified, nothing to add.
return nil
default:
// Incorrect configuration. This could be handled in a better way, but
// usually this will be found by developers (not by TinyGo users).
panic("unknown libc: " + c.Target.Libc)
}
}
// LDFlags returns the flags to pass to the linker. A few more flags are needed
// (like the one for the compiler runtime), but this represents the majority of
// the flags.
+3 -3
View File
@@ -9,8 +9,8 @@ import (
var (
validBuildModeOptions = []string{"default", "c-shared", "wasi-legacy"}
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise", "boehm"}
validSchedulerOptions = []string{"none", "tasks", "asyncify", "threads", "cores"}
validSerialOptions = []string{"none", "uart", "usb", "rtt"}
validPrintSizeOptions = []string{"none", "short", "full", "html"}
validPanicStrategyOptions = []string{"print", "trap"}
@@ -43,6 +43,7 @@ type Options struct {
PrintCommands func(cmd string, args ...string) `json:"-"`
Semaphore chan struct{} `json:"-"` // -p flag controls cap
Debug bool
Nobounds bool
PrintSizes string
PrintAllocs *regexp.Regexp // regexp string
PrintStacks bool
@@ -52,7 +53,6 @@ type Options struct {
Programmer string
OpenOCDCommands []string
LLVMFeatures string
PrintJSON bool
Monitor bool
BaudRate int
Timeout time.Duration
+2 -2
View File
@@ -9,8 +9,8 @@ import (
func TestVerifyOptions(t *testing.T) {
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, conservative, custom, precise`)
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, asyncify`)
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, conservative, custom, precise, boehm`)
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, asyncify, threads, cores`)
expectedPrintSizeError := errors.New(`invalid size option 'incorrect': valid values are none, short, full, html`)
expectedPanicStrategyError := errors.New(`invalid panic option 'incorrect': valid values are print, trap`)
+44 -9
View File
@@ -178,6 +178,21 @@ func (spec *TargetSpec) resolveInherits() error {
// Load a target specification.
func LoadTarget(options *Options) (*TargetSpec, error) {
if options.Target == "" && options.GOARCH == "wasm" {
// Set a specific target if we're building from a known GOOS/GOARCH
// combination that is defined in a target JSON file.
switch options.GOOS {
case "js":
options.Target = "wasm"
case "wasip1":
options.Target = "wasip1"
case "wasip2":
options.Target = "wasip2"
default:
return nil, errors.New("GOARCH=wasm but GOOS is not set correctly. Please set GOOS to js, wasip1, or wasip2.")
}
}
if options.Target == "" {
return defaultTarget(options)
}
@@ -247,8 +262,6 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
GOOS: options.GOOS,
GOARCH: options.GOARCH,
BuildTags: []string{options.GOOS, options.GOARCH},
GC: "precise",
Scheduler: "tasks",
Linker: "cc",
DefaultStackSize: 1024 * 64, // 64kB
GDB: []string{"gdb"},
@@ -356,7 +369,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
return nil, fmt.Errorf("invalid GOMIPS=%s: must be hardfloat or softfloat", options.GOMIPS)
}
case "wasm":
return nil, fmt.Errorf("GOARCH=wasm but GOOS is unset. Please set GOOS to wasm, wasip1, or wasip2.")
return nil, fmt.Errorf("GOARCH=wasm but GOOS is unset. Please set GOOS to js, wasip1, or wasip2.")
default:
return nil, fmt.Errorf("unknown GOARCH=%s", options.GOARCH)
}
@@ -366,11 +379,13 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
llvmvendor := "unknown"
switch options.GOOS {
case "darwin":
spec.GC = "boehm"
platformVersion := "10.12.0"
if options.GOARCH == "arm64" {
platformVersion = "11.0.0" // first macosx platform with arm64 support
}
llvmvendor = "apple"
spec.Scheduler = "threads"
spec.Linker = "ld.lld"
spec.Libc = "darwin-libSystem"
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer to
@@ -384,10 +399,13 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
)
spec.ExtraFiles = append(spec.ExtraFiles,
"src/internal/futex/futex_darwin.c",
"src/internal/task/task_threads.c",
"src/runtime/os_darwin.c",
"src/runtime/runtime_unix.c",
"src/runtime/signal.c")
case "linux":
spec.GC = "boehm"
spec.Scheduler = "threads"
spec.Linker = "ld.lld"
spec.RTLib = "compiler-rt"
spec.Libc = "musl"
@@ -408,19 +426,30 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
}
spec.ExtraFiles = append(spec.ExtraFiles,
"src/internal/futex/futex_linux.c",
"src/internal/task/task_threads.c",
"src/runtime/runtime_unix.c",
"src/runtime/signal.c")
case "windows":
spec.GC = "boehm"
spec.Scheduler = "tasks"
spec.Linker = "ld.lld"
spec.Libc = "mingw-w64"
// Note: using a medium code model, low image base and no ASLR
// because Go doesn't really need those features. ASLR patches
// around issues for unsafe languages like C/C++ that are not
// normally present in Go (without explicitly opting in).
// For more discussion:
// https://groups.google.com/g/Golang-nuts/c/Jd9tlNc6jUE/m/Zo-7zIP_m3MJ?pli=1
switch options.GOARCH {
case "386":
spec.LDFlags = append(spec.LDFlags,
"-m", "i386pe",
"--major-os-version", "4",
"--major-subsystem-version", "4",
)
// __udivdi3 is not present in ucrt it seems.
spec.RTLib = "compiler-rt"
case "amd64":
// Note: using a medium code model, low image base and no ASLR
// because Go doesn't really need those features. ASLR patches
// around issues for unsafe languages like C/C++ that are not
// normally present in Go (without explicitly opting in).
// For more discussion:
// https://groups.google.com/g/Golang-nuts/c/Jd9tlNc6jUE/m/Zo-7zIP_m3MJ?pli=1
spec.LDFlags = append(spec.LDFlags,
"-m", "i386pep",
"--image-base", "0x400000",
@@ -442,6 +471,12 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
return nil, fmt.Errorf("unknown GOOS=%s", options.GOOS)
}
if spec.GC == "boehm" {
// Add this file only when needed. This fixes a build failure on
// Windows.
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/gc_boehm.c")
}
// Target triples (which actually have four components, but are called
// triples for historical reasons) have the form:
// arch-vendor-os-environment
+9 -1
View File
@@ -76,7 +76,15 @@ func (b *builder) createCall(fnType llvm.Type, fn llvm.Value, args []llvm.Value,
fragments := b.expandFormalParam(arg)
expanded = append(expanded, fragments...)
}
return b.CreateCall(fnType, fn, expanded, name)
call := b.CreateCall(fnType, fn, expanded, name)
if !fn.IsAFunction().IsNil() {
if cc := fn.FunctionCallConv(); cc != llvm.CCallConv {
// Set a different calling convention if needed.
// This is needed for GetModuleHandleExA on Windows, for example.
call.SetInstructionCallConv(cc)
}
}
return call
}
// createInvoke is like createCall but continues execution at the landing pad if
+47 -10
View File
@@ -58,6 +58,7 @@ type Config struct {
MaxStackAlloc uint64
NeedsStackObjects bool
Debug bool // Whether to emit debug information in the LLVM module.
Nobounds bool // Whether to skip bounds checks
PanicStrategy string
}
@@ -83,6 +84,7 @@ type compilerContext struct {
funcPtrType llvm.Type // pointer in function address space (1 for AVR, 0 elsewhere)
funcPtrAddrSpace int
uintptrType llvm.Type
nocaptureAttr llvm.Attribute
program *ssa.Program
diagnostics []error
functionInfos map[*ssa.Function]functionInfo
@@ -134,6 +136,13 @@ func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *C
c.funcPtrType = dummyFunc.Type()
dummyFunc.EraseFromParentAsFunction()
// The attribute "nocapture" changed to "captures(none)" in LLVM 21.
if llvmutil.Version() < 21 {
c.nocaptureAttr = c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)
} else {
c.nocaptureAttr = c.ctx.CreateEnumAttribute(llvm.AttributeKindID("captures"), 0)
}
return c
}
@@ -388,7 +397,7 @@ func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type {
// makeLLVMType creates a LLVM type for a Go type. Don't call this, use
// getLLVMType instead.
func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type {
switch typ := goType.(type) {
switch typ := types.Unalias(goType).(type) {
case *types.Array:
elemType := c.getLLVMType(typ.Elem())
return llvm.ArrayType(elemType, int(typ.Len()))
@@ -496,6 +505,21 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
llvmType := c.getLLVMType(typ)
sizeInBytes := c.targetData.TypeAllocSize(llvmType)
switch typ := typ.(type) {
case *types.Alias:
// Implement types.Alias just like types.Named: by treating them like a
// C typedef.
temporaryMDNode := c.dibuilder.CreateReplaceableCompositeType(llvm.Metadata{}, llvm.DIReplaceableCompositeType{
Tag: dwarf.TagTypedef,
SizeInBits: sizeInBytes * 8,
AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
})
c.ditypes[typ] = temporaryMDNode
md := c.dibuilder.CreateTypedef(llvm.DITypedef{
Type: c.getDIType(types.Unalias(typ)), // TODO: use typ.Rhs in Go 1.23
Name: typ.String(),
})
temporaryMDNode.ReplaceAllUsesWith(md)
return md
case *types.Array:
return c.dibuilder.CreateArrayType(llvm.DIArrayType{
SizeInBits: sizeInBytes * 8,
@@ -858,6 +882,11 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
// Interfaces don't have concrete methods.
continue
}
if _, isalias := member.Type().(*types.Alias); isalias {
// Aliases don't need to be redefined, since they just refer to
// an already existing type whose methods will be defined.
continue
}
// Named type. We should make sure all methods are created.
// This includes both functions with pointer receivers and those
@@ -1835,15 +1864,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
//
// This is also where compiler intrinsics are implemented.
func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error) {
var params []llvm.Value
for _, param := range instr.Args {
params = append(params, b.getValue(param, getPos(instr)))
}
// Try to call the function directly for trivially static calls.
var callee, context llvm.Value
var calleeType llvm.Type
exported := false
// See if this is an intrinsic function that is handled specially.
if fn := instr.StaticCallee(); fn != nil {
// Direct function call, either to a named or anonymous (directly
// applied) function call. If it is anonymous, it may be a closure.
@@ -1879,13 +1900,29 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
return llvm.ConstInt(b.ctx.Int8Type(), panicStrategy, false), nil
case name == "runtime/interrupt.New":
return b.createInterruptGlobal(instr)
case name == "runtime.exportedFuncPtr":
_, ptr := b.getFunction(instr.Args[0].(*ssa.Function))
return b.CreatePtrToInt(ptr, b.uintptrType, ""), nil
case name == "(*runtime/interrupt.Checkpoint).Save":
return b.createInterruptCheckpoint(instr.Args[0]), nil
case name == "internal/abi.FuncPCABI0":
retval := b.createDarwinFuncPCABI0Call(instr)
if !retval.IsNil() {
return retval, nil
}
}
}
var params []llvm.Value
for _, param := range instr.Args {
params = append(params, b.getValue(param, getPos(instr)))
}
// Try to call the function directly for trivially static calls.
var callee, context llvm.Value
var calleeType llvm.Type
exported := false
if fn := instr.StaticCallee(); fn != nil {
calleeType, callee = b.getFunction(fn)
info := b.getFunctionInfo(fn)
if callee.IsNil() {
+15 -6
View File
@@ -103,10 +103,11 @@ func (b *builder) createLandingPad() {
b.CreateBr(b.blockEntries[b.fn.Recover])
}
// createInvokeCheckpoint saves the function state at the given point, to
// continue at the landing pad if a panic happened. This is implemented using a
// setjmp-like construct.
func (b *builder) createInvokeCheckpoint() {
// Create a checkpoint (similar to setjmp). This emits inline assembly that
// stores the current program counter inside the ptr address (actually
// ptr+sizeof(ptr)) and then returns a boolean indicating whether this is the
// normal flow (false) or we jumped here from somewhere else (true).
func (b *builder) createCheckpoint(ptr llvm.Value) llvm.Value {
// Construct inline assembly equivalents of setjmp.
// The assembly works as follows:
// * All registers (both callee-saved and caller saved) are clobbered
@@ -217,11 +218,19 @@ li a0, 0
// This case should have been handled by b.supportsRecover().
b.addError(b.fn.Pos(), "unknown architecture for defer: "+b.archFamily())
}
asmType := llvm.FunctionType(resultType, []llvm.Type{b.deferFrame.Type()}, false)
asmType := llvm.FunctionType(resultType, []llvm.Type{b.dataPtrType}, false)
asm := llvm.InlineAsm(asmType, asmString, constraints, false, false, 0, false)
result := b.CreateCall(asmType, asm, []llvm.Value{b.deferFrame}, "setjmp")
result := b.CreateCall(asmType, asm, []llvm.Value{ptr}, "setjmp")
result.AddCallSiteAttribute(-1, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("returns_twice"), 0))
isZero := b.CreateICmp(llvm.IntEQ, result, llvm.ConstInt(resultType, 0, false), "setjmp.result")
return isZero
}
// createInvokeCheckpoint saves the function state at the given point, to
// continue at the landing pad if a panic happened. This is implemented using a
// setjmp-like construct.
func (b *builder) createInvokeCheckpoint() {
isZero := b.createCheckpoint(b.deferFrame)
continueBB := b.insertBasicBlock("")
b.CreateCondBr(isZero, continueBB, b.landingpad)
b.SetInsertPointAtEnd(continueBB)
+12
View File
@@ -249,3 +249,15 @@ func (b *builder) emitCSROperation(call *ssa.CallCommon) (llvm.Value, error) {
return llvm.Value{}, b.makeError(call.Pos(), "unknown CSR operation: "+name)
}
}
// Implement runtime/interrupt.Checkpoint.Save. It needs to be implemented
// directly at the call site. If it isn't implemented directly at the call site
// (but instead through a function call), it might result in an overwritten
// stack in the non-jump return case.
func (b *builder) createInterruptCheckpoint(ptr ssa.Value) llvm.Value {
addr := b.getValue(ptr, ptr.Pos())
b.createNilCheck(ptr, addr, "deref")
stackPointer := b.readStackPointer()
b.CreateStore(stackPointer, addr)
return b.createCheckpoint(addr)
}
+5 -2
View File
@@ -122,6 +122,9 @@ func (c *compilerContext) pkgPathPtr(pkgpath string) llvm.Value {
// This function returns a pointer to the 'kind' field (which might not be the
// first field in the struct).
func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
// Resolve alias types: alias types are resolved at compile time.
typ = types.Unalias(typ)
ms := c.program.MethodSets.MethodSet(typ)
hasMethodSet := ms.Len() != 0
_, isInterface := typ.Underlying().(*types.Interface)
@@ -512,7 +515,7 @@ var basicTypeNames = [...]string{
// interface lowering pass to assign type codes as expected by the reflect
// package. See getTypeCodeNum.
func getTypeCodeName(t types.Type) (string, bool) {
switch t := t.(type) {
switch t := types.Unalias(t).(type) {
case *types.Named:
if t.Obj().Parent() != t.Obj().Pkg().Scope() {
return "named:" + t.String() + "$local", true
@@ -942,7 +945,7 @@ func signature(sig *types.Signature) string {
// normalization around `byte` vs `uint8` for example.
func typestring(t types.Type) string {
// See: https://github.com/golang/go/blob/master/src/go/types/typestring.go
switch t := t.(type) {
switch t := types.Unalias(t).(type) {
case *types.Array:
return "[" + strconv.FormatInt(t.Len(), 10) + "]" + typestring(t.Elem())
case *types.Basic:
+23
View File
@@ -121,6 +121,29 @@ func (b *builder) createKeepAliveImpl() {
b.CreateRetVoid()
}
// createAbiEscapeImpl implements the generic internal/abi.Escape function. It
// currently only supports pointer types.
func (b *builder) createAbiEscapeImpl() {
b.createFunctionStart(true)
// The first parameter is assumed to be a pointer. This is checked at the
// call site of createAbiEscapeImpl.
pointerValue := b.getValue(b.fn.Params[0], getPos(b.fn))
// Create an equivalent of the following C code, which is basically just a
// nop but ensures the pointerValue is kept alive:
//
// __asm__ __volatile__("" : : "r"(pointerValue))
//
// It should be portable to basically everything as the "r" register type
// exists basically everywhere.
asmType := llvm.FunctionType(b.dataPtrType, []llvm.Type{b.dataPtrType}, false)
asmFn := llvm.InlineAsm(asmType, "", "=r,0", true, false, 0, false)
result := b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
b.CreateRet(result)
}
var mathToLLVMMapping = map[string]string{
"math.Ceil": "llvm.ceil.f64",
"math.Exp": "llvm.exp.f64",
+15 -7
View File
@@ -371,13 +371,6 @@ func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.In
return big.NewInt(1)
case llvm.StructTypeKind:
ptrs := big.NewInt(0)
if typ.StructName() == "runtime.funcValue" {
// Hack: the type runtime.funcValue contains an 'id' field which is
// of type uintptr, but before the LowerFuncValues pass it actually
// contains a pointer (ptrtoint) to a global. This trips up the
// interp package. Therefore, make the id field a pointer for now.
typ = c.ctx.StructType([]llvm.Type{c.dataPtrType, c.dataPtrType}, false)
}
for i, subtyp := range typ.StructElementTypes() {
subptrs := c.getPointerBitmap(subtyp, pos)
if subptrs.BitLen() == 0 {
@@ -459,6 +452,21 @@ func (b *builder) readStackPointer() llvm.Value {
return b.CreateCall(stacksave.GlobalValueType(), stacksave, nil, "")
}
// writeStackPointer emits a LLVM intrinsic call that updates the current stack
// pointer.
func (b *builder) writeStackPointer(sp llvm.Value) {
name := "llvm.stackrestore.p0"
if llvmutil.Version() < 18 {
name = "llvm.stackrestore" // backwards compatibility with LLVM 17 and below
}
stackrestore := b.mod.NamedFunction(name)
if stackrestore.IsNil() {
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.dataPtrType}, false)
stackrestore = llvm.AddFunction(b.mod, name, fnType)
}
b.CreateCall(stackrestore.GlobalValueType(), stackrestore, []llvm.Value{sp}, "")
}
// createZExtOrTrunc lets the input value fit in the output type bits, by zero
// extending or truncating the integer.
func (b *builder) createZExtOrTrunc(value llvm.Value, t llvm.Type) llvm.Value {
+1 -1
View File
@@ -218,7 +218,7 @@ func Version() int {
return major
}
// Return the byte order for the given target triple. Most targets are little
// ByteOrder returns the byte order for the given target triple. Most targets are little
// endian, but for example MIPS can be big-endian.
func ByteOrder(target string) binary.ByteOrder {
if strings.HasPrefix(target, "mips-") {
+1 -3
View File
@@ -248,7 +248,7 @@ func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llv
// can be compared with runtime.memequal. Note that padding bytes are undef
// and can alter two "equal" structs being equal when compared with memequal.
func hashmapIsBinaryKey(keyType types.Type) bool {
switch keyType := keyType.(type) {
switch keyType := keyType.Underlying().(type) {
case *types.Basic:
return keyType.Info()&(types.IsBoolean|types.IsInteger) != 0
case *types.Pointer:
@@ -263,8 +263,6 @@ func hashmapIsBinaryKey(keyType types.Type) bool {
return true
case *types.Array:
return hashmapIsBinaryKey(keyType.Elem())
case *types.Named:
return hashmapIsBinaryKey(keyType.Underlying())
default:
return false
}
+51 -16
View File
@@ -139,8 +139,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
// not.
// (It may be safe to add the nocapture parameter to the context
// parameter, but I'd like to stay on the safe side here).
nocapture := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0)
llvmFn.AddAttributeAtIndex(i+1, nocapture)
llvmFn.AddAttributeAtIndex(i+1, c.nocaptureAttr)
}
}
@@ -153,7 +152,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
// Mark it as noreturn so LLVM can optimize away code.
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("noreturn"), 0))
case "internal/abi.NoEscape":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(1, c.nocaptureAttr)
case "runtime.alloc":
// Tell the optimizer that runtime.alloc is an allocator, meaning that it
// returns values that are never null and never alias to an existing value.
@@ -175,25 +174,25 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
case "runtime.sliceAppend":
// Appending a slice will only read the to-be-appended slice, it won't
// be modified.
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(2, c.nocaptureAttr)
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
case "runtime.sliceCopy":
// Copying a slice won't capture any of the parameters.
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("writeonly"), 0))
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(1, c.nocaptureAttr)
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(2, c.nocaptureAttr)
case "runtime.stringFromBytes":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(1, c.nocaptureAttr)
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
case "runtime.stringFromRunes":
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(1, c.nocaptureAttr)
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
case "runtime.trackPointer":
// This function is necessary for tracking pointers on the stack in a
// portable way (see gc_stack_portable.go). Indicate to the optimizer
// that the only thing we'll do is read the pointer.
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(1, c.nocaptureAttr)
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
case "__mulsi3", "__divmodsi4", "__udivmodsi4":
if strings.Split(c.Triple, "-")[0] == "avr" {
@@ -208,6 +207,12 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
// > circumstances, and should not be exposed to source languages.
llvmutil.AppendToGlobal(c.mod, "llvm.compiler.used", llvmFn)
}
case "GetModuleHandleExA", "GetProcAddress", "GetSystemInfo", "GetSystemTimeAsFileTime", "LoadLibraryExW", "QueryPerformanceCounter", "QueryPerformanceFrequency", "QueryUnbiasedInterruptTime", "SetEnvironmentVariableA", "Sleep", "SystemFunction036", "VirtualAlloc":
// On Windows we need to use a special calling convention for some
// external calls.
if c.GOOS == "windows" && c.GOARCH == "386" {
llvmFn.SetFunctionCallConv(llvm.X86StdcallCallConv)
}
}
// External/exported functions may not retain pointer values.
@@ -222,11 +227,9 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", info.wasmName))
}
nocaptureKind := llvm.AttributeKindID("nocapture")
nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
for i, typ := range paramTypes {
if typ.TypeKind() == llvm.PointerTypeKind {
llvmFn.AddAttributeAtIndex(i+1, nocapture)
llvmFn.AddAttributeAtIndex(i+1, c.nocaptureAttr)
}
}
}
@@ -247,6 +250,23 @@ func (c *compilerContext) maybeCreateSyntheticFunction(fn *ssa.Function, llvmFn
// The exception is the package initializer, which does appear in the
// *ssa.Package members and so shouldn't be created here.
if fn.Synthetic != "" && fn.Synthetic != "package initializer" && fn.Synthetic != "generic function" && fn.Synthetic != "range-over-func yield" {
if origin := fn.Origin(); origin != nil && origin.RelString(nil) == "internal/abi.Escape" {
// This is a special implementation or internal/abi.Escape, which
// can only really be implemented in the compiler.
// For simplicity we'll only implement pointer parameters for now.
if _, ok := fn.Params[0].Type().Underlying().(*types.Pointer); ok {
irbuilder := c.ctx.NewBuilder()
defer irbuilder.Dispose()
b := newBuilder(c, irbuilder, fn)
b.createAbiEscapeImpl()
llvmFn.SetLinkage(llvm.LinkOnceODRLinkage)
llvmFn.SetUnnamedAddr(true)
}
// If the parameter is not of a pointer type, it will be left
// unimplemented. This will result in a linker error if the function
// is really called, making it clear it needs to be implemented.
return
}
if len(fn.Blocks) == 0 {
c.addError(fn.Pos(), "missing function body")
return
@@ -438,6 +458,10 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
}
}
}
if c.Nobounds {
info.nobounds = true
}
}
// Check whether this function can be used in //go:wasmimport or
@@ -603,7 +627,7 @@ func (c *compilerContext) addStandardAttributes(llvmFn llvm.Value) {
// linkName is equal to .RelString(nil) on a global and extern is false, but for
// some symbols this is different (due to //go:extern for example).
type globalInfo struct {
linkName string // go:extern
linkName string // go:extern, go:linkname
extern bool // go:extern
align int // go:align
section string // go:section
@@ -688,14 +712,14 @@ func (c *compilerContext) getGlobalInfo(g *ssa.Global) globalInfo {
// Check for //go: pragmas, which may change the link name (among others).
doc := c.astComments[info.linkName]
if doc != nil {
info.parsePragmas(doc)
info.parsePragmas(doc, c, g)
}
return info
}
// Parse //go: pragma comments from the source. In particular, it parses the
// //go:extern pragma on globals.
func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
// //go:extern and //go:linkname pragmas on globals.
func (info *globalInfo) parsePragmas(doc *ast.CommentGroup, c *compilerContext, g *ssa.Global) {
for _, comment := range doc.List {
if !strings.HasPrefix(comment.Text, "//go:") {
continue
@@ -716,6 +740,17 @@ func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
if len(parts) == 2 {
info.section = parts[1]
}
case "//go:linkname":
if len(parts) != 3 || parts[1] != g.Name() {
continue
}
// Only enable go:linkname when the package imports "unsafe".
// This is a slightly looser requirement than what gc uses: gc
// requires the file to import "unsafe", not the package as a
// whole.
if hasUnsafeImport(g.Pkg.Pkg) {
info.linkName = parts[2]
}
}
}
}
+24 -1
View File
@@ -268,6 +268,8 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
// The signature looks like this:
// func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
isI386 := strings.HasPrefix(b.Triple, "i386-")
// Prepare input values.
var paramTypes []llvm.Type
var params []llvm.Value
@@ -285,11 +287,17 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
if setLastError.IsNil() {
llvmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.ctx.Int32Type()}, false)
setLastError = llvm.AddFunction(b.mod, "SetLastError", llvmType)
if isI386 {
setLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
}
}
getLastError := b.mod.NamedFunction("GetLastError")
if getLastError.IsNil() {
llvmType := llvm.FunctionType(b.ctx.Int32Type(), nil, false)
getLastError = llvm.AddFunction(b.mod, "GetLastError", llvmType)
if isI386 {
getLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
}
}
// Now do the actual call. Pseudocode:
@@ -300,9 +308,24 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
// Note that SetLastError/GetLastError could be replaced with direct
// access to the thread control block, which is probably smaller and
// faster. The Go runtime does this in assembly.
b.CreateCall(setLastError.GlobalValueType(), setLastError, []llvm.Value{llvm.ConstNull(b.ctx.Int32Type())}, "")
// On windows/386, we also need to save/restore the stack pointer. I'm
// not entirely sure why this is needed, but without it these calls
// change the stack pointer leading to a crash soon after.
setLastErrorCall := b.CreateCall(setLastError.GlobalValueType(), setLastError, []llvm.Value{llvm.ConstNull(b.ctx.Int32Type())}, "")
var sp llvm.Value
if isI386 {
setLastErrorCall.SetInstructionCallConv(llvm.X86StdcallCallConv)
sp = b.readStackPointer()
}
syscallResult := b.CreateCall(llvmType, fnPtr, params, "")
if isI386 {
syscallResult.SetInstructionCallConv(llvm.X86StdcallCallConv)
b.writeStackPointer(sp)
}
errResult := b.CreateCall(getLastError.GlobalValueType(), getLastError, nil, "err")
if isI386 {
errResult.SetInstructionCallConv(llvm.X86StdcallCallConv)
}
if b.uintptrType != b.ctx.Int32Type() {
errResult = b.CreateZExt(errResult, b.uintptrType, "err.uintptr")
}
+4 -4
View File
@@ -1,6 +1,6 @@
; ModuleID = 'basic.go'
source_filename = "basic.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
%main.kv = type { float, i32, i32, i32 }
@@ -206,7 +206,7 @@ entry:
ret void
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+7 -7
View File
@@ -1,6 +1,6 @@
; ModuleID = 'channel.go'
source_filename = "channel.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
%runtime.channelOp = type { ptr, ptr, i32, ptr }
@@ -82,11 +82,11 @@ entry:
store i32 1, ptr %select.send.value, align 4
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %select.states.alloca)
store ptr %ch1, ptr %select.states.alloca, align 4
%select.states.alloca.repack1 = getelementptr inbounds i8, ptr %select.states.alloca, i32 4
%select.states.alloca.repack1 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 4
store ptr %select.send.value, ptr %select.states.alloca.repack1, align 4
%0 = getelementptr inbounds i8, ptr %select.states.alloca, i32 8
%0 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 8
store ptr %ch2, ptr %0, align 4
%.repack3 = getelementptr inbounds i8, ptr %select.states.alloca, i32 12
%.repack3 = getelementptr inbounds nuw i8, ptr %select.states.alloca, i32 12
store ptr null, ptr %.repack3, align 4
%select.result = call { i32, i1 } @runtime.chanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr null, i32 0, i32 0, ptr undef) #4
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %select.states.alloca)
@@ -107,8 +107,8 @@ select.body: ; preds = %select.next
declare { i32, i1 } @runtime.chanSelect(ptr, ptr, i32, i32, ptr, i32, i32, ptr) #1
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #4 = { nounwind }
+7 -7
View File
@@ -27,7 +27,7 @@ entry:
%0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
store i32 0, ptr %defer.alloca, align 4
%defer.alloca.repack15 = getelementptr inbounds i8, ptr %defer.alloca, i32 4
%defer.alloca.repack15 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
store ptr null, ptr %defer.alloca.repack15, align 4
store ptr %defer.alloca, ptr %deferPtr, align 4
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
@@ -51,7 +51,7 @@ rundefers.loophead: ; preds = %3, %rundefers.block
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
rundefers.loop: ; preds = %rundefers.loophead
%stack.next.gep = getelementptr inbounds i8, ptr %2, i32 4
%stack.next.gep = getelementptr inbounds nuw i8, ptr %2, i32 4
%stack.next = load ptr, ptr %stack.next.gep, align 4
store ptr %stack.next, ptr %deferPtr, align 4
%callback = load i32, ptr %2, align 4
@@ -87,7 +87,7 @@ rundefers.loophead6: ; preds = %5, %lpad
br i1 %stackIsNil7, label %rundefers.end3, label %rundefers.loop5
rundefers.loop5: ; preds = %rundefers.loophead6
%stack.next.gep8 = getelementptr inbounds i8, ptr %4, i32 4
%stack.next.gep8 = getelementptr inbounds nuw i8, ptr %4, i32 4
%stack.next9 = load ptr, ptr %stack.next.gep8, align 4
store ptr %stack.next9, ptr %deferPtr, align 4
%callback11 = load i32, ptr %4, align 4
@@ -144,11 +144,11 @@ entry:
%0 = call ptr @llvm.stacksave.p0()
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
store i32 0, ptr %defer.alloca, align 4
%defer.alloca.repack22 = getelementptr inbounds i8, ptr %defer.alloca, i32 4
%defer.alloca.repack22 = getelementptr inbounds nuw i8, ptr %defer.alloca, i32 4
store ptr null, ptr %defer.alloca.repack22, align 4
store ptr %defer.alloca, ptr %deferPtr, align 4
store i32 1, ptr %defer.alloca2, align 4
%defer.alloca2.repack23 = getelementptr inbounds i8, ptr %defer.alloca2, i32 4
%defer.alloca2.repack23 = getelementptr inbounds nuw i8, ptr %defer.alloca2, i32 4
store ptr %defer.alloca, ptr %defer.alloca2.repack23, align 4
store ptr %defer.alloca2, ptr %deferPtr, align 4
%setjmp = call i32 asm "\0Amovs r0, #0\0Amov r2, pc\0Astr r2, [r1, #4]", "={r0},{r1},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{cpsr},~{memory}"(ptr nonnull %deferframe.buf) #5
@@ -172,7 +172,7 @@ rundefers.loophead: ; preds = %4, %3, %rundefers.b
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
rundefers.loop: ; preds = %rundefers.loophead
%stack.next.gep = getelementptr inbounds i8, ptr %2, i32 4
%stack.next.gep = getelementptr inbounds nuw i8, ptr %2, i32 4
%stack.next = load ptr, ptr %stack.next.gep, align 4
store ptr %stack.next, ptr %deferPtr, align 4
%callback = load i32, ptr %2, align 4
@@ -218,7 +218,7 @@ rundefers.loophead10: ; preds = %7, %6, %lpad
br i1 %stackIsNil11, label %rundefers.end7, label %rundefers.loop9
rundefers.loop9: ; preds = %rundefers.loophead10
%stack.next.gep12 = getelementptr inbounds i8, ptr %5, i32 4
%stack.next.gep12 = getelementptr inbounds nuw i8, ptr %5, i32 4
%stack.next13 = load ptr, ptr %stack.next.gep12, align 4
store ptr %stack.next13, ptr %deferPtr, align 4
%callback15 = load i32, ptr %5, align 4
+4 -4
View File
@@ -1,6 +1,6 @@
; ModuleID = 'float.go'
source_filename = "float.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
@@ -93,6 +93,6 @@ entry:
ret i8 %0
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
+4 -4
View File
@@ -1,6 +1,6 @@
; ModuleID = 'func.go'
source_filename = "func.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
@@ -44,7 +44,7 @@ entry:
ret void
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+11 -11
View File
@@ -1,6 +1,6 @@
; ModuleID = 'gc.go'
source_filename = "gc.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
%runtime._interface = type { ptr, ptr }
@@ -105,18 +105,18 @@ entry:
%makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
store ptr %makeslice, ptr @main.slice1, align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice1, i32 4), align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice1, i32 8), align 4
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice1, i32 4), align 4
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice1, i32 8), align 4
%makeslice1 = call align 4 dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #3
store ptr %makeslice1, ptr @main.slice2, align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice2, i32 4), align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice2, i32 8), align 4
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice2, i32 4), align 4
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice2, i32 8), align 4
%makeslice3 = call align 4 dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #3
store ptr %makeslice3, ptr @main.slice3, align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice3, i32 4), align 4
store i32 5, ptr getelementptr inbounds (i8, ptr @main.slice3, i32 8), align 4
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice3, i32 4), align 4
store i32 5, ptr getelementptr inbounds nuw (i8, ptr @main.slice3, i32 8), align 4
ret void
}
@@ -127,7 +127,7 @@ entry:
%0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3
store double %v.r, ptr %0, align 8
%.repack1 = getelementptr inbounds i8, ptr %0, i32 8
%.repack1 = getelementptr inbounds nuw i8, ptr %0, i32 8
store double %v.i, ptr %.repack1, align 8
%1 = insertvalue %runtime._interface { ptr @"reflect/types.type:basic:complex128", ptr undef }, ptr %0, 1
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:complex128", ptr nonnull %stackalloc, ptr undef) #3
@@ -135,7 +135,7 @@ entry:
ret %runtime._interface %1
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+4 -4
View File
@@ -1,6 +1,6 @@
; ModuleID = 'go1.20.go'
source_filename = "go1.20.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
%runtime._string = type { ptr, i32 }
@@ -57,7 +57,7 @@ entry:
ret ptr %s.data
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+6 -6
View File
@@ -1,6 +1,6 @@
; ModuleID = 'go1.21.go'
source_filename = "go1.21.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
%runtime._string = type { ptr, i32 }
@@ -86,7 +86,7 @@ entry:
%stackalloc = alloca i8, align 1
%4 = call i1 @runtime.stringLess(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr undef) #5
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
%6 = extractvalue %runtime._string %5, 0
%6 = select i1 %4, ptr %a.data, ptr %b.data
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
ret %runtime._string %5
}
@@ -125,7 +125,7 @@ entry:
%stackalloc = alloca i8, align 1
%4 = call i1 @runtime.stringLess(ptr %b.data, i32 %b.len, ptr %a.data, i32 %a.len, ptr undef) #5
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
%6 = extractvalue %runtime._string %5, 0
%6 = select i1 %4, ptr %a.data, ptr %b.data
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
ret %runtime._string %5
}
@@ -171,9 +171,9 @@ declare i32 @llvm.smax.i32(i32, i32) #4
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.umax.i32(i32, i32) #4
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) }
attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #5 = { nounwind }
+12 -12
View File
@@ -65,7 +65,7 @@ entry:
store i32 3, ptr %n, align 4
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
store i32 5, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %0, i32 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
store ptr %n, ptr %1, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
@@ -87,7 +87,7 @@ entry:
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
entry:
%1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4
call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3)
ret void
@@ -104,9 +104,9 @@ define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %co
entry:
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
store i32 5, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %0, i32 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
store ptr %fn.context, ptr %1, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 8
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8
store ptr %fn.funcptr, ptr %2, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
@@ -117,9 +117,9 @@ entry:
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
entry:
%1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds i8, ptr %0, i32 8
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
%5 = load ptr, ptr %4, align 4
call void %5(i32 %1, ptr %3) #9
ret void
@@ -154,11 +154,11 @@ define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value,
entry:
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
store ptr %itf.value, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %0, i32 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
store ptr @"main$string", ptr %1, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 8
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8
store i32 4, ptr %2, align 4
%3 = getelementptr inbounds i8, ptr %0, i32 12
%3 = getelementptr inbounds nuw i8, ptr %0, i32 12
store ptr %itf.typecode, ptr %3, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
@@ -171,11 +171,11 @@ declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
entry:
%1 = load ptr, ptr %0, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds i8, ptr %0, i32 8
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
%5 = load i32, ptr %4, align 4
%6 = getelementptr inbounds i8, ptr %0, i32 12
%6 = getelementptr inbounds nuw i8, ptr %0, i32 12
%7 = load ptr, ptr %6, align 4
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
ret void
+22 -22
View File
@@ -1,6 +1,6 @@
; ModuleID = 'goroutine.go'
source_filename = "goroutine.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
@@ -72,7 +72,7 @@ entry:
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store i32 5, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %0, i32 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
store ptr %n, ptr %1, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
%2 = load i32, ptr %n, align 4
@@ -93,7 +93,7 @@ entry:
define linkonce_odr void @"main.closureFunctionGoroutine$1$gowrapper"(ptr %0) unnamed_addr #5 {
entry:
%1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4
call void @"main.closureFunctionGoroutine$1"(i32 %1, ptr %3)
call void @runtime.deadlock(ptr undef) #9
@@ -113,9 +113,9 @@ entry:
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store i32 5, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %0, i32 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
store ptr %fn.context, ptr %1, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 8
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8
store ptr %fn.funcptr, ptr %2, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 65536, ptr undef) #9
ret void
@@ -125,9 +125,9 @@ entry:
define linkonce_odr void @main.funcGoroutine.gowrapper(ptr %0) unnamed_addr #6 {
entry:
%1 = load i32, ptr %0, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds i8, ptr %0, i32 8
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
%5 = load ptr, ptr %4, align 4
call void %5(i32 %1, ptr %3) #9
call void @runtime.deadlock(ptr undef) #9
@@ -165,11 +165,11 @@ entry:
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
store ptr %itf.value, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %0, i32 4
%1 = getelementptr inbounds nuw i8, ptr %0, i32 4
store ptr @"main$string", ptr %1, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 8
%2 = getelementptr inbounds nuw i8, ptr %0, i32 8
store i32 4, ptr %2, align 4
%3 = getelementptr inbounds i8, ptr %0, i32 12
%3 = getelementptr inbounds nuw i8, ptr %0, i32 12
store ptr %itf.typecode, ptr %3, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
ret void
@@ -181,24 +181,24 @@ declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr, ptr, i
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(ptr %0) unnamed_addr #8 {
entry:
%1 = load ptr, ptr %0, align 4
%2 = getelementptr inbounds i8, ptr %0, i32 4
%2 = getelementptr inbounds nuw i8, ptr %0, i32 4
%3 = load ptr, ptr %2, align 4
%4 = getelementptr inbounds i8, ptr %0, i32 8
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
%5 = load i32, ptr %4, align 4
%6 = getelementptr inbounds i8, ptr %0, i32 12
%6 = getelementptr inbounds nuw i8, ptr %0, i32 12
%7 = load ptr, ptr %6, align 4
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(ptr %1, ptr %3, i32 %5, ptr %7, ptr undef) #9
call void @runtime.deadlock(ptr undef) #9
unreachable
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.regularFunction" }
attributes #4 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
attributes #5 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
attributes #6 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper" }
attributes #7 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
attributes #8 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.regularFunction" }
attributes #4 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" }
attributes #5 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" }
attributes #6 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper" }
attributes #7 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
attributes #8 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" }
attributes #9 = { nounwind }
+8 -8
View File
@@ -1,6 +1,6 @@
; ModuleID = 'interface.go'
source_filename = "interface.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
%runtime._interface = type { ptr, ptr }
@@ -130,11 +130,11 @@ entry:
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #6
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.Error() string" }
attributes #4 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.String() string" }
attributes #5 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
attributes #6 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.Error() string" }
attributes #4 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-methods"="reflect/methods.String() string" }
attributes #5 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
attributes #6 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
attributes #7 = { nounwind }
+4 -4
View File
@@ -1,6 +1,6 @@
; ModuleID = 'pointer.go'
source_filename = "pointer.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
@@ -44,7 +44,7 @@ entry:
ret ptr %x
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+11 -11
View File
@@ -1,6 +1,6 @@
; ModuleID = 'pragma.go'
source_filename = "pragma.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
@extern_global = external global [0 x i8], align 1
@@ -93,13 +93,13 @@ entry:
ret void
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="extern_func" }
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exportedFunctionInSection" }
attributes #7 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
attributes #8 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
attributes #9 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exported" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="extern_func" }
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exportedFunctionInSection" }
attributes #7 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
attributes #8 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
attributes #9 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" "wasm-export-name"="exported" }
+6 -6
View File
@@ -1,6 +1,6 @@
; ModuleID = 'slice.go'
source_filename = "slice.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
@@ -51,9 +51,9 @@ entry:
%varargs = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #3
store i32 1, ptr %varargs, align 4
%0 = getelementptr inbounds i8, ptr %varargs, i32 4
%0 = getelementptr inbounds nuw i8, ptr %varargs, i32 4
store i32 2, ptr %0, align 4
%1 = getelementptr inbounds i8, ptr %varargs, i32 8
%1 = getelementptr inbounds nuw i8, ptr %varargs, i32 8
store i32 3, ptr %1, align 4
%append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, ptr undef) #3
%append.newPtr = extractvalue { ptr, i32, i32 } %append.new, 0
@@ -322,7 +322,7 @@ unsafe.Slice.throw: ; preds = %entry
unreachable
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+6 -6
View File
@@ -1,6 +1,6 @@
; ModuleID = 'string.go'
source_filename = "string.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
%runtime._string = type { ptr, i32 }
@@ -84,11 +84,11 @@ declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
define hidden i8 @main.stringLookup(ptr %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #2 {
entry:
%0 = zext i8 %x to i32
%.not = icmp ult i32 %0, %s.len
%.not = icmp ugt i32 %s.len, %0
br i1 %.not, label %lookup.next, label %lookup.throw
lookup.next: ; preds = %entry
%1 = getelementptr inbounds i8, ptr %s.data, i32 %0
%1 = getelementptr inbounds nuw i8, ptr %s.data, i32 %0
%2 = load i8, ptr %1, align 1
ret i8 %2
@@ -97,7 +97,7 @@ lookup.throw: ; preds = %entry
unreachable
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { nounwind }
+19 -19
View File
@@ -1,6 +1,6 @@
; ModuleID = 'zeromap.go'
source_filename = "zeromap.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
%main.hasPadding = type { i1, i32, i1 }
@@ -27,9 +27,9 @@ entry:
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
store %main.hasPadding %2, ptr %hashmap.key, align 4
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
%3 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
%4 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %4, i32 3, ptr undef) #5
%5 = call i1 @runtime.hashmapBinaryGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #5
call void @llvm.lifetime.end.p0(i64 12, ptr nonnull %hashmap.key)
@@ -60,9 +60,9 @@ entry:
store i32 5, ptr %hashmap.value, align 4
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
store %main.hasPadding %2, ptr %hashmap.key, align 4
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
%3 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
%4 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %4, i32 3, ptr undef) #5
call void @runtime.hashmapBinarySet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #5
call void @llvm.lifetime.end.p0(i64 12, ptr nonnull %hashmap.key)
@@ -81,16 +81,16 @@ entry:
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
%hashmap.key.repack1 = getelementptr inbounds i8, ptr %hashmap.key, i32 12
%hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
%0 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
%0 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
%1 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
%1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
%2 = getelementptr inbounds i8, ptr %hashmap.key, i32 13
%2 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 13
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 21
%3 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 21
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
%4 = call i1 @runtime.hashmapBinaryGet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, i32 4, ptr undef) #5
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %hashmap.key)
@@ -109,16 +109,16 @@ entry:
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
%hashmap.key.repack1 = getelementptr inbounds i8, ptr %hashmap.key, i32 12
%hashmap.key.repack1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 12
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
%0 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
%0 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 1
call void @runtime.memzero(ptr nonnull %0, i32 3, ptr undef) #5
%1 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
%1 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 9
call void @runtime.memzero(ptr nonnull %1, i32 3, ptr undef) #5
%2 = getelementptr inbounds i8, ptr %hashmap.key, i32 13
%2 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 13
call void @runtime.memzero(ptr nonnull %2, i32 3, ptr undef) #5
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 21
%3 = getelementptr inbounds nuw i8, ptr %hashmap.key, i32 21
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
call void @runtime.hashmapBinarySet(ptr %m, ptr nonnull %hashmap.key, ptr nonnull %hashmap.value, ptr undef) #5
call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %hashmap.key)
@@ -132,9 +132,9 @@ entry:
ret void
}
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #1 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #3 = { noinline nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" }
attributes #4 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #5 = { nounwind }
+40 -20
View File
@@ -10,6 +10,7 @@ import (
"go/types"
"io"
"path/filepath"
"reflect"
"sort"
"strings"
@@ -23,6 +24,11 @@ import (
type Diagnostic struct {
Pos token.Position
Msg string
// Start and end position, if available. For many errors these positions are
// not available, but for some they are.
StartPos token.Position
EndPos token.Position
}
// One or multiple errors of a particular package.
@@ -114,12 +120,22 @@ func createPackageDiagnostic(err error) PackageDiagnostic {
func createDiagnostics(err error) []Diagnostic {
switch err := err.(type) {
case types.Error:
return []Diagnostic{
{
Pos: err.Fset.Position(err.Pos),
Msg: err.Msg,
},
diag := Diagnostic{
Pos: err.Fset.Position(err.Pos),
Msg: err.Msg,
}
// There is a special unexported API since Go 1.16 that provides the
// range (start and end position) where the type error exists.
// There is no promise of backwards compatibility in future Go versions
// so we have to be extra careful here to be resilient.
v := reflect.ValueOf(err)
start := v.FieldByName("go116start")
end := v.FieldByName("go116end")
if start.IsValid() && end.IsValid() && start.Int() != end.Int() {
diag.StartPos = err.Fset.Position(token.Pos(start.Int()))
diag.EndPos = err.Fset.Position(token.Pos(end.Int()))
}
return []Diagnostic{diag}
case scanner.Error:
return []Diagnostic{
{
@@ -188,25 +204,29 @@ func (diag Diagnostic) WriteTo(w io.Writer, wd string) {
fmt.Fprintln(w, diag.Msg)
return
}
pos := diag.Pos // make a copy
if !strings.HasPrefix(pos.Filename, filepath.Join(goenv.Get("GOROOT"), "src")) && !strings.HasPrefix(pos.Filename, filepath.Join(goenv.Get("TINYGOROOT"), "src")) {
// This file is not from the standard library (either the GOROOT or the
// TINYGOROOT). Make the path relative, for easier reading. Ignore any
// errors in the process (falling back to the absolute path).
pos.Filename = tryToMakePathRelative(pos.Filename, wd)
}
pos := RelativePosition(diag.Pos, wd)
fmt.Fprintf(w, "%s: %s\n", pos, diag.Msg)
}
// try to make the path relative to the current working directory. If any error
// occurs, this error is ignored and the absolute path is returned instead.
func tryToMakePathRelative(dir, wd string) string {
// Convert the position in pos (assumed to have an absolute path) into a
// relative path if possible. Paths inside GOROOT/TINYGOROOT will remain
// absolute.
func RelativePosition(pos token.Position, wd string) token.Position {
// Check whether we even have a working directory.
if wd == "" {
return dir // working directory not found
return pos
}
relpath, err := filepath.Rel(wd, dir)
if err != nil {
return dir
// Paths inside GOROOT should be printed in full.
if strings.HasPrefix(pos.Filename, filepath.Join(goenv.Get("GOROOT"), "src")) || strings.HasPrefix(pos.Filename, filepath.Join(goenv.Get("TINYGOROOT"), "src")) {
return pos
}
return relpath
// Make the path relative, for easier reading. Ignore any errors in the
// process (falling back to the absolute path).
relpath, err := filepath.Rel(wd, pos.Filename)
if err == nil {
pos.Filename = relpath
}
return pos
}
+6 -1
View File
@@ -8,6 +8,7 @@ import (
"strings"
"testing"
"github.com/tinygo-org/tinygo/builder"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/diagnostics"
)
@@ -64,7 +65,11 @@ func testErrorMessages(t *testing.T, filename string, options *compileopts.Optio
// Try to build a binary (this should fail with an error).
tmpdir := t.TempDir()
err := Build(filename, tmpdir+"/out", options)
config, err := builder.NewConfig(options)
if err != nil {
t.Fatal("expected to get a compiler error")
}
err = Build(filename, tmpdir+"/out", config)
if err == nil {
t.Fatal("expected to get a compiler error")
}
Generated
+4 -4
View File
@@ -20,16 +20,16 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1728500571,
"narHash": "sha256-dOymOQ3AfNI4Z337yEwHGohrVQb4yPODCW9MDUyAc4w=",
"lastModified": 1747953325,
"narHash": "sha256-y2ZtlIlNTuVJUZCqzZAhIw5rrKP4DOSklev6c8PyCkQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d51c28603def282a24fa034bcb007e2bcb5b5dd0",
"rev": "55d1f923c480dadce40f5231feb472e81b0bab48",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-24.05",
"ref": "nixos-25.05",
"type": "indirect"
}
},
+5 -14
View File
@@ -21,7 +21,6 @@
# make llvm-source # fetch compiler-rt
# git submodule update --init # fetch lots of other libraries and SVD files
# make gen-device -j4 # build src/device/*/*.go files
# make wasi-libc # build support for wasi/wasm
#
# With this, you should have an environment that can compile anything - except
# for the Xtensa architecture (ESP8266/ESP32) because support for that lives in
@@ -35,7 +34,7 @@
inputs = {
# Use a recent stable release, but fix the version to make it reproducible.
# This version should be updated from time to time.
nixpkgs.url = "nixpkgs/nixos-24.05";
nixpkgs.url = "nixpkgs/nixos-25.05";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
@@ -49,11 +48,11 @@
buildInputs = [
# These dependencies are required for building tinygo (go install).
go
llvmPackages_18.llvm
llvmPackages_18.libclang
llvmPackages_20.llvm
llvmPackages_20.libclang
# Additional dependencies needed at runtime, for building and/or
# flashing.
llvmPackages_18.lld
llvmPackages_20.lld
avrdude
binaryen
# Additional dependencies needed for on-chip debugging.
@@ -64,20 +63,12 @@
#openocd
];
shellHook= ''
# Configure CLANG, LLVM_AR, and LLVM_NM for `make wasi-libc`.
# Without setting these explicitly, Homebrew versions might be used
# or the default `ar` and `nm` tools might be used (which don't
# support wasi).
export CLANG="clang-18 -resource-dir ${llvmPackages_18.clang.cc.lib}/lib/clang/18"
export LLVM_AR=llvm-ar
export LLVM_NM=llvm-nm
# Make `make smoketest` work (the default is `md5`, while Nix only
# has `md5sum`).
export MD5SUM=md5sum
# Ugly hack to make the Clang resources directory available.
export GOFLAGS="\"-ldflags=-X github.com/tinygo-org/tinygo/goenv.clangResourceDir=${llvmPackages_18.clang.cc.lib}/lib/clang/18\" -tags=llvm18"
export GOFLAGS="\"-ldflags=-X github.com/tinygo-org/tinygo/goenv.clangResourceDir=${llvmPackages_20.clang.cc.lib}/lib/clang/20\" -tags=llvm20"
'';
};
}
+7 -15
View File
@@ -1,12 +1,10 @@
module github.com/tinygo-org/tinygo
go 1.19
go 1.22.0
require (
github.com/aykevl/go-wasm v0.0.2-0.20240825160117-b76c3f9f0982
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
github.com/chromedp/chromedp v0.7.6
github.com/gofrs/flock v0.8.1
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
@@ -16,22 +14,16 @@ require (
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
github.com/tetratelabs/wazero v1.6.0
go.bug.st/serial v1.6.0
golang.org/x/net v0.26.0
golang.org/x/sys v0.21.0
golang.org/x/tools v0.22.1-0.20240621165957-db513b091504
golang.org/x/net v0.35.0
golang.org/x/sys v0.30.0
golang.org/x/tools v0.30.0
gopkg.in/yaml.v2 v2.4.0
tinygo.org/x/go-llvm v0.0.0-20250119132755-9dca92dfb4f9
tinygo.org/x/go-llvm v0.0.0-20250916101410-63740cfada08
)
require (
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/creack/goselect v0.1.2 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/stretchr/testify v1.8.4 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/text v0.22.0 // indirect
)
+19 -35
View File
@@ -1,33 +1,17 @@
github.com/aykevl/go-wasm v0.0.2-0.20240825160117-b76c3f9f0982 h1:cD7QfvrJdYmBw2tFP/VyKPT8ZESlcrwSwo7SvH9Y4dc=
github.com/aykevl/go-wasm v0.0.2-0.20240825160117-b76c3f9f0982/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139 h1:2O/WuAt8J5id3khcAtVB90czG80m+v0sfkLE07GrCVg=
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee h1:+SFdIVfQpG0s0DHYzou0kgfE0n0ZjKPwbiRJsXrZegU=
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
github.com/chromedp/chromedp v0.7.6 h1:2juGaktzjwULlsn+DnvIZXFUckEp5xs+GOBroaea+jA=
github.com/chromedp/chromedp v0.7.6/go.mod h1:ayT4YU/MGAALNfOg9gNrpGSAdnU51PMx+FCeuT1iXzo=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s=
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -41,9 +25,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
@@ -52,27 +35,28 @@ github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzl
github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/tools v0.22.1-0.20240621165957-db513b091504 h1:MMsD8mMfluf/578+3wrTn22pjI/Xkzm+gPW47SYfspY=
golang.org/x/tools v0.22.1-0.20240621165957-db513b091504/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
tinygo.org/x/go-llvm v0.0.0-20250119132755-9dca92dfb4f9 h1:rMvEzuCYjyiR+pmdiCVWTQw3L6VqiSIXoL19I3lYufE=
tinygo.org/x/go-llvm v0.0.0-20250119132755-9dca92dfb4f9/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
tinygo.org/x/go-llvm v0.0.0-20250916101410-63740cfada08 h1:vvEVYF4Qb38C25U8Ae/1QUWlCSp4pIE0PR+/BwNPvBU=
tinygo.org/x/go-llvm v0.0.0-20250916101410-63740cfada08/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
+1 -1
View File
@@ -10,7 +10,7 @@ import (
// Version of TinyGo.
// Update this value before release of new version of software.
const version = "0.36.0"
const version = "0.40.0-dev"
// Return TinyGo version, either in the form 0.30.0 or as a development version
// (like 0.30.0-dev-abcd012).
+12 -8
View File
@@ -1,18 +1,22 @@
module github.com/tinygo-org/tinygo/internal/tools
module github.com/tinygo-org/tinygo/internal/wasm-tools
go 1.22.4
go 1.23.0
require github.com/bytecodealliance/wasm-tools-go v0.3.1
require (
go.bytecodealliance.org v0.6.2
go.bytecodealliance.org/cm v0.2.2
)
require (
github.com/coreos/go-semver v0.3.1 // indirect
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/regclient/regclient v0.7.1 // indirect
github.com/regclient/regclient v0.8.2 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/tetratelabs/wazero v1.9.0 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/urfave/cli/v3 v3.0.0-alpha9.2 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/sys v0.26.0 // indirect
github.com/urfave/cli/v3 v3.0.0-beta1 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/sys v0.31.0 // indirect
)
+22 -18
View File
@@ -1,5 +1,3 @@
github.com/bytecodealliance/wasm-tools-go v0.3.1 h1:9Q9PjSzkbiVmkUvZ7nYCfJ02mcQDBalxycA3s8g7kR4=
github.com/bytecodealliance/wasm-tools-go v0.3.1/go.mod h1:vNAQ8DAEp6xvvk+TUHah5DslLEa76f4H6e737OeaxuY=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -7,16 +5,16 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/olareg/olareg v0.1.0 h1:1dXBOgPrig5N7zoXyIZVQqU0QBo6sD9pbL6UYjY75CA=
github.com/olareg/olareg v0.1.0/go.mod h1:RBuU7JW7SoIIxZKzLRhq8sVtQeAHzCAtRrXEBx2KlM4=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/olareg/olareg v0.1.1 h1:Ui7q93zjcoF+U9U71sgqgZWByDoZOpqHitUXEu2xV+g=
github.com/olareg/olareg v0.1.1/go.mod h1:w8NP4SWrHHtxsFaUiv1lnCnYPm4sN1seCd2h7FK/dc0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/regclient/regclient v0.7.1 h1:qEsJrTmZd98fZKjueAbrZCSNGU+ifnr6xjlSAs3WOPs=
github.com/regclient/regclient v0.7.1/go.mod h1:+w/BFtJuw0h0nzIw/z2+1FuA2/dVXBzDq4rYmziJpMc=
github.com/regclient/regclient v0.8.2 h1:23BQ3jWgKYHHIXUhp/S9laVJDHDoOQaQCzXMJ4undVE=
github.com/regclient/regclient v0.8.2/go.mod h1:uGyetv0o6VLyRDjtfeBqp/QBwRLJ3Hcn07/+8QbhNcM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
@@ -25,19 +23,25 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli/v3 v3.0.0-alpha9.2 h1:CL8llQj3dGRLVQQzHxS+ZYRLanOuhyK1fXgLKD+qV+Y=
github.com/urfave/cli/v3 v3.0.0-alpha9.2/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
go.bytecodealliance.org v0.6.2 h1:Jy4u5DVmSkXgsnwojBhJ+AD/YsJsR3VzVnxF0xRCqTQ=
go.bytecodealliance.org v0.6.2/go.mod h1:gqjTJm0y9NSksG4py/lSjIQ/SNuIlOQ+hCIEPQwtJgA=
go.bytecodealliance.org/cm v0.2.2 h1:M9iHS6qs884mbQbIjtLX1OifgyPG9DuMs2iwz8G4WQA=
go.bytecodealliance.org/cm v0.2.2/go.mod h1:JD5vtVNZv7sBoQQkvBvAAVKJPhR/bqBH7yYXTItMfZI=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+3 -2
View File
@@ -5,7 +5,8 @@
package tools
import (
_ "github.com/bytecodealliance/wasm-tools-go/cmd/wit-bindgen-go"
_ "go.bytecodealliance.org/cm"
_ "go.bytecodealliance.org/cmd/wit-bindgen-go"
)
//go:generate go install github.com/bytecodealliance/wasm-tools-go/cmd/wit-bindgen-go
//go:generate go install go.bytecodealliance.org/cmd/wit-bindgen-go
+14 -1
View File
@@ -364,9 +364,22 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
continue
}
nBytes := uint32(n * elemSize)
srcObj := mem.get(src.index())
dstObj := mem.getWritable(dst.index())
if srcObj.buffer == nil || dstObj.buffer == nil {
// If the buffer is nil, it means the slice is external.
// This can happen for example when copying data out of
// a //go:embed slice, which is not available at interp
// time.
// See: https://github.com/tinygo-org/tinygo/issues/4895
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
if err != nil {
return nil, mem, err
}
continue
}
dstBuf := dstObj.buffer.asRawValue(r)
srcBuf := mem.get(src.index()).buffer.asRawValue(r)
srcBuf := srcObj.buffer.asRawValue(r)
copy(dstBuf.buf[dst.offset():dst.offset()+nBytes], srcBuf.buf[src.offset():])
dstObj.buffer = dstBuf
mem.put(dst.index(), dstObj)
-13
View File
@@ -824,19 +824,6 @@ func (v rawValue) rawLLVMValue(mem *memoryView) (llvm.Value, error) {
if err != nil {
return llvm.Value{}, err
}
if !field.IsAGlobalVariable().IsNil() {
elementType := field.GlobalValueType()
if elementType.TypeKind() == llvm.StructTypeKind {
// There are some special pointer types that should be used
// as a ptrtoint, so that they can be used in certain
// optimizations.
name := elementType.StructName()
if name == "runtime.funcValueWithSignature" {
uintptrType := ctx.IntType(int(mem.r.pointerSize) * 8)
field = llvm.ConstPtrToInt(field, uintptrType)
}
}
}
structFields = append(structFields, field)
i += mem.r.pointerSize
continue
+1 -1
View File
@@ -10,7 +10,7 @@ target triple = "x86_64--linux"
@main.exposedValue2 = local_unnamed_addr global i16 0
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
@main.gepArray = local_unnamed_addr global [8 x i8] zeroinitializer
@main.negativeGEP = global ptr getelementptr inbounds (i8, ptr @main.negativeGEP, i64 2)
@main.negativeGEP = global ptr getelementptr inbounds nuw (i8, ptr @main.negativeGEP, i64 2)
declare void @runtime.printint64(i64) unnamed_addr
+1 -1
View File
@@ -5,7 +5,7 @@ target triple = "x86_64--linux"
@ptrToIntResult = local_unnamed_addr global i8 2
@pointerTagResult = local_unnamed_addr global i64 2
@someArray = internal global { i16, i8, i8 } zeroinitializer
@someArrayPointer = local_unnamed_addr global ptr getelementptr inbounds (i8, ptr @someArray, i64 2)
@someArrayPointer = local_unnamed_addr global ptr getelementptr inbounds nuw (i8, ptr @someArray, i64 2)
define void @runtime.initAll() local_unnamed_addr {
ret void
+18
View File
@@ -11,6 +11,10 @@ target triple = "x86_64--linux"
@main.sliceDstUntaint.buf = internal global [2 x i8] zeroinitializer
@main.sliceSrcTaint.buf = internal global [2 x i8] c"cd"
@main.sliceDstTaint.buf = internal global [2 x i8] zeroinitializer
@main.sliceSrcExternal1.buf = external global [2 x i8]
@main.sliceDstExternal1.buf = internal global [2 x i8] zeroinitializer
@main.sliceSrcExternal2.buf = internal global [2 x i8] zeroinitializer
@main.sliceDstExternal2.buf = external global [2 x i8]
declare i64 @runtime.sliceCopy(ptr %dst, ptr %src, i64 %dstLen, i64 %srcLen, i64 %elemSize) unnamed_addr
@@ -58,6 +62,14 @@ entry:
%sliceDstTaint.val = load i8, ptr getelementptr inbounds (i8, ptr @main.sliceDstTaint.buf, i32 0)
call void @runtime.printuint8(i8 %sliceDstTaint.val)
; print(sliceDstExternal1[0])
%sliceDstExternal1.val = load i8, ptr getelementptr inbounds (i8, ptr @main.sliceDstExternal1.buf, i32 0)
call void @runtime.printuint8(i8 %sliceDstExternal1.val)
; print(sliceDstExternal2[0])
%sliceDstExternal2.val = load i8, ptr getelementptr inbounds (i8, ptr @main.sliceDstExternal2.buf, i32 0)
call void @runtime.printuint8(i8 %sliceDstExternal2.val)
ret void
}
@@ -102,5 +114,11 @@ entry:
call void @use(ptr @main.sliceSrcTaint.buf)
%copy.n4 = call i64 @runtime.sliceCopy(ptr @main.sliceDstTaint.buf, ptr @main.sliceSrcTaint.buf, i64 2, i64 2, i64 1)
; Test that copying from or into external buffers works correctly.
; These copy operations must be done at runtime.
; https://github.com/tinygo-org/tinygo/issues/4895
%copy.n5 = call i64 @runtime.sliceCopy(ptr @main.sliceDstExternal1.buf, ptr @main.sliceSrcExternal1.buf, i64 2, i64 2, i64 1)
%copy.n6 = call i64 @runtime.sliceCopy(ptr @main.sliceDstExternal2.buf, ptr @main.sliceSrcExternal2.buf, i64 2, i64 2, i64 1)
ret void
}
+10
View File
@@ -3,6 +3,10 @@ target triple = "x86_64--linux"
@main.sliceSrcTaint.buf = internal global [2 x i8] c"cd"
@main.sliceDstTaint.buf = internal global [2 x i8] zeroinitializer
@main.sliceSrcExternal1.buf = external global [2 x i8]
@main.sliceDstExternal1.buf = internal global [2 x i8] zeroinitializer
@main.sliceSrcExternal2.buf = internal global [2 x i8] zeroinitializer
@main.sliceDstExternal2.buf = external global [2 x i8]
declare i64 @runtime.sliceCopy(ptr, ptr, i64, i64, i64) unnamed_addr
@@ -16,6 +20,8 @@ define void @runtime.initAll() unnamed_addr {
entry:
call void @use(ptr @main.sliceSrcTaint.buf)
%copy.n4 = call i64 @runtime.sliceCopy(ptr @main.sliceDstTaint.buf, ptr @main.sliceSrcTaint.buf, i64 2, i64 2, i64 1)
%copy.n5 = call i64 @runtime.sliceCopy(ptr @main.sliceDstExternal1.buf, ptr @main.sliceSrcExternal1.buf, i64 2, i64 2, i64 1)
%copy.n6 = call i64 @runtime.sliceCopy(ptr @main.sliceDstExternal2.buf, ptr @main.sliceSrcExternal2.buf, i64 2, i64 2, i64 1)
ret void
}
@@ -28,5 +34,9 @@ entry:
call void @runtime.printuint8(i8 97)
%sliceDstTaint.val = load i8, ptr @main.sliceDstTaint.buf, align 1
call void @runtime.printuint8(i8 %sliceDstTaint.val)
%sliceDstExternal1.val = load i8, ptr @main.sliceDstExternal1.buf, align 1
call void @runtime.printuint8(i8 %sliceDstExternal1.val)
%sliceDstExternal2.val = load i8, ptr @main.sliceDstExternal2.buf, align 1
call void @runtime.printuint8(i8 %sliceDstExternal2.val)
ret void
}
Submodule
+1
Submodule lib/bdwgc added at 1166f11f7d
+3 -1
View File
@@ -8,7 +8,9 @@ import (
//
// The program must already be parsed and type-checked with the .Parse() method.
func (p *Program) LoadSSA() *ssa.Program {
prog := ssa.NewProgram(p.fset, ssa.SanityCheckFunctions|ssa.BareInits|ssa.GlobalDebug|ssa.InstantiateGenerics)
// TODO: re-enable SanityCheckFunctions when x/tools is upgraded to
// a version with a fix for https://golang.org/issues/73594.
prog := ssa.NewProgram(p.fset /*ssa.SanityCheckFunctions|*/, ssa.BareInits|ssa.GlobalDebug|ssa.InstantiateGenerics)
for _, pkg := range p.sorted {
prog.CreatePackage(pkg.Pkg, pkg.Files, &pkg.info, true)
+156 -63
View File
@@ -138,27 +138,13 @@ func printCommand(cmd string, args ...string) {
}
// Build compiles and links the given package and writes it to outpath.
func Build(pkgName, outpath string, options *compileopts.Options) error {
config, err := builder.NewConfig(options)
if err != nil {
return err
}
if options.PrintJSON {
b, err := json.MarshalIndent(config, "", " ")
if err != nil {
handleCompilerError(err)
}
fmt.Printf("%s\n", string(b))
return nil
}
func Build(pkgName, outpath string, config *compileopts.Config) error {
// Create a temporary directory for intermediary files.
tmpdir, err := os.MkdirTemp("", "tinygo")
if err != nil {
return err
}
if !options.Work {
if !config.Options.Work {
defer os.RemoveAll(tmpdir)
}
@@ -305,7 +291,8 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
})
if testConfig.CompileOnly {
return true, nil
// Return the compiler error, if there is one.
return true, err
}
importPath := strings.TrimSuffix(result.ImportPath, ".test")
@@ -353,8 +340,17 @@ func dirsToModuleRootAbs(maindir, modroot string) []string {
return dirs
}
// validateOutputFormat checks if the output file extension matches the expected format
func validateOutputFormat(outpath, expectedExt string) error {
actualExt := filepath.Ext(outpath)
if actualExt != expectedExt {
return fmt.Errorf("output format %s does not match target format %s", actualExt, expectedExt)
}
return nil
}
// Flash builds and flashes the built binary to the given serial port.
func Flash(pkgName, port string, options *compileopts.Options) error {
func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
config, err := builder.NewConfig(options)
if err != nil {
return err
@@ -403,13 +399,24 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
if !options.Work {
defer os.RemoveAll(tmpdir)
}
// Validate output format before building
if outpath != "" {
if err := validateOutputFormat(outpath, fileExt); err != nil {
return err
}
}
// Build the binary.
result, err := builder.Build(pkgName, fileExt, tmpdir, config)
if err != nil {
return err
}
// Save output file if specified (after build, before flashing)
if outpath != "" {
if err := copyFile(result.Binary, outpath); err != nil {
return fmt.Errorf("failed to save output file: %v", err)
}
}
// do we need port reset to put MCU into bootloader mode?
if config.Target.PortReset == "true" && flashMethod != "openocd" {
port, err := getDefaultPort(port, config.Target.SerialPort)
@@ -1027,15 +1034,50 @@ func findFATMounts(options *compileopts.Options) ([]mountPoint, error) {
return nil, fmt.Errorf("could not list mount points: %w", err)
}
for _, elem := range list {
// TODO: find a way to check for the filesystem type.
// (Only return FAT filesystems).
points = append(points, mountPoint{
name: elem.Name(),
path: filepath.Join("/Volumes", elem.Name()),
})
volumePath := filepath.Join("/Volumes", elem.Name())
if _, err := os.Stat(volumePath); err != nil {
continue
}
cmd := exec.Command("diskutil", "info", volumePath)
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
continue // skip if diskutil failed
}
diskInfo := map[string]string{}
scanner := bufio.NewScanner(&out)
for scanner.Scan() {
line := scanner.Text()
parts := strings.SplitN(line, ":", 2)
if len(parts) != 2 {
continue
}
key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])
diskInfo[key] = value
}
if err := scanner.Err(); err != nil {
continue
}
volName, okv := diskInfo["Volume Name"]
fsType, okf := diskInfo["File System Personality"]
if !okv || !okf {
continue
}
// Check if a filesystem type is FAT-based
if strings.Contains(strings.ToUpper(fsType), "FAT") {
points = append(points, mountPoint{
name: volName,
path: volumePath,
})
}
}
sort.Slice(points, func(i, j int) bool {
return points[i].path < points[j].name
return points[i].path < points[j].path
})
return points, nil
case "linux":
@@ -1276,6 +1318,11 @@ extension at all.`
(https://tinygo.org/docs/reference/microcontrollers/).
Examples: "arduino-nano", "d1mini", "xiao".
-o={filename}:
Save the built binary to the specified output file. The file
format must match the target's expected format (e.g., .hex,
.uf2). Both flashing and saving will be performed.
-monitor:
Start the serial monitor (see below) immediately after
flashing. However, some microcontrollers need a split second
@@ -1396,6 +1443,68 @@ func usage(command string) {
}
// Print diagnostics very similar to the -json flag in Go.
func printBuildOutput(err error, jsonDiagnostics bool) {
if err == nil {
return // nothing to report
}
if jsonDiagnostics {
workingDir, getwdErr := os.Getwd()
if getwdErr != nil {
workingDir = ""
}
type jsonDiagnosticOutput struct {
ImportPath string
Action string
Output string `json:",omitempty"`
StartPos string `json:",omitempty"` // non-standard
EndPos string `json:",omitempty"` // non-standard
}
for _, diags := range diagnostics.CreateDiagnostics(err) {
if diags.ImportPath != "" {
output, _ := json.Marshal(jsonDiagnosticOutput{
ImportPath: diags.ImportPath,
Action: "build-output",
Output: "# " + diags.ImportPath + "\n",
})
os.Stdout.Write(append(output, '\n'))
}
for _, diag := range diags.Diagnostics {
w := &bytes.Buffer{}
diag.WriteTo(w, workingDir)
data := jsonDiagnosticOutput{
ImportPath: diags.ImportPath,
Action: "build-output",
Output: w.String(),
}
if diag.StartPos.IsValid() && diag.EndPos.IsValid() {
// Include the non-standard StartPos/EndPos values. These
// are useful for the TinyGo Playground to show better error
// messages.
data.StartPos = diagnostics.RelativePosition(diag.StartPos, workingDir).String()
data.EndPos = diagnostics.RelativePosition(diag.EndPos, workingDir).String()
}
output, _ := json.Marshal(data)
os.Stdout.Write(append(output, '\n'))
}
// Emit the "Action":"build-fail" JSON.
output, _ := json.Marshal(jsonDiagnosticOutput{
ImportPath: diags.ImportPath,
Action: "build-fail",
})
os.Stdout.Write(append(output, '\n'))
}
os.Exit(1)
}
// Regular diagnostic handling.
handleCompilerError(err)
}
func handleCompilerError(err error) {
if err != nil {
wd, getwdErr := os.Getwd()
@@ -1492,9 +1601,9 @@ func main() {
command := os.Args[1]
opt := flag.String("opt", "z", "optimization level: 0, 1, 2, s, z")
gc := flag.String("gc", "", "garbage collector to use (none, leaking, conservative)")
gc := flag.String("gc", "", "garbage collector to use (none, leaking, conservative, custom, precise, boehm)")
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
scheduler := flag.String("scheduler", "", "which scheduler to use (none, tasks, asyncify)")
scheduler := flag.String("scheduler", "", "which scheduler to use (none, tasks, cores, threads, asyncify)")
serial := flag.String("serial", "", "which serial output to use (none, uart, usb, rtt)")
work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit")
interpTimeout := flag.Duration("interp-timeout", 180*time.Second, "interp optimization pass timeout")
@@ -1512,8 +1621,10 @@ func main() {
printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines")
printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed")
printCommands := flag.Bool("x", false, "Print commands")
flagJSON := flag.Bool("json", false, "print output in JSON format")
parallelism := flag.Int("p", runtime.GOMAXPROCS(0), "the number of build jobs that can run in parallel")
nodebug := flag.Bool("no-debug", false, "strip debug information")
nobounds := flag.Bool("nobounds", false, "do not emit bounds checks")
ocdCommandsString := flag.String("ocd-commands", "", "OpenOCD commands, overriding target spec (can specify multiple separated by commas)")
ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug")
port := flag.String("port", "", "flash port (can specify multiple candidates separated by commas)")
@@ -1536,16 +1647,13 @@ func main() {
// development it can be useful to not emit debug information at all.
skipDwarf := flag.Bool("internal-nodwarf", false, "internal flag, use -no-debug instead")
var flagJSON, flagDeps, flagTest bool
if command == "help" || command == "list" || command == "info" || command == "build" {
flag.BoolVar(&flagJSON, "json", false, "print data in JSON format")
}
var flagDeps, flagTest bool
if command == "help" || command == "list" {
flag.BoolVar(&flagDeps, "deps", false, "supply -deps flag to go list")
flag.BoolVar(&flagTest, "test", false, "supply -test flag to go list")
}
var outpath string
if command == "help" || command == "build" || command == "test" {
if command == "help" || command == "build" || command == "test" || command == "flash" {
flag.StringVar(&outpath, "o", "", "output filename")
}
@@ -1625,6 +1733,7 @@ func main() {
SkipDWARF: *skipDwarf,
Semaphore: make(chan struct{}, *parallelism),
Debug: !*nodebug,
Nobounds: *nobounds,
PrintSizes: *printSize,
PrintStacks: *printStacks,
PrintAllocs: printAllocs,
@@ -1634,7 +1743,6 @@ func main() {
Programmer: *programmer,
OpenOCDCommands: ocdCommands,
LLVMFeatures: *llvmFeatures,
PrintJSON: flagJSON,
Monitor: *monitor,
BaudRate: *baudrate,
Timeout: *timeout,
@@ -1684,33 +1792,20 @@ func main() {
usage(command)
os.Exit(1)
}
if options.Target == "" {
switch {
case options.GOARCH == "wasm":
switch options.GOOS {
case "js":
options.Target = "wasm"
case "wasip1":
options.Target = "wasip1"
case "wasip2":
options.Target = "wasip2"
default:
fmt.Fprintln(os.Stderr, "GOARCH=wasm but GOOS is not set correctly. Please set GOOS to wasm, wasip1, or wasip2.")
os.Exit(1)
}
case filepath.Ext(outpath) == ".wasm":
fmt.Fprintln(os.Stderr, "you appear to want to build a wasm file, but have not specified either a target flag, or the GOARCH/GOOS to use.")
os.Exit(1)
}
if filepath.Ext(outpath) == ".wasm" && options.GOARCH != "wasm" && options.Target == "" {
fmt.Fprintln(os.Stderr, "you appear to want to build a wasm file, but have not specified either a target flag, or the GOARCH/GOOS to use.")
os.Exit(1)
}
err := Build(pkgName, outpath, options)
config, err := builder.NewConfig(options)
handleCompilerError(err)
err = Build(pkgName, outpath, config)
printBuildOutput(err, *flagJSON)
case "flash", "gdb", "lldb":
pkgName := filepath.ToSlash(flag.Arg(0))
if command == "flash" {
err := Flash(pkgName, *port, options)
handleCompilerError(err)
err := Flash(pkgName, *port, outpath, options)
printBuildOutput(err, *flagJSON)
} else {
if !options.Debug {
fmt.Fprintln(os.Stderr, "Debug disabled while running debugger?")
@@ -1718,7 +1813,7 @@ func main() {
os.Exit(1)
}
err := Debug(command, pkgName, *ocdOutput, options)
handleCompilerError(err)
printBuildOutput(err, *flagJSON)
}
case "run":
if flag.NArg() < 1 {
@@ -1728,7 +1823,7 @@ func main() {
}
pkgName := filepath.ToSlash(flag.Arg(0))
err := Run(pkgName, options, flag.Args()[1:])
handleCompilerError(err)
printBuildOutput(err, *flagJSON)
case "test":
var pkgNames []string
for i := 0; i < flag.NArg(); i++ {
@@ -1795,6 +1890,7 @@ func main() {
wd = ""
}
diagnostics.CreateDiagnostics(err).WriteTo(os.Stderr, wd)
os.Exit(1)
}
if !passed {
select {
@@ -1856,16 +1952,13 @@ func main() {
os.Exit(1)
}
config.GoMinorVersion = 0 // this avoids creating the list of Go1.x build tags.
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
cachedGOROOT, err := loader.GetCachedGoroot(config)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
if flagJSON {
if *flagJSON {
json, _ := json.MarshalIndent(struct {
Target *compileopts.TargetSpec `json:"target"`
GOROOT string `json:"goroot"`
@@ -1907,7 +2000,7 @@ func main() {
os.Exit(1)
}
var extraArgs []string
if flagJSON {
if *flagJSON {
extraArgs = append(extraArgs, "-json")
}
if flagDeps {
+60 -24
View File
@@ -35,6 +35,8 @@ const TESTDATA = "testdata"
var testTarget = flag.String("target", "", "override test target")
var testOnlyCurrentOS = flag.Bool("only-current-os", false, "")
var supportedLinuxArches = map[string]string{
"AMD64Linux": "linux/amd64",
"X86Linux": "linux/386",
@@ -158,20 +160,51 @@ func TestBuild(t *testing.T) {
return
}
t.Run("EmulatedCortexM3", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("cortex-m-qemu", sema), tests, t)
})
if !*testOnlyCurrentOS {
t.Run("EmulatedCortexM3", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("cortex-m-qemu", sema), tests, t)
})
t.Run("EmulatedRISCV", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("riscv-qemu", sema), tests, t)
})
t.Run("EmulatedRISCV", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("riscv-qemu", sema), tests, t)
})
t.Run("AVR", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("simavr", sema), tests, t)
})
t.Run("AVR", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("simavr", sema), tests, t)
})
t.Run("WebAssembly", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("wasm", sema), tests, t)
// Test with -gc=boehm.
t.Run("gc.go-boehm", func(t *testing.T) {
t.Parallel()
optionsBoehm := optionsFromTarget("wasm", sema)
optionsBoehm.GC = "boehm"
runTest("gc.go", optionsBoehm, t, nil, nil)
})
})
t.Run("WASIp1", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("wasip1", sema), tests, t)
// Test with -gc=boehm.
t.Run("gc.go-boehm", func(t *testing.T) {
t.Parallel()
optionsBoehm := optionsFromTarget("wasip1", sema)
optionsBoehm.GC = "boehm"
runTest("gc.go", optionsBoehm, t, nil, nil)
})
})
t.Run("WASIp2", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("wasip2", sema), tests, t)
})
}
if runtime.GOOS == "linux" {
for name, osArch := range supportedLinuxArches {
@@ -191,18 +224,13 @@ func TestBuild(t *testing.T) {
options := optionsFromOSARCH("linux/mipsle/softfloat", sema)
runTest("cgo/", options, t, nil, nil)
})
t.Run("WebAssembly", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("wasm", sema), tests, t)
})
t.Run("WASI", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("wasip1", sema), tests, t)
})
t.Run("WASIp2", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("wasip2", sema), tests, t)
})
} else if runtime.GOOS == "windows" {
if runtime.GOARCH != "386" {
t.Run("Windows386", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromOSARCH("windows/386", sema), tests, t)
})
}
}
}
@@ -396,10 +424,12 @@ func optionsFromOSARCH(osarch string, sema chan struct{}) compileopts.Options {
}
func runTest(name string, options compileopts.Options, t *testing.T, cmdArgs, environmentVars []string) {
t.Helper()
runTestWithConfig(name, t, options, cmdArgs, environmentVars)
}
func runTestWithConfig(name string, t *testing.T, options compileopts.Options, cmdArgs, environmentVars []string) {
t.Helper()
// Get the expected output for this test.
// Note: not using filepath.Join as it strips the path separator at the end
// of the path.
@@ -675,6 +705,10 @@ func TestWasmExport(t *testing.T) {
// again.
checkResult("reentrantCall(2, 3)", mustCall(mod.ExportedFunction("reentrantCall").Call(ctx, 2, 3)), []uint64{5})
checkResult("reentrantCall(1, 8)", mustCall(mod.ExportedFunction("reentrantCall").Call(ctx, 1, 8)), []uint64{9})
// Check that goroutines started inside //go:wasmexport don't
// block the called function from returning.
checkResult("goroutineExit()", mustCall(mod.ExportedFunction("goroutineExit").Call(ctx)), nil)
}
// Add wasip1 module.
@@ -844,6 +878,7 @@ func TestWasmExit(t *testing.T) {
// Check whether the output of a test equals the expected output.
func checkOutput(t *testing.T, filename string, actual []byte) {
t.Helper()
expectedOutput, err := os.ReadFile(filename)
if err != nil {
t.Fatal("could not read output file:", err)
@@ -852,6 +887,7 @@ func checkOutput(t *testing.T, filename string, actual []byte) {
}
func checkOutputData(t *testing.T, expectedOutput, actual []byte) {
t.Helper()
expectedOutput = bytes.ReplaceAll(expectedOutput, []byte("\r\n"), []byte("\n"))
actual = bytes.ReplaceAll(actual, []byte("\r\n"), []byte("\n"))
+3 -3
View File
@@ -35,8 +35,8 @@ func Monitor(executable, port string, config *compileopts.Config) error {
// Use the RTT interface, which is documented (in part) here:
// https://wiki.segger.com/RTT
// Try to find the "machine.rttSerialInstance" symbol, which is the RTT
// control block.
// Try to find the "_SEGGER_RTT" symbol (machine.rttSerialInstance)
// symbol, which is the RTT control block.
file, err := elf.Open(executable)
if err != nil {
return fmt.Errorf("could not open ELF file to determine RTT control block: %w", err)
@@ -48,7 +48,7 @@ func Monitor(executable, port string, config *compileopts.Config) error {
}
var address uint64
for _, symbol := range symbols {
if symbol.Name == "machine.rttSerialInstance" {
if symbol.Name == "_SEGGER_RTT" {
address = symbol.Value
break
}
+18 -21
View File
@@ -1,6 +1,9 @@
package rand
import "errors"
import (
"errors"
"unsafe"
)
func init() {
Reader = &reader{}
@@ -16,28 +19,22 @@ func (r *reader) Read(b []byte) (n int, err error) {
return
}
var randomByte uint32
for i := range b {
// Call rand_s every four bytes because it's a C int (always 32-bit in
// Windows).
if i%4 == 0 {
errCode := libc_rand_s(&randomByte)
if errCode != 0 {
// According to the documentation, it can return an error.
return n, errRandom
}
} else {
randomByte >>= 8
}
b[i] = byte(randomByte)
// Use the old RtlGenRandom, introduced in Windows XP.
// Even though the documentation says it is deprecated, it is widely used
// and probably won't go away anytime soon.
// See for example: https://github.com/golang/go/issues/33542
// For Windows 7 and newer, we might switch to ProcessPrng in the future
// (which is a documented function and might be a tiny bit faster).
ok := libc_RtlGenRandom(unsafe.Pointer(&b[0]), len(b))
if !ok {
return 0, errRandom
}
return len(b), nil
}
// Cryptographically secure random number generator.
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/rand-s?view=msvc-170
// errno_t rand_s(unsigned int* randomValue);
// This function is part of advapi32.dll, and is called SystemFunction036 for
// some reason. It's available on Windows XP and newer.
// See: https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
//
//export rand_s
func libc_rand_s(randomValue *uint32) int32
//export SystemFunction036
func libc_RtlGenRandom(buf unsafe.Pointer, len int) bool
+4
View File
@@ -63,6 +63,10 @@ func SecCertificateCopyData(cert CFRef) ([]byte, error) {
return nil, errors.New("not implemented")
}
func SecTrustCopyCertificateChain(trustObj CFRef) (CFRef, error) {
return 0, errors.New("not implemented")
}
func SecTrustEvaluateWithError(trustObj CFRef) (int, error) {
return 0, errors.New("not implemented")
}
+5
View File
@@ -146,6 +146,11 @@ const (
SYST_CALIB_NOREF = 0x80000000 // Bit NOREF.
)
// ClearPendingIRQ clears the pending status of the interrupt.
func ClearPendingIRQ(irq uint32) {
NVIC.ICPR[irq>>5].Set(1 << (irq & 0x1F))
}
// Enable the given interrupt number.
func EnableIRQ(irq uint32) {
NVIC.ISER[irq>>5].Set(1 << (irq & 0x1F))
+58
View File
@@ -275,3 +275,61 @@ const (
DPC CSR = 0x7B1 // Debug PC.
DSCRATCH CSR = 0x7B2 // Debug scratch register.
)
// Bitfields for the CSR registers above.
const (
// MSTATUS (common bits between RV32 and RV64)
MSTATUS_SIE = 1 << 1
MSTATUS_MIE = 1 << 3
MSTATUS_SPIE = 1 << 5
MSTATUS_UBE = 1 << 6
MSTATUS_MPIE = 1 << 7
MSTATUS_SPP = 1 << 8
MSTATUS_MPRV = 1 << 17
MSTATUS_SUM = 1 << 18
MSTATUS_MXR = 1 << 19
MSTATUS_TVM = 1 << 20
MSTATUS_TW = 1 << 21
MSTATUS_TSR = 1 << 22
MIE_SSIE = 1 << 1
MIE_MSIE = 1 << 3
MIE_STIE = 1 << 5
MIE_MTIE = 1 << 7
MIE_SEIE = 1 << 9
MIE_MEIE = 1 << 11
MIP_SSIP = 1 << 1
MIP_MSIP = 1 << 3
MIP_STIP = 1 << 5
MIP_MTIP = 1 << 7
MIP_SEIP = 1 << 9
MIP_MEIP = 1 << 11
)
// Interrupt constants
const (
// MCAUSE values with the topmost bit (interrupt bit) set.
SupervisorSoftwareInterrupt = 1
MachineSoftwareInterrupt = 3
SupervisorTimerInterrupt = 5
MachineTimerInterrupt = 7
SupervisorExternalInterrupt = 9
MachineExternalInterrupt = 11
// MCAUSE values with the topmost bit (interrupt bit) clear.
InstructionAddressMisaligned = 0
InstructionAccessFault = 1
IllegalInstruction = 2
Breakpoint = 3
LoadAddressMisaligned = 4
LoadAccessFault = 5
StoreOrAMOAddressMisaligned = 6
StoreOrAMOAccessFault = 7
EnvironmentCallFromUMode = 8
EnvironmentCallFromSMode = 9
EnvironmentCallFromMMode = 11
InstructionPageFault = 12
LoadPageFault = 13
StoreOrAMOPageFault = 15
)
+39
View File
@@ -3,8 +3,47 @@
.type _start,@function
_start:
// If we're on a multicore system, we need to wait for hart 0 to wake us up.
#if TINYGO_CORES > 1
csrr a0, mhartid
// Hart 0 stack
bnez a0, 1f
la sp, _stack_top
1:
// Hart 1 stack
li a1, 1
bne a0, a1, 2f
la sp, _stack1_top
2:
// Hart 2 stack
#if TINYGO_CORES >= 3
li a1, 2
bne a0, a1, 3f
la sp, _stack2_top
#endif
3:
// Hart 3 stack
#if TINYGO_CORES >= 4
li a1, 3
bne a0, a1, 4f
la sp, _stack3_top
#endif
4:
// done
#if TINYGO_CORES > 4
#error only up to 4 cores are supported at the moment!
#endif
#else
// Load the stack pointer.
la sp, _stack_top
#endif
// Load the globals pointer. The program will load pointers relative to this
// register, so it must be set to the right value on startup.
+51
View File
@@ -0,0 +1,51 @@
// Hand created file. DO NOT DELETE.
// Definitions that are missing in src/device/rp/rp2040.go generated from SVDs
//go:build rp && rp2040
package rp
// DMA: 2.5.3.1. System DREQ Table from RP2040 Datasheet
// https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
const (
DREQ_PIO0_TX0 = 0
DREQ_PIO0_TX1 = 1
DREQ_PIO0_TX2 = 2
DREQ_PIO0_TX3 = 3
DREQ_PIO0_RX0 = 4
DREQ_PIO0_RX1 = 5
DREQ_PIO0_RX2 = 6
DREQ_PIO0_RX3 = 7
DREQ_PIO1_TX0 = 8
DREQ_PIO1_TX1 = 9
DREQ_PIO1_TX2 = 10
DREQ_PIO1_TX3 = 11
DREQ_PIO1_RX0 = 12
DREQ_PIO1_RX1 = 13
DREQ_PIO1_RX2 = 14
DREQ_PIO1_RX3 = 15
DREQ_SPI0_TX = 16
DREQ_SPI0_RX = 17
DREQ_SPI1_TX = 18
DREQ_SPI1_RX = 19
DREQ_UART0_TX = 20
DREQ_UART0_RX = 21
DREQ_UART1_TX = 22
DREQ_UART1_RX = 23
DREQ_PWM_WRAP0 = 24
DREQ_PWM_WRAP1 = 25
DREQ_PWM_WRAP2 = 26
DREQ_PWM_WRAP3 = 27
DREQ_PWM_WRAP4 = 28
DREQ_PWM_WRAP5 = 29
DREQ_PWM_WRAP6 = 30
DREQ_PWM_WRAP7 = 31
DREQ_I2C0_TX = 32
DREQ_I2C0_RX = 33
DREQ_I2C1_TX = 34
DREQ_I2C1_RX = 35
DREQ_ADC = 36
DREQ_XIP_STREAM = 37
DREQ_XIP_SSITX = 38
DREQ_XIP_SSIRX = 39
)
+66
View File
@@ -0,0 +1,66 @@
// Hand created file. DO NOT DELETE.
// Definitions that are missing in src/device/rp/rp2350.go generated from SVDs
//go:build rp && rp2350
package rp
// DMA: 12.6.4.1. System DREQ Table from RP2350 Datasheet
// https://datasheets.raspberrypi.com/rp2350/rp2350-datasheet.pdf
const (
DREQ_PIO0_TX0 = 0
DREQ_PIO0_TX1 = 1
DREQ_PIO0_TX2 = 2
DREQ_PIO0_TX3 = 3
DREQ_PIO0_RX0 = 4
DREQ_PIO0_RX1 = 5
DREQ_PIO0_RX2 = 6
DREQ_PIO0_RX3 = 7
DREQ_PIO1_TX0 = 8
DREQ_PIO1_TX1 = 9
DREQ_PIO1_TX2 = 10
DREQ_PIO1_TX3 = 11
DREQ_PIO1_RX0 = 12
DREQ_PIO1_RX1 = 13
DREQ_PIO1_RX2 = 14
DREQ_PIO1_RX3 = 15
DREQ_PIO2_TX0 = 16
DREQ_PIO2_TX1 = 17
DREQ_PIO2_TX2 = 18
DREQ_PIO2_TX3 = 19
DREQ_PIO2_RX0 = 20
DREQ_PIO2_RX1 = 21
DREQ_PIO2_RX2 = 22
DREQ_PIO2_RX3 = 23
DREQ_SPI0_TX = 24
DREQ_SPI0_RX = 25
DREQ_SPI1_TX = 26
DREQ_SPI1_RX = 27
DREQ_UART0_TX = 28
DREQ_UART0_RX = 29
DREQ_UART1_TX = 30
DREQ_UART1_RX = 31
DREQ_PWM_WRAP0 = 32
DREQ_PWM_WRAP1 = 33
DREQ_PWM_WRAP2 = 34
DREQ_PWM_WRAP3 = 35
DREQ_PWM_WRAP4 = 36
DREQ_PWM_WRAP5 = 37
DREQ_PWM_WRAP6 = 38
DREQ_PWM_WRAP7 = 39
DREQ_PWM_WRAP8 = 40
DREQ_PWM_WRAP9 = 41
DREQ_PWM_WRAP10 = 42
DREQ_PWM_WRAP11 = 43
DREQ_I2C0_TX = 44
DREQ_I2C0_RX = 45
DREQ_I2C1_TX = 46
DREQ_I2C1_RX = 47
DREQ_ADC = 48
DREQ_XIP_STREAM = 49
DREQ_XIP_QMITX = 50
DREQ_XIP_QMIRX = 51
DREQ_HSTX = 52
DREQ_CORESIGHT = 53
DREQ_SHA256 = 54
)
+40
View File
@@ -0,0 +1,40 @@
package main
import (
"machine"
"runtime"
"sync"
"time"
)
const N = 500000
const Ngoro = 4
func main() {
start := time.Now()
var wg sync.WaitGroup
wg.Add(Ngoro)
for i := 0; i < Ngoro; i++ {
go adder(&wg, N)
}
wg.Wait()
elapsed := time.Since(start)
goroutineCtxSwitchOverhead := (elapsed / (Ngoro * N)).String()
elapsedstr := elapsed.String()
machine.LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
for {
println("bench:", elapsedstr, "goroutine ctx switch:", goroutineCtxSwitchOverhead)
machine.LED.High()
time.Sleep(elapsed)
machine.LED.Low()
time.Sleep(elapsed)
}
}
func adder(wg *sync.WaitGroup, num int) {
for i := 0; i < num; i++ {
runtime.Gosched()
}
wg.Done()
}
+15
View File
@@ -0,0 +1,15 @@
package main
import (
"machine"
"machine/usb/msc"
"time"
)
func main() {
msc.Port(machine.Flash)
for {
time.Sleep(2 * time.Second)
}
}
+7
View File
@@ -8,3 +8,10 @@ import "unsafe"
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
return p
}
func Escape[T any](x T) T {
// This function is either implemented in the compiler, or left undefined
// for some variation of T. The body of this function should not be compiled
// as-is.
panic("internal/abi.Escape: unreachable (implemented in the compiler)")
}
+51
View File
@@ -0,0 +1,51 @@
package cm
// CaseUnmarshaler returns an function that can unmarshal text into
// [variant] or [enum] case T.
//
// [enum]: https://component-model.bytecodealliance.org/design/wit.html#enums
// [variant]: https://component-model.bytecodealliance.org/design/wit.html#variants
func CaseUnmarshaler[T ~uint8 | ~uint16 | ~uint32](cases []string) func(v *T, text []byte) error {
if len(cases) <= linearScanThreshold {
return func(v *T, text []byte) error {
if len(text) == 0 {
return &emptyTextError{}
}
s := string(text)
for i := 0; i < len(cases); i++ {
if cases[i] == s {
*v = T(i)
return nil
}
}
return &noMatchingCaseError{}
}
}
m := make(map[string]T, len(cases))
for i, v := range cases {
m[v] = T(i)
}
return func(v *T, text []byte) error {
if len(text) == 0 {
return &emptyTextError{}
}
c, ok := m[string(text)]
if !ok {
return &noMatchingCaseError{}
}
*v = c
return nil
}
}
const linearScanThreshold = 16
type emptyTextError struct{}
func (*emptyTextError) Error() string { return "empty text" }
type noMatchingCaseError struct{}
func (*noMatchingCaseError) Error() string { return "no matching case" }
+1 -1
View File
@@ -1,4 +1,4 @@
// Package cm contains types and functions for interfacing with the WebAssembly Component Model.
// Package cm provides types and functions for interfacing with the WebAssembly Component Model.
//
// The types in this package (such as [List], [Option], [Result], and [Variant]) are designed to match the memory layout
// of [Component Model] types as specified in the [Canonical ABI].

Some files were not shown because too many files have changed in this diff Show More