Compare commits

...

1863 Commits

Author SHA1 Message Date
Ayke van Laethem dd6fa89aa6 Release 0.32.0 2024-06-16 18:24:36 +02:00
leongross d513cae5d2 add SetReadDeadline stub 2024-06-15 11:34:06 +02:00
Ayke van Laethem e612f7cf3f Add smoke tests for machine package
The machine package wasn't tested for every board. Therefore, add a new
serial-like test that also tries to import the machine package. This
should highlight potential issues in the future.
2024-06-14 17:28:31 +02:00
Ayke van Laethem 385a7920e6 compiler: fix race condition by applying a proposed patch
This commit switches to v0.22.0 of golang.org/x/tools and then applies
https://go-review.googlesource.com/c/tools/+/590815 to fix the race
condition.

In my testing, it seems to fix these issues.
2024-06-12 14:46:47 +02:00
Ayke van Laethem 077b35e9ad all: drop support for Go 1.18
Go 1.18 has been unsupported for quite a while now (the oldest supported
version is Go 1.21). But more importantly, the golang.org/x/tools module
now requires Go 1.19 or later. So we'll drop this older version.
2024-06-12 14:46:47 +02:00
deadprogram 880e940417 targets: add cyw43439 tag to badger2040-w and also add new pico-w target for wireless support
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-06-11 07:57:58 +02:00
L. Pereira ad6c89bf64 transform/rtcalls: Bail fast if can't convert pointer
There's no need to keep looping if one of the uses makes it impossible
to convert a call to `runtime.stringToBytes()` with a raw pointer.

Signed-off-by: L. Pereira <l.pereira@fastly.com>
2024-06-10 12:39:55 +02:00
Ayke van Laethem ae6220262a cgo: implement shift operations in preprocessor macros 2024-06-07 20:40:27 +02:00
leongross e731a31eb9 update fpm ci, fixup import
Signed-off-by: leongross <leon.gross@9elements.com>
2024-06-06 16:24:33 +02:00
leongross 3023ba584b Add process.Release for unix
Signed-off-by: leongross <leon.gross@9elements.com>
2024-06-06 16:24:33 +02:00
leongross 3a8ef33c72 add FindProcess for posix
Signed-off-by: leongross <leon.gross@9elements.com>
2024-06-06 16:24:33 +02:00
leongross 20b58a0128 Add signal stubs (#4270)
os: init signal ignore stub and add other stubs

Signed-off-by: leongross <leon.gross@9elements.com>
2024-06-02 09:52:31 +02:00
Damian Gryski bfccf3592a builder: make sure wasm-opt command line is printed if asked 2024-05-31 11:20:04 -07:00
Damian Gryski 272fea13e7 builder: keep un-wasm-opt'd .wasm if -work was passed 2024-05-31 11:20:04 -07:00
Damian Gryski b6fd0c818e src/reflect: uncomment more tests that pass 2024-05-29 13:56:04 -07:00
Ayke van Laethem c383a407e3 cgo: do a basic test that math functions work
They should, but we weren't testing this.
I discovered this while working on
https://github.com/tinygo-org/macos-minimal-sdk/pull/4 which will likely
make math.h not work anymore. So I wanted to make sure we have a test in
place before we update that dependency.
2024-05-29 21:51:39 +02:00
diamondburned 7b7601d77c os/user: add stubs for Lookup{,Group} and Group 2024-05-28 23:56:51 +02:00
frenkel26 f7c0466f78 compiler,reflect: fix NumMethods for Interface type 2024-05-28 14:09:59 +02:00
Ayke van Laethem 81ce7fb738 LLVM 18 support 2024-05-24 19:12:26 +02:00
Ayke van Laethem c2776dcf78 main: add -serial=rtt flag as possible option
I added this a while ago but forgot to change the help documentation.
2024-05-24 17:37:49 +02:00
leongross ad0340d437 fix fpm ci installion
Signed-off-by: leongross <leon.gross@9elements.com>
2024-05-18 12:00:28 +02:00
leongross 30c4df16f2 add aes generic aliases 2024-05-14 20:44:48 +02:00
Randy Reddig fe27b674cd reflect: use int in StringHeader and SliceHeader on non-AVR platforms (#4156) 2024-05-14 14:04:54 +02:00
Mateusz Nowak c78dbcd3f2 Support UF2 drives with space in their name on Linux
Some devices, such as Seeed Studio XIAO with Adafruit bootloader, use complex names for UF2 device. With this fix applied, /proc/mounts should be parsed correctly
2024-05-14 13:58:44 +02:00
Johann Freymuth 8890b57ba0 Add I2C support for esp32 (#4259)
machine/esp32: add i2c support
2024-05-13 21:58:06 +02:00
deadprogram ee3a05f1de targets: add support for Badger2040 W
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-05-13 20:10:36 +02:00
Elias Naur 9307204111 Revert "flake.nix: explicitly add libcxx as dependency"
This reverts commit 7b8ae2d6b6.
2024-05-13 19:04:01 +02:00
Marco Manino 71878c2c0c Adding a comment 2024-05-13 16:49:18 +02:00
Marco Manino cef2a82c97 Checking for methodset existance 2024-05-13 16:49:18 +02:00
Johann Freymuth 1d9f26cee1 targets: add support for m5paper 2024-05-12 16:09:27 +02:00
sago35 6e58c44390 machine: add TxFifoFreeLevel() for CAN 2024-05-10 18:45:06 +02:00
deadprogram 7d6b667bba machine/stm32: add i2c Frequency and SetBaudRate() function for boards that were missing implementation
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-05-08 10:57:46 +02:00
Christian Stewart 72f30ca6ec Makefile: add lld to list of build targets for wasm-ld
The current list of targets does not build wasm-ld.

wasm-ld is a symlink created in ./llvm-build/bin pointing to ./lld.

Add the "lld" build target to get wasm-ld into ./llvm-build/bin.

Fixes a build failure where wasm-ld is not found.

Signed-off-by: Christian Stewart <christian@aperture.us>
2024-05-05 11:31:46 +02:00
deadprogram 293b620faf build: update llvm cache to use tagged LLVM source version
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-04-30 19:02:45 +02:00
Dan Kegel ad0af607ef Add 'make spell' target, fix what it finds. In .go files, only checks comments. 2024-04-30 07:47:11 +02:00
deadprogram da23cdeae4 make: use release esp-17.0.1_20240419 tag for source from espressif LLVM fork for reproducible builds
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-04-29 20:50:23 +02:00
Ayke van Laethem d419cc11bf simulator: add support for GetRNG
This is needed to be able to simulate the Gopher Badge code:
https://github.com/conejoninja/gopherbadge
2024-04-28 23:59:23 +02:00
Ayke van Laethem 441dfc98d7 simulator: fix I2C support
- Add ReadRegister and WriteRegister (because they're still used by
    some packages).
  - Fix out-of-bounds panic in I2C.Tx when either w or r has a length of
    zero (or is nil).
2024-04-28 23:05:49 +02:00
Elias Naur 2b3b870bfe mksnanov3: limit programming speed to 1800 kHz
Both of my development boards exhibit stability problems when
programming at the default 4000 kHz speed of the target/stmf32d4x
OpenOCD configuration.

Note that the speed limit must be set by an event handler, because it
is hard-coded by a similar event handler in stmf32f4x.cfg:

  $_TARGETNAME configure -event reset-init {
  	# Configure PLL to boost clock to HSI x 4 (64 MHz)
    ...

  	# Boost JTAG frequency
  	adapter speed 8000     <-- resolves to 4000 kHz by the SWD interface
  }

While here, replace the reference to the deprecated "stlink-v2"
configuration.
2024-04-27 13:02:20 +02:00
Ayke van Laethem 7748c4922e compileopts: fix race condition
Appending to a slice can lead to a race condition if the capacity of the
slice is larger than the length (and therefore the returned slice will
overwrite some fields in the underlying array).

This fixes that race condition. I don't know how severe this particular
one is. It shouldn't be that severe, but it is a bug and it makes it
easier to hunt for possibly more serious race conditions.
2024-04-27 11:12:19 +02:00
Elias Naur 50f700ddb5 runtime: skip negative sleep durations in sleepTicks
sleepTicks calls machineLightSleep with the duration cast to an unsigned
integer. This underflow for negative durations.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-04-27 09:52:44 +02:00
Ayke van Laethem f986ea84ac rp2040: fix timeUnit type
It should be int64 like for all other systems, not uint64.
2024-04-26 14:12:10 +02:00
sago35 797a5a2031 machine/thingplus_rp2040, machine/waveshare-rp2040-zero:add WS2812 definition 2024-04-24 08:50:53 +02:00
dkegel-fastly 3d433fe9f1 Lint: lint and fix src/{os,reflect} (#4228)
* lint: expand to src/{os,reflect}, fix or suppress what it found

* internal/tools/tools.go: the tools idiom requires a build tag guard to avoid go test complaints
2024-04-22 11:10:13 -07:00
hongkuang 1154212c15 chore: fix function names in comment
Signed-off-by: hongkuang <liurenhong@outlook.com>
2024-04-20 14:58:06 +02:00
Patrick Ting 22bf045c9a add stm32 nucleol476rg support 2024-04-19 20:50:00 +02:00
dkegel-fastly 39029cc376 Run Nick G's spellchecker github.com/client9/misspell, carefuly fix what it found (#4235) 2024-04-19 06:57:01 -07:00
Elias Naur 7122755725 compileopts: apply OpenOCD commands after target configuration
The openocd-commands option cannot refer to commands defined by the
target configuration. Lift this restriction by moving the commands to
after target loading.
2024-04-17 21:54:38 +02:00
leongross dcee228c4e add os.Link
Signed-off-by: leongross <leon.gross@9elements.com>
2024-04-14 16:56:53 +02:00
Dan Kegel 9d6e30701b lint: add "make lint" target, run it from ci
See https://github.com/tinygo-org/tinygo/issues/4225

Runs in both circleci and github, circleci is run on branch push, github is run on PR

Revive builds so fast, don't bother installing it; saves us wondering which one we get

Uses tools.go idiom to give control over linter versions to go.mod.

Also pacifies linter re AppendToGlobal as a token first fix.

TODO: gradually expand the number of directories that are linted,
uncomment more entries in revive.toml, and fix or suppress the
warnings lint finds.

TODO: add linters "go vet" and staticcheck

NOT TODO: don't add metalinters like golangci-lint that pull in
lots of new of dependencies; we'd rather not clutter go.mod that
much, let alone open ourselves up to the additional attack surface.
2024-04-13 18:57:31 +02:00
Ayke van Laethem 85b59e66da machine: add __tinygo_spi_tx function to simulator
This is much, _much_ faster than __tinygo_spi_transfer which can only
transfer a single byte at a time. This is especially important for
simulated displays.

I've already implemented the browser side of this on the playground and
have used this patch for local testing where it massively speeds up
display operations.
2024-04-13 11:38:18 +02:00
Ayke van Laethem 90b0bf646c rp2040: make all RP2040 boards available for simulation
This makes all rp2040 boards available for simulation using
-tags=<board_name>. Importantly, this includes the Gopher Badge which
I'm working on to add to the TinyGo Playground.
2024-04-04 19:34:01 +02:00
Ayke van Laethem c55ac9f28e rp2040: move UART0 and UART1 to common file
This is makes it easier to use these in simulation, plus it avoids
duplication. The only downside I see is that more UARTs get defined than
a board supports, but no existing code should break (no UARTs get
renamed for example).
2024-04-04 19:34:01 +02:00
leongross 2733e376bd fix square alias for ed25519
Signed-off-by: leongross <leon.gross@9elements.com>
2024-04-03 12:35:20 +02:00
Ayke van Laethem 331cfb65b7 nix: fix wasi-libc include headers
Apparently Nix really doesn't like --sysroot, so we have to use
`-nostdlibinc` and `-isystem` instead.
2024-03-28 15:46:00 +01:00
Randy Reddig 055950421a all: change references of 'wasi' to 'wasip1'; test hygiene 2024-03-27 16:01:40 +01:00
Randy Reddig cfcc894855 targets: add wasi.json that inherits wasip1.json
PR feedback
2024-03-27 16:01:40 +01:00
Randy Reddig 8bd0155c51 os, testing: just check runtime.GOOS == "wasip1" 2024-03-27 16:01:40 +01:00
Randy Reddig 32a056c32a syscall: use libc_getpagesize instead of hard-coded constant
TODO: should Getpagesize on wasip1 just return wasmPageSize?
2024-03-27 16:01:40 +01:00
Randy Reddig 8e8ad9004f all: replace target=wasi with target=wasip1
This eliminates the 'wasi' build tag in favor of 'GOOS=wasip1', introduced in Go 1.21.

For backwards compatablity, -target=wasi is a synonym for -target=wasip1.
2024-03-27 16:01:40 +01:00
Patrick Lindsay 62d8cdb218 Map the rest of the pinout 2024-03-27 11:55:25 +01:00
Patrick Lindsay b6fdbee14e Begin implementing support for Adafruit ESP32 Feather V2 2024-03-27 11:55:25 +01:00
deadprogram a5ceb793be builder: add check for error on creating needed directory as suggested by @b0ch3nski
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-03-26 12:20:50 +01:00
Ayke van Laethem 7c546525ea wasm-unknown: add math and memory builtins that LLVM needs
This new library is needed for wasm targets that aren't WASI and don't
need/want a libc, but still need some intrinsics that are generated by
LLVM.
2024-03-26 12:20:50 +01:00
Ayke van Laethem d628e3e2cb ci: don't add --recursive when updating submodules
It's not generally needed. It was added in
https://github.com/tinygo-org/tinygo/pull/3958 to fix an issue with
binaryen that has since been fixed in a different way, so we don't need
the googletest dependency anymore.
2024-03-24 13:04:47 +01:00
Jonathan Böcker d97e4dbccf Add smoke test for pca10059-s140v7 2024-03-23 10:23:07 +01:00
Jonathan Böcker a7ddb33bea Add pca10059-s140v7 as a target 2024-03-23 10:23:07 +01:00
Ayke van Laethem 8a93196f1f Makefile: allow overriding the packages to test in make test
This way you can for example run `make test GOTESTPKGS=./builder` to
only test the builder package.
I've often done this by manually modifying the Makefile, so having a
make parameter available would make this much easier.
2024-03-22 23:18:10 +01:00
Anders Savill 6714974aba feather-nrf52840-sense doesn't use LFXO 2024-03-21 20:29:02 +01:00
deadprogram d67ec3b266 goenv: put back @sago35 update to new v0.32.0 development version
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-03-21 06:41:10 +01:00
Ayke van Laethem 78775007fa wasm: fix symbol table index for archives
The symbol table was generated incorrectly. The correct way is to use
the custom linking WebAssembly section, which I implemented in go-wasm
for this purpose.

This fixes https://github.com/tinygo-org/tinygo/issues/4114 and is a
prerequisite for https://github.com/tinygo-org/tinygo/pull/4176.
2024-03-19 07:12:22 +01:00
Ayke van Laethem ad4d722f54 all: move -panic=trap support to the compiler/runtime
Support for `-panic=trap` was previously a pass in the optimization
pipeline. This change moves it to the compiler and runtime, which in my
opinion is a much better place.

As a side effect, it also fixes
https://github.com/tinygo-org/tinygo/issues/4161 by trapping inside
runtime.runtimePanicAt and not just runtime.runtimePanic.

This change also adds a test for the list of imported functions. This is
a more generic test where it's easy to add more tests for WebAssembly
file properties, such as exported functions.
2024-03-19 07:10:51 +01:00
deadprogram 6384ecace0 docs: update CHANGELOG for 0.31.2 patch release
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-03-10 15:13:23 +01:00
deadprogram 38881a2850 goenv: update to v0.31.2 for patch release
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-03-10 15:13:23 +01:00
deadprogram 0f1cf14743 net: update to net package with Buffers implementation
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-03-09 10:56:14 -05:00
sago35 7c34f7704e goenv: update to new v0.32.0 development version 2024-03-04 19:29:26 +01:00
Randy Reddig 377415a6c3 runtime: add Frame.Entry field
This enables compatibility with golang.org/x/tools/internal/pkgbits.

https://github.com/golang/tools/blob/master/internal/pkgbits/frames_go17.go
2024-03-02 21:17:34 +01:00
deadprogram 1e13c6d18f syscall: add wasm_unknown to some additional files so it can compile more code
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-03-02 20:49:56 +01:00
deadprogram 14121f4b0e all: update for 0.31.1
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-28 13:22:23 +01:00
deadprogram 7768195835 net: update to latest main
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-28 13:22:23 +01:00
deadprogram c095b7e9c4 build: only use GHA cache for docker dev builds, ignore the previous saved build-context
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-28 08:57:35 +01:00
Ayke van Laethem 1f6d34d995 interp: make getelementptr offsets signed
getelementptr offsets are signed, not unsigned. Yet they were used as
unsigned integers in interp.
Somehow this worked most of the time, until finally there was some code
that did a getelementptr with a negative index.
2024-02-27 15:16:38 +01:00
Ayke van Laethem 9951eb9990 interp: return a proper error message when indexing out of range
This helps debug issues inside interp.
2024-02-27 15:16:38 +01:00
deadprogram c8f77d26a8 docker: update final build stage to go1.22
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-27 11:57:37 +01:00
Ayke van Laethem 8eaa9bd8d0 ci: fix binaryen build
Disable the googletest dependency so that we can avoid that submodule
dependency.
2024-02-26 15:30:41 +01:00
Ayke van Laethem 6061f3db92 all: version 0.31.0 2024-02-26 09:37:39 +01:00
Akshay Pai 410aa0e0d8 Stub CallSlice for Value 2024-02-25 14:45:50 +01:00
deadprogram c66836cf3a targets: add support for Thumby
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-23 14:00:57 +01:00
Ayke van Laethem ca9211b582 main: make ports subcommand more verbose
By listing column headers and printing a message when no ports are
found, it should be a bit easier to use.
2024-02-23 08:37:26 +01:00
Ayke van Laethem cb7d470ba4 main: change monitor -info to ports
I believe this provides a better UX.
2024-02-23 08:37:26 +01:00
Ayke van Laethem 5baee9a8ee ci: switch to Go 1.22 2024-02-20 21:58:09 +01:00
Ayke van Laethem c47f52b546 Dockerfile: reduce size of resulting image
This reduces the size of the Docker image from 13GB to 1.71GB, and
should therefore make CI of the drivers package much faster. It should
hopefully also avoid the out-of-space problem we currently have when
building the smoke tests for the drivers repo.

 This size reduction is done by using multistage builds and only copying
 the necessary files in the final stage.
2024-02-20 21:00:22 +01:00
Ayke van Laethem a2588d8db3 compileopts: remove workaround for LLVM 16
This workaround is no longer needed now that we've switched to LLVM 17
where this bug has been fixed upstream:
https://github.com/espressif/llvm-project/pull/84
2024-02-19 23:29:44 +01:00
Ayke van Laethem f529b6071d interp: do not register runtime timers during interp
The runtime hasn't been initialized yet so this leads to problems.

This fixes https://github.com/tinygo-org/tinygo/issues/4123.
2024-02-19 22:17:19 +01:00
Ayke van Laethem 5557e97888 device: update SVD files
This updates lib/cmsis-svd, pulling in the updates to the Espressif SVD
files here:
https://github.com/cmsis-svd/cmsis-svd-data/pull/3

This is needed for wifi/BLE support on the ESP32-C3 (the older SVD files
were missing some necessary interrupts).
2024-02-19 19:10:21 +01:00
Ayke van Laethem d04b07fa8b compileopts: always enable CGo
CGo is needed for the rp2040 and for macOS (GOOS=darwin), without it
these targets just won't work. And there really isn't a benefit from
disabling CGo: we don't need any external linkers for example.

This avoids a somewhat common issue of people having CGO_ENABLED=0
somewhere in their environment and not understanding why things don't
work. See for example: https://github.com/tinygo-org/tinygo/issues/3450
2024-02-19 17:53:36 +01:00
Ayke van Laethem 7486277012 all: make TinyGo code usable with "big Go" CGo
I managed to get CGo sort-of working in VSCode (meaning that it will
typecheck code in the IDE itself) using a few crude hacks, but it
requires a few minor changes to the TinyGo standard library.

I intend to eventually add this support in the TinyGo extension for
VSCode directly, but for now I've manually updated .vscode/settings.json
to get IDE support. In any case, it would be nice to have this for when
I hopefully add this to the TinyGo extension eventually.
2024-02-19 15:49:36 +01:00
deadprogram 36d60b8349 targets/wasm_unknown: remove _start to _initialize to match WASI
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-17 10:18:00 +01:00
deadprogram c55191283b builder: add 'wasm-unknown' to list of targets for clang features verification
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-17 10:18:00 +01:00
deadprogram ad30085b93 targets/wasm_unknown: use proper defaults for GC
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-17 10:18:00 +01:00
deadprogram e9ca41735a make: add smoketest for wasm-unknown target
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-15 17:54:18 +01:00
deadprogram df1f83f4e1 examples: add example for use with wasm-unknown target
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-15 17:54:18 +01:00
deadprogram 5879d785a9 target/wasm_unknown: remove bulk memory and use imported memory for extreme tinyness
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-15 17:54:18 +01:00
deadprogram 186018abeb runtime, targets: some WIP on wasm unknown in part from PR #3072
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-15 17:54:18 +01:00
BCG 828b9614c2 nrf52840: generic board support (#4121)
machine/nrf52840: generic board support
2024-02-12 10:37:19 +01:00
Xudong Zheng f5e933cd4d machine/rp2040: set XOSC startup delay multiplier
XOSC requires additional time to stablize on certain RP2040 boards.

Signed-off-by: Xudong Zheng <7pkvm5aw@slicealias.com>
2024-02-11 11:59:54 +01:00
Ayke van Laethem 0952b1b984 compileopts: set 'purego' build tag by default
This is needed for various crypto libraries.
2024-02-11 10:43:28 +01:00
Ayke van Laethem ed55f56d85 ci: update from Node.js 16 to Node.js 18
Node.js 16 is no longer supported, so we can drop support for it as
well.

This also means updating a whole lot of GitHub Actions versions, because
they were updated to work on Node.js 20 instead. For most actions this
should be a relatively small change, but the upload-aftifact action has
had some major changes (which should generally improve things a lot).
2024-02-11 09:43:22 +01:00
Ayke van Laethem edb8766aab esp32: switch over to the official SVD file 2024-02-09 16:12:21 +01:00
deadprogram 413bb55e2c build: remove more files from host on Docker build to avoid running out of disk space
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-02-07 07:31:54 +01:00
Ayke van Laethem 0db1a4bec1 gi: add macOS ARM64 builder
This means we can finally release native arm64 builds of TinyGo on
macOS!

Also update from macOS 11 to macOS 12, because macOS 11 is not supported
anymore.
2024-02-05 20:43:43 +01:00
Damian Gryski 2867da164d Allow larger systems to have a larger max stack alloc
Fixes #3331
2024-01-31 17:51:55 +01:00
Elias Naur 7b8ae2d6b6 flake.nix: explicitly add libcxx as dependency
Without this change, my tinygo builds crash with

SIGSEGV: segmentation violation
PC=0x10884f87c m=16 sigcode=2
signal arrived during cgo execution

goroutine 378 [syscall]:
runtime.cgocall(0x100631e44, 0x1401755be88)
	/nix/store/4hf287252ilsdf2w36mfm8fa0rvbf33w-go-1.21.4/share/go/src/runtime/cgocall.go:157 +0x44 fp=0x1401755be50 sp=0x1401755be10 pc=0x1002a5084
tinygo.org/x/go-llvm._Cfunc_LLVMGoWriteThinLTOBitcodeToMemoryBuffer(0x123614160)
	_cgo_gotypes.go:6078 +0x34 fp=0x1401755be80 sp=0x1401755be50 pc=0x1004b66b4
...

and reports using LLVM 16:

$ tinygo version
tinygo version 0.31.0-dev darwin/arm64 (using go version go1.21.4 and LLVM version 16.0.6)

I don't know why libcxx-16 is being included, but explicitly specifying
llvmPackages_17.libcxx fixes the crash and version skew.
2024-01-31 14:56:16 +01:00
Damian Gryski 5b8127fd4e reflect: move indirect values into interface when setting interfaces
Fixes #4040
2024-01-31 13:48:02 +01:00
= cc3e785692 Remove unused value 2024-01-29 16:23:35 +01:00
BCG 0ea5cfc8fe rp2040: add definition for machine.PinToggle 2024-01-29 12:38:06 +01:00
Ayke van Laethem 70f1a5429a esp32c3: update linker script to support binary blobs
To be able to link with the binary blobs that provide wifi and BLE, the
linker script needs a few tweaks.
2024-01-27 14:11:09 +01:00
Ayke van Laethem 2fb2113168 esp32c3: add more ROM functions
These functions are used by the binary blobs that implement wifi/BLE on
the ESP32-C3. While this is a lot of lines of linker script, I think
it's a good idea to add them here (instead of in a separate library)
because they're part of the ESP32-C3 hardware.
2024-01-27 14:11:09 +01:00
soypat cb39611389 sync: implement trylock 2024-01-26 14:30:06 +01:00
Elias Naur 45764325b4 targets: add motor control pin definitions for MKS Nano V3x boards
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-01-23 21:04:22 +01:00
Elias Naur bb66232164 targets: add support for the MKS Robin Nano V3.x
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-01-23 21:04:22 +01:00
Daniel Esteban 9679e7f1cc fix typo 2024-01-23 16:52:37 +01:00
Ayke van Laethem 6cdfc298cf all: switch to LLVM 17 by default 2024-01-20 10:50:42 +01:00
Ayke van Laethem 9a4bfd0e96 ci: fix sizediff error when changing the LLVM version 2024-01-20 10:50:42 +01:00
Ayke van Laethem ee3106be98 reflect: update to Go 1.22 semantics
The IsZero function was changed slightly in Go 1.22, so we'll need to
update it.

While this could in theory break existing programs that rely on the old
behavior, they'd also break with the imminent Go 1.22 release so I don't
think this is a real problem.
2024-01-20 08:53:49 +01:00
Ayke van Laethem 57f49af726 loader: make sure Go version is plumbed through
This fixes the new loop variable behavior in Go 1.22.

Specifically:
  * The compiler (actually, the x/tools/go/ssa package) now correctly
    picks up the Go version.
  * If a module doesn't specify the Go version, the current Go version
    (from the `go` tool and standard library) is used. This fixes
    `go run`.
  * The tests in testdata/ that use a separate directory are now
    actually run in that directory. This makes it possible to use a
    go.mod file there.
  * There is a test to make sure old Go modules still work with the old
    Go behavior, even on a newer Go version.
2024-01-19 21:23:58 +01:00
Ayke van Laethem 38a80b45d3 all: support Go 1.22
This adds initial support for Go 1.22. Not all new features are
supported yet.
2024-01-19 13:51:40 +01:00
Ayke van Laethem e9003e2deb runtime: add runtime.rand function
This function is needed for Go 1.22, and is used from various packages
like math/rand.

When there is no random number generator available, it falls back to a
static sequence of numbers. I think this is fine, because as far as I
can see it is only used for non-cryptographic needs.
2024-01-19 13:46:27 +01:00
Ayke van Laethem 204659bdcd reflect: add TypeFor[T]
This function was added in Go 1.22. See:
https://github.com/golang/go/commit/42d2dfb4305aecb3a6e5494db6b8f6e48a09b420
2024-01-19 13:46:27 +01:00
Ayke van Laethem 08ca1d13d0 loader: enforce Go language version in the type checker
This means for example that ranging over integers will only work when
setting the Go version to go1.22 or later in the go.mod file.
2024-01-19 13:46:27 +01:00
Ayke van Laethem 53db436a7d cgo: add file AST for fake C file locations
This is needed for the type checker, otherwise it doesn't know which Go
version it should use for type checking.
2024-01-18 20:19:15 +01:00
Ayke van Laethem 0ad15551c8 compiler: update golang.org/x/tools/go/ssa package
This update includes support for the new range loops over integers.
2024-01-18 19:51:52 +01:00
Ayke van Laethem afd65e224a bytealg: update to Go 1.22
A few non-generic functions like HashStrBytes have been kept for
backwards compatibility, so this package should continue to work with
older Go versions (as long as they support generics).
2024-01-17 13:39:57 +01:00
deadprogram 5f50c3b60b machine/samd51: add UART hardware flow control support
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-01-17 12:41:15 +01:00
deadprogram 8858d49989 targets: add ninafw tag to Arduino mkrwifi1010 and Adafruit Matrix Portal M4 for drivers netlink support
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-01-15 19:34:05 -05:00
deadprogram cf39d8b2c8 targets: add ninafw pins and settings to Adafruit PyBadge board with AirLift Featherwing
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-01-15 19:34:05 -05:00
deadprogram d92a31b440 targets: add ninafw pins and settings to Adafruit Metro M4 Airlift board
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-01-15 19:34:05 -05:00
deadprogram 9c77a38358 build: use llvm-17 base image correctly for faster docker dev builds
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-01-12 19:23:33 +01:00
Ayke van Laethem d0445d6f83 cgo: fix calling CGo callback inside generic function
The package of the generic function might not be set, so we have to call
Origin() for it.

Found while porting mcufont to TinyGo.
2024-01-12 14:54:42 +01:00
BCG a40b11f535 Adding additional build tag for boards with ninafw 2024-01-07 16:06:16 +01:00
deadprogram 8c90f4facf machine/pyportal: add needed values to board file for ninafw BLE support
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-01-06 22:46:47 +01:00
deadprogram c7c9a76af5 build: add step to build LLVM 17 base image
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-01-05 21:13:30 +01:00
Ayke van Laethem 6984af43a0 all: statically link to LLVM 17 instead of LLVM 16
We can now finally do it, now that Espressif has updated their fork.
2024-01-05 21:13:30 +01:00
deadprogram 81c56c3ab8 machine, targets: ninafw support for arduino-nano33 and nano-rp2040 boards
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-01-05 19:04:12 +01:00
deadprogram 3d9a1ca22a machine/samd21: add hardware flow control for UART
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-01-05 17:56:45 +01:00
deadprogram c2083014b3 targets: add ninafw tag to nano-rp2040 for ninafw BLE support
Signed-off-by: deadprogram <ron@hybridgroup.com>
2024-01-03 23:28:28 -05:00
Scott Feldman 603a81f194 expose UART4 on wioterminal board
The right-hand grove port on the wioterminal can be used as UART, using
D0/D1 pins.  The pins D0/D1 are tied to SERCOM4, so this patch exposes a
UART4 for sercom4 access.

  RX = A0/D0 = PB08/SERCOM4.0 (port 4 pad 0)
  TX = A1/D1 = PB09/SERCOM4.1 (port 4 pad 1)

Tested with Lora E5 UART.

  uart : = machine.UART4
  tx := machine.D0
  rx := machine.D1

Note: must also cross Tx/Rx wires in grove cable.  See
https://www.lucadentella.it/en/2022/01/29/wio-terminal-porta-grove-di-destra-e-moduli-uart/
2023-12-31 10:54:11 +01:00
Elias Naur cfc32794a7 os/user: add bare-bones implementation of the os/user package
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2023-12-30 10:56:23 +01:00
Elias Naur 1d9c53d00e nix: upgrade to NixOS 23.11
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2023-12-24 16:32:16 +01:00
Ayke van Laethem 8d2a07b927 main: add -serial=rtt support 2023-12-23 08:14:35 -05:00
deadprogram ffe6dfd21b machine/nano-rp2040: add UART1 and correct mappings for NINA via UART.
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-20 16:51:21 -05:00
deadprogram cf21380264 machine/serial, rp2040: add support for hardware flow control
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-20 16:48:12 -05:00
deadprogram 534b3b0c0b net: update to latest main branch with accept fix
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-19 08:16:40 +01:00
deadprogram ceeb233ff6 build: another try to handle python unlink/link due to homebrew
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-18 20:23:19 +01:00
deadprogram de3f0af829 build: fix for macos homebrew as discussed in https://github.com/Homebrew/brew/issues/15621
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-17 21:26:23 +01:00
Scott Feldman a511f18c64 stub out more types/funcs to compile against golang.org/x/net/internal/socket (#4037)
* stub out more types/funcs to compile against golang.org/x/net/internal/socket

These are changes need to compile github.com/domainr/dnsr/ with TinyGo.
See issue https://github.com/tinygo-org/net/issues/14.

These change are mostly to fix missing symbols in src/crypto/tls and
src/net.  Missing types and functions are cut-and-pasted from go1.21.4.
Functions are stubbed out returning errors.New("not implemented").

DNRS is compiled by running tinygo test:

   sfeldma@nuc:~/work/dnsr$ tinygo test -target=wasi

With this patch, and a corresponding patch for tinygo-org/net to fixup
src/net, you should get a clean compile.
2023-12-17 15:32:53 +01:00
deadprogram 731bd5cd1b net: update to latest main branch with TCPListener
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-09 12:11:04 +01:00
deadprogram 4acf59546e modules: update net submodule to latest commit with http Client Transport interface
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-09 09:48:29 +01:00
deadprogram 2ee4d9aaa1 builder/picolib: add needed file for compiling math functions with error support.
Thanks to @aykevl for actually finding and providing this fix, I really just
reported the problem and tested the fix.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-09 07:47:27 +01:00
deadprogram b58b7c59ae runtime: stub out Breakpoint() function
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-08 21:10:26 +01:00
deadprogram e14b6a7009 lib/cmsis-svd: change to new repo location for the SVD files
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-07 14:38:36 +01:00
deadprogram a1a2d1ab81 modules: switch to main branch of net submodule
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-06 13:11:44 +01:00
Scott Feldman 07591178cd move syscall constants for networking into net space to avoid windows build issue 2023-12-06 13:11:44 +01:00
Scott Feldman 43bdc888dd move IPPROTO_TLS to netdev to avoid src/syscall dependency 2023-12-06 13:11:44 +01:00
Scott Feldman 4229e670ce Add network device driver model, netdev
This PR adds a network device driver model called netdev. There will be a companion PR for TinyGo drivers to update the netdev drivers and network examples. This PR covers the core "net" package.

An RFC for the work is here: #tinygo-org/drivers#487. Some things have changed from the RFC, but nothing major.

The "net" package is a partial port of Go's "net" package, version 1.19.3. The src/net/README file has details on what is modified from Go's "net" package.

Most "net" features are working as they would in normal Go. TCP/UDP/TLS protocol support is there. As well as HTTP client and server support. Standard Go network packages such as golang.org/x/net/websockets and Paho MQTT client work as-is. Other packages are likely to work as-is.

Testing results are here (https://docs.google.com/spreadsheets/d/e/2PACX-1vT0cCjBvwXf9HJf6aJV2Sw198F2ief02gmbMV0sQocKT4y4RpfKv3dh6Jyew8lQW64FouZ8GwA2yjxI/pubhtml?gid=1013173032&single=true).
2023-12-06 13:11:44 +01:00
deadprogram 76a7ad2a3e modules: add tinygo net package as submodule
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-06 13:11:44 +01:00
deadprogram e4f551ac7f src/net: remove existing files to replace with submodule
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-06 13:11:44 +01:00
Yurii Soldak 338590cc75 machine/atmega: uart double speed mode
Less errors and higher throughput.
Example: default / slow mode is problematic for 115200 on 16Mhz CPU.
2023-12-05 16:29:51 +01:00
deadprogram 22d70604d8 sizediff: cleanup before checkout of branche to allow for new/removed files to be able to still run thru size tests
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-04 18:26:00 +01:00
deadprogram c6add1e769 machine/esp32c3: implement RNG
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-04 09:34:20 +01:00
deadprogram c6609a02fa machine/esp32c3: move i2c implementation into separate file to skip m5stamp-c3 since it does not appear to expose those pins
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-03 22:05:08 +01:00
deadprogram a449c4813a build: can only build boards with board files for pin mapping
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-03 22:05:08 +01:00
deadprogram 19fb1bfafc machine/esp32c3: corrected implementation for error handling and when to expect NACK
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-03 22:05:08 +01:00
deadprogram f91b6ad0df machine/esp32c3: handle defaults for I2C configuration
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-12-03 22:05:08 +01:00
Dmitriy 94459cefe5 machine/esp32c3: implement i2c for esp32-c3 2023-12-03 22:05:08 +01:00
Yurii Soldak 803ba4f54d tools/sizediff: cleanup and calculate ram 2023-12-03 20:08:48 +01:00
Yurii Soldak 2919fa8b14 machine/atmega: bufferSize = 32
to save memory on 2k ram targets
also updates sizediff tool to show ram differences
2023-12-03 12:55:22 +01:00
Yurii Soldak 6420e90124 machine/atmega328pb: refactor to enable extra uart 2023-12-02 13:26:59 +01:00
deadprogram 2d289addb7 builds: update all GH action workflows to use latest versions
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-11-29 08:58:27 +01:00
sago35 4df145dcb4 m5stamp-c3: change settings to explicitly use UART 2023-11-29 08:11:46 +01:00
deadprogram e065da20cb targets: add Adafruit qtpy-esp32c3 board support
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-11-28 23:57:30 +01:00
deadprogram d7c77b6761 machine/esp32c3: implement USB_SERIAL for USBCDC communication
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-11-28 23:05:07 +01:00
deadprogram f51029484a builds: free space before doing docker build job
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-11-28 20:56:08 +01:00
deadprogram 03cfcbc17c docker: makefile was renamed but did not show error util cache was busted
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-11-28 19:52:43 +01:00
deadprogram 649f49e000 docker: remove lists after update to reduce image size
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-11-28 19:52:43 +01:00
deadprogram 3bcd4dc3e0 lib/cmsis-svd: switch to new location and latest version of shared SVD repository
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-11-25 15:34:20 +01:00
deadprogram 772c71ec27 make/gen-device-esp: change order of generating ESP32 device wrappers to avoid community ESP32 being overwritten by the official one
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-11-25 15:34:20 +01:00
Rado M 9b896dc981 refactor: reuse OptLevel() to get the opt level 2023-11-24 16:19:18 +01:00
Scott Feldman d4189feca6 Bump default stack size for target pico to 8kb from 2kb 2023-11-12 19:22:50 +01:00
Damian Gryski 777048cfa9 compiler: fix crash on type assert on interfaces with no methods 2023-11-08 19:41:25 +01:00
sago35 2b215955ca machine/usb: add support for ISERIAL descriptor 2023-11-07 00:11:40 +01:00
Elliott Sales de Andrade ce25f00769 Bump wasi-libc to SDK 20
The version 17 SDK adds `getpagesize`, so use it instead of hardcoding a
number (even if their implementation is _also_ a hardcoded number.)
2023-11-04 23:32:42 +01:00
Elliott Sales de Andrade 1a59aecb63 Point wasi-libc submodule to new location. 2023-11-04 23:32:42 +01:00
Shane O'Donovan cca32e67a9 reflect: stub FuncOf() 2023-11-04 22:44:56 +01:00
Randy Reddig 174d492355 compileopts, targets, main: support Wasmtime v14 (#3972)
compileopts, targets, main: support Wasmtime v14
2023-11-02 19:49:52 +01:00
Christian Ege 5355473dce doc: fix a typo in the rtcinterrupt example (#3981)
docs: fix a typo in the rtcinterrupt example, also provide a link to the interrupt online doc
2023-11-02 18:13:22 +01:00
sago35 a531ed614a main, compileopts: move GetTargetSpecs() to compileopts package 2023-11-02 15:37:43 +01:00
sago35 24ae6fdf29 main: add -info option to tinygo monitor 2023-11-02 15:37:43 +01:00
deadprogram 938ce22307 machine/stm32: implement DeviceID() with unique ID per processor
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-10-27 17:44:53 +02:00
Kenneth Bell 9fb5a5b9a4 nrf,sam,rp2040: add machine.HardwareID function 2023-10-27 13:25:32 +02:00
deadprogram 9fd9d9c05a compileopts: add cflag '-isystem' for resource directory search since needed for Xtensa
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-10-25 08:57:39 +02:00
deadprogram fd50227a3d build: pin wasmtime version used for testing to v13.0.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-10-24 13:10:09 +02:00
Kenneth Bell a90295430c ci: work-around for broken links in github runners 2023-10-23 21:25:41 +02:00
deadprogram fa4ca63ff2 machine/spi: use interface to ensure uniformity for all machine implementations
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-10-17 13:41:32 +02:00
Flavio Castelli 7019c4e8fc Binaryen116 (#3958)
dependencies: update binaryen submodule to version 116

Signed-off-by: Flavio Castelli <fcastelli@suse.com>
Co-authored-by: DarkByteBen <ben@darkbytelabs.com>
2023-10-16 18:34:20 +02:00
deadprogram b79e0e8528 docs: add Nix badge for builds to README
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-10-15 21:02:25 +02:00
Ayke van Laethem 51bed3afae nix: fix md5sum on MacOS
The default on MacOS is `md5`, while Nix only has `md5sum` available.
Therefore, make it possible to override the variable via the environment
so that flake.nix can set the correct binary name.
2023-10-15 17:51:13 +02:00
Ayke van Laethem 4d4ccddad8 nix: support make wasi-libc on MacOS 2023-10-15 17:51:13 +02:00
Ayke van Laethem f55f5315cc builder: generalize build ID fallback to darwin
This is to support NixOS, who have added -no_uuid to the linker.
Upstream bug report: https://github.com/NixOS/nixpkgs/issues/178366
2023-10-15 17:51:13 +02:00
Ayke van Laethem 7468a00ef4 all: fix a small incompatibility with Nix
Hopefully this won't break anybody: while all tests still pass, there
could in theory be systems where not supplying those libraries leads to
linker errors.
2023-10-15 17:51:13 +02:00
ginglis13 8d77278c6b refactor: rm io/ioutil funcs
io/ioutil has been deprecated since Go 1.16
https://pkg.go.dev/io/ioutil

Signed-off-by: ginglis13 <ginglis05@gmail.com>
2023-10-15 12:12:07 +02:00
Ayke van Laethem dde9b5ad3a goenv: re-add support for Clang headers on darwin
When TinyGo is installed using `go install` or `go build`, it uses the
Clang resource directory from the host. This works for Linux, but
doesn't work anymore on macOS with a recent change I made.

This re-adds support for Darwin in that case (with much, much simpler
code than there used to be).
2023-10-15 10:51:06 +02:00
Ayke van Laethem 2d4307647e nix: improve docs and add support for wasi-libc
I forgot a few things in the flake file, but now everything should be
included.
2023-10-14 17:32:56 +02:00
Ron Evans 935a293106 machine/i2c: add interface check and implementation where missing for SetBaudRate() (#3406)
* machine/i2c: add interface check and placeholder implementation where missing for SetBaudRate()
2023-10-14 13:17:24 +02:00
Ayke van Laethem 72b715fa99 all: add Nix flake file
This adds a flake.nix file that makes it possible to quickly create a
development environment.

You can download Nix here, for use on your Linux or macOS system:
https://nixos.org/download.html

After you have installed Nix, you can enter the development environment
as follows:

    nix develop

This drops you into a bash shell, where you can install TinyGo simply
using the following command:

    go install

That's all! Assuming you've set up your $PATH correctly, you can now use
the tinygo command as usual:

    tinygo version

You can also do many other things from this environment. Building and
flashing should work as you're used to: it's not a VM or container so
there are no access restrictions.
2023-10-14 11:35:26 +02:00
Ayke van Laethem d801d0cd53 builder: refactor clang include headers
Set -resource-dir in a central place instead of passing the header path
around everywhere and adding it using the `-I` flag. I believe this is
closer to how Clang is intended to be used.

This change was inspired by my attempt to add a Nix flake file to
TinyGo.
2023-10-14 11:35:26 +02:00
Anuraag Agrawal c2f1965e03 Fix bitstring order in precise GC docs (#3947)
docs: Fix bitstring order in precise GC docs
2023-10-13 08:57:30 +02:00
sago35 75bba42b60 goenv: update to new v0.31.0 development version 2023-10-11 02:24:58 +02:00
Ayke van Laethem 18b50db0dc all: add initial LLVM 17 support
This allows us to test and use LLVM 17, now that it is available in
Homebrew.

Full support for LLVM 17 (including using it by default) will have to
wait until Espressif rebases their Xtensa fork of LLVM.
2023-10-06 09:05:07 +02:00
Ayke van Laethem 499fce9cee avr: don't compile large parts of picolibc (math, stdio)
These parts aren't critical and lead to crashes on small chips without
long jumps (like the attiny85) with LLVM 17. (Older LLVM versions would
emit long jumps regardless, even if the chip didn't support those).

For more information, see: https://github.com/llvm/llvm-project/issues/67042
2023-10-06 09:05:07 +02:00
deadprogram 88b29589d6 targets: increase default stack size to 64k for wasi/wasm targets
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-10-04 22:43:14 +02:00
Ayke van Laethem 8cbfbcae5a build: avoid sharing GlobalValues between build instances
This happens with `tinygo test` for example when testing multiple
packages at the same time. I found this because the compiler crashed in
`make tinygo-test-fast`:

    fatal error: concurrent map writes
    fatal error: concurrent map read and map write

    goroutine 15 [running]:
    github.com/tinygo-org/tinygo/builder.Build({0x40002d0be0, 0xa}, {0x0, 0x0}, {0x4000398048, 0x14}, 0x40003b0000)
            /home/ayke/src/tinygo/tinygo/builder/build.go:131 +0x388
    main.buildAndRun({0x40002d0be0, 0xa}, 0x40003b0000, {0x8bc178, 0x40003a4090}, {0x0, 0x0, 0x0}, {0x0, 0x0, ...}, ...)
            /home/ayke/src/tinygo/tinygo/main.go:856 +0x45c
    main.Test({0x40002d0be0, 0xa}, {0x8bc118, 0x40000b3a08}, {0x0?, 0x0?}, 0x40001e6000, {0x0, 0x0})
            /home/ayke/src/tinygo/tinygo/main.go:270 +0x758
    main.main.func3()
            /home/ayke/src/tinygo/tinygo/main.go:1718 +0xe4
    created by main.main in goroutine 1
            /home/ayke/src/tinygo/tinygo/main.go:1712 +0x34ec

My solution is essentially to copy the map over instead of modifying it
directly.

I've also moved the code up a little, because I think that's a more
sensible place (out of the way of the whole package compile logic).
2023-10-04 16:20:32 +02:00
Ayke van Laethem 5cd8ba2421 all: refactor goenv.Version to add the git sha1 if needed
Previously all (except one!) usage of goenv.Version manually added the
git sha1 hash, leading to duplicate code. I've moved this to do it all
in one place, to avoid this duplication.
2023-10-04 16:20:32 +02:00
Ayke van Laethem 2320b18953 ci: use matrix instead of duplicating the Linux cross job
This reduces a lot of copy-pasted code (that was in fact different in a
small way!)
2023-10-04 14:21:43 +02:00
Ayke van Laethem 3b1913ac57 all: use the new LLVM pass manager
The old LLVM pass manager is deprecated and should not be used anymore.
Moreover, the pass manager builder (which we used to set up a pass
pipeline) is actually removed from LLVM entirely in LLVM 17:
https://reviews.llvm.org/D145387
https://reviews.llvm.org/D145835

The new pass manager does change the binary size in many cases: both
growing and shrinking it. However, on average the binary size remains
more or less the same.

This is needed as a preparation for LLVM 17.
2023-10-04 13:05:58 +02:00
Ayke van Laethem 1da1abe314 all: remove LLVM 14 support
This is a big change: apart from removing LLVM 14 it also removes typed
pointer support (which was only fully supported in LLVM up to version
14). This removes about 200 lines of code, but more importantly removes
a ton of special cases for LLVM 14.
2023-10-01 18:32:15 +02:00
ayan george c9721197d5 bulid: Rename Makefile to GNUmakefile
Prior to this commit, the build instructions were encoded in Makefiles
that contained GNU extensions that are unique to GNU Make and
incompatible with older implementations.

Thie commit renames all Makefiles to GNUmakefile which clearly denotes
that the file contains GNU extensions.

GNU Make actually first looks for a GNUmakefile, then makefile, THEN
Makefile so in addition to simply being more correct and portable, it
saves a few unnecessary failed attempts to open the correct build
file.
2023-10-01 14:55:34 +02:00
ayan george 738747bd05 build: use $(MAKE) to represent make executable
Prior to this commit, our Makefiles assumed the name of the make program
was simply "make".

Since we use GNU make extensions, this isn't always the case --
operating systems like FreeBSD come with their own implementation named
make which can be incompatible with the extensions used in by tinygo.

To run a compatible make on some of these systems, we have explicitly
call GNU make by running gmake.

This commit changes references to the command "make" to "$(MAKE)" which
is a variable that contains the name of the executable invoked to
process the Makefile.

This allow the Makefiles to be uniformly processed by the same make
program.
2023-10-01 14:55:34 +02:00
ayan george 0bb4a8abeb docs: Update BUILDING.md
Indicate that GNU Make is the version of make required to build.
2023-09-29 17:45:59 +02:00
Ayke van Laethem 6ef8fcd537 cgo: add C._Bool type
This fixes https://github.com/tinygo-org/tinygo/issues/3926.

While working on this I've found another bug: if C.bool is referenced
from within Go, it isn't available anymore on the C side. This is an
existing bug that also applies to float and double, but may be less
likely to be triggered there.
This bug is something to be fixed at a later time (it has something to
do with preprocessor defines).
2023-09-24 07:41:26 -07:00
Ayke van Laethem a896f7f218 transform: fix bug in StringToBytes optimization pass
Previously, this pass would convert any read-only use of a
runtime.stringToBytes call to use the original string buffer instead.
This is incorrect: if there are any writes to the resulting buffer, none
of the slice buffer pointers can be converted to use the original
read-only string buffer.

This commit fixes that bug and adds a test to prove the new (correct)
behavior.
2023-09-23 07:48:43 -07:00
Ayke van Laethem 081d2e58c6 interp: print LLVM instruction in traceback
The old traceback would look like this:

    # internal/godebug
    /usr/local/go/src/internal/godebug/godebug.go:101:11: interp: test
    call <2> 0 <3> 0

    traceback:
    /usr/local/go/src/internal/godebug/godebug.go:101:11:
    call <2> 0 <3> 0
    /usr/local/go/src/internal/godebug:
    call <1> 0

With this patch, it looks like this:

    # io/fs
    /usr/local/go/src/io/fs/fs.go:144:45: interp: test
      %0 = load %runtime._interface, ptr @"internal/oserror.ErrInvalid", align 8, !dbg !316

    traceback:
    /usr/local/go/src/io/fs/fs.go:144:45:
      %0 = load %runtime._interface, ptr @"internal/oserror.ErrInvalid", align 8, !dbg !316
    /usr/local/go/src/io/fs/fs.go:137:28:
      %0 = call %runtime._interface @"io/fs.errInvalid"(ptr undef), !dbg !317

For developers (like me) who are familiar with LLVM, this is probably
easier to read. For users, I'm not sure: the instructions have quite a
lot of distracting fluff in them. But at least it contains the function
names that are called (which are not currently present in the old
traceback).
...that said, having the LLVM instructions in a bug report is probably
going to be easier for people who are familar with LLVM.
2023-09-22 15:28:52 +02:00
Ayke van Laethem ed2a98c7d0 ci: redo LLVM build on Windows
MinGW got updated, so it looks like we need to do a new LLVM build.
2023-09-21 21:33:34 +02:00
Ayke van Laethem 731532cd2b all: release 0.30.0
This is a small release just in time for GopherCon US.

Some of the big changes of this release are:

  - switch to LLVM 16
  - fixes for two separate hard-to-reproduce compiler crashes
  - added support for the Adafruit Gemma M0
2023-09-21 08:03:16 +02:00
Kenneth Bell adadbadec3 interp: improve unknown opcode handling 2023-09-21 01:18:05 +02:00
Kenneth Bell 58fafaeb5c build: #3893 do not return LLVM structs from Build 2023-09-21 01:18:05 +02:00
Dan Kegel 13a8eae0d4 build: build Go SSA serially [issue 3895]
From
https://github.com/tinygo-org/tinygo/pull/3915#issuecomment-1724405109

According to Ayke, it slows down the build but seems to reliably fix https://github.com/tinygo-org/tinygo/issues/3895
2023-09-20 23:22:18 +02:00
Ayke van Laethem 42da7654ec compiler: don't use types in the global context
This usually works by chance, but leads to crashes. So we should never
ever do this.

I'm pretty sure this is the crash behind this issue: https://github.com/tinygo-org/tinygo/issues/3894

It may also have caused this crash: https://github.com/tinygo-org/tinygo/issues/3874

I have a suspicion this is also behind the rather crash-prone CircleCI
jobs, that we haven't been able to find the source of. But we'll find
out soon enough once this fix is merged.

To avoid hitting this issue again in the future, I've created a PR to
remove these dangerous functions altogether from the go-llvm API:
https://github.com/tinygo-org/go-llvm/pull/54
2023-09-19 09:21:51 +02:00
Ayke van Laethem 8698a7e496 all: default to LLVM 16
So that `go install` works on MacOS with Homebrew (and on Linux with an
up-to-date distro).
2023-09-18 21:58:02 +02:00
Ayke van Laethem 1d7543e2bf all: switch to LLVM 16
This commit adds support for LLVM 16 and switches to it by default. That
means three LLVM versions are supported at the same time: LLVM 14, 15,
and 16.

This commit includes work by QuLogic:

  * Part of this work was based on a PR by QuLogic:
    https://github.com/tinygo-org/tinygo/pull/3649
    But I also had parts of this already implemented in an old branch I
    already made for LLVM 16.
  * QuLogic also provided a CGo fix here, which is also incorporated in
    this commit:
    https://github.com/tinygo-org/tinygo/pull/3869

The difference with the original PR by QuLogic is that this commit is
more complete:
  * It switches to LLVM 16 by default.
  * It updates some things to also make it work with a self-built LLVM.
  * It fixes the CGo bug in a slightly different way, and also fixes
    another one not included in the original PR.
  * It does not keep compiler tests passing on older LLVM versions. I
    have found this to be quite burdensome and therefore don't generally
    do this - the smoke tests should hopefully catch most regressions.
2023-09-18 21:58:02 +02:00
deadprogram ff32fbbb4f targets: increase default stack size to 32k for wasi/wasm targets
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-09-17 14:24:21 +02:00
sago35 3ad2530ee7 atsamd21, atsamd51: add support for USB INTERRUPT OUT 2023-09-16 09:30:05 +02:00
deadprogram c4de195f04 machine/rp2040: always use the USB device enum fix, even in chips that supposedly have the HW fix.
Additionally, correct the amount of time spent waiting after USB reset, based on advice from @sago35

Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-09-12 08:41:58 +02:00
Timothy Rule 75aca0f5ee Board support for Adafruit Gemma M0 (#3903)
machine, targets: Board support for Adafruit Gemma M0
2023-09-11 11:11:26 +02:00
Elliott Sales de Andrade bb9a9beed5 Update golang.org/x/tools to v0.12.0 2023-09-10 23:14:58 +02:00
Elliott Sales de Andrade 4042c1d618 Update tools to 0.9.0
This requires updating test data, due to the change noted in the
previous commit.
2023-09-10 23:14:58 +02:00
Elliott Sales de Andrade bf73516259 compiler: Handle nil array and struct constants
This is necessary for tools 0.9.0, which started lifting those since
https://github.com/golang/tools/commit/71ea8f168c160da91116b4ddbd577a8fc95aa334
2023-09-10 23:14:58 +02:00
deadprogram 43d282174f targets: add GoBadge target as alias for PyBadge :)
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-09-10 15:52:55 +02:00
Damian Gryski 0042bf62a5 compiler,reflect: add support for [...]T -> []T in reflect 2023-09-10 13:05:18 +02:00
Ayke van Laethem f11731ff35 interp: don't copy unknown values in runtime.sliceCopy
This was bug https://github.com/tinygo-org/tinygo/issues/3890.
See the diff for details. Essentially, it means that `copy` in the
interpreter was copying data that wasn't known yet, or copying data into
a slice that could be read externally after the interp pass.
2023-09-10 11:30:09 +02:00
sago35 e9d8a9bc0b goenv: update to new v0.30.0 development version 2023-09-08 17:41:31 +02:00
deadprogram 9d6eb1ff06 machine/usb/adc/midi: improve implementation to include several new messages
such as program changes and pitch bend. Also add error handling for invalid
parameter values such as MIDI channel. This however makes a somewhat breaking
change to the current implementation, in that we now use the typical MIDI user
system of counting MIDI channels from 1-16 instead of from 0-15 as the lower
level USB-MIDI API itself expects.

Also add constant values for continuous controller messages, rename SendCC
function, and add SysEx function.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-09-07 08:41:57 +02:00
Ayke van Laethem 4643401a1d runtime: refactor markGlobals to findGlobals
Instead of markGlobals calling markRoots unconditionally (which doesn't
make sense for -gc=none and -gc=leaking), provide markRoots as a
callback function.

This is in preparation for -gc=boehm, where the previous design is even
more awkward and a callback makes far more sense.

I've tested the size impact using `make smoketest XTENSA=0`. There is
none, except for two cases:

  * One with `-opt=0` so const-propagation for the callback didn't take
    place.
  * One other on AVR, I don't know why but as it's only 16 bytes in a
    very specific case I'm going to assume it's just a random change in
    compiler output that caused a size difference.
2023-09-05 00:42:01 +02:00
deadprogram dc449882ad docs: update CHANGELOG for release 0.29
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-08-25 15:57:40 +02:00
deadprogram a158d3194f all: update version for 0.29 release
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-08-25 15:57:40 +02:00
Pertti Erkkilä 806498f099 nRF52: set SPI TX/RX lengths even data is empty. Fixes #3868 (#3877)
machine/hrf: Set SPI TX/RX lengths even data is empty. Fixes #3868
2023-08-24 13:15:18 +02:00
deadprogram e3bc6da9e4 make: add task to check NodeJS version before running tests
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-08-19 20:04:10 +02:00
Pierre Constantineau 3e2471d934 adding new uf2 target for PCA10056 (#3765)
targets: adding new uf2 target for PCA10056
2023-08-19 11:06:17 +02:00
Ayke van Laethem a545f17d2e wasm: add support for GOOS=wasip1
This adds true GOOS=wasip1 support in addition to our existing
-target=wasi support. The old support for WASI isn't removed, but should
be treated as deprecated and will likely be removed eventually to reduce
the test burden.
2023-08-17 18:16:54 +02:00
Kenneth Bell f4375d0452 samd51,rp2040,nrf528xx,stm32: implement watchdog 2023-08-15 11:50:07 +02:00
deadprogram 756cdf44ed loader: merge go.env file which is now required starting in Go 1.21 to correctly get required packages
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-08-13 17:11:11 +02:00
Ayke van Laethem 9037bf8bf0 main: add target JSON file in tinygo info output
It looks like this on my system, for example:

    {
      "target": {
        "llvm-target": "aarch64-unknown-linux",
        "cpu": "generic",
        "features": "+neon",
        "goos": "linux",
        "goarch": "arm64",
        "build-tags": [
          "linux",
          "arm64"
        ],
        "gc": "precise",
        "scheduler": "tasks",
        "linker": "ld.lld",
        "rtlib": "compiler-rt",
        "libc": "musl",
        "default-stack-size": 65536,
        "ldflags": [
          "--gc-sections"
        ],
        "extra-files": [
          "src/runtime/asm_arm64.S",
          "src/internal/task/task_stack_arm64.S"
        ],
        "gdb": [
          "gdb"
        ],
        "flash-1200-bps-reset": "false"
      },
      "goroot": "/home/ayke/.cache/tinygo/goroot-23c311bcaa05f188affa3c42310aba343acc82562d5e5f04dea9d5b79ac35f7e",
      "goos": "linux",
      "goarch": "arm64",
      "goarm": "6",
      ...
    }

This can be very useful while working on the automatically generated
target object for example (in my case, GOOS=wasip1).
2023-08-13 15:27:21 +02:00
deadprogram bfe9ee378f rp2040: move flash related functions into separate file from C imports for correct LSP. Fixes #3852
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-08-13 14:08:57 +02:00
deadprogram 37a4fa205c modules: update to go-serial package v1.6.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-08-11 18:21:05 +02:00
deadprogram 59cc7d4c42 docker: use Go 1.21 for Docker dev container build
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-08-11 17:35:43 +02:00
deadprogram ab64e215dd build: switch GH actions builds to use Go 1.21 final release
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-08-10 12:45:52 +02:00
deadprogram 253dbe335a builder: update message for max supported Go version
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-08-09 19:27:15 +02:00
Unrud 0ef86e1534 Add support for HID Keyboard LEDs 2023-08-07 14:00:32 +02:00
Kenneth Bell 72270f9052 all: use https for renesas submodule #3856 2023-08-07 10:29:31 +02:00
sago35 67ec722a74 board: add AKIZUKI DENSHI AE-RP2040 2023-08-04 17:53:01 +02:00
Ayke van Laethem 62294feb56 compiler: improve panic message when a runtime call is unavailable
This should not happen under normal circumstances. It can still happen
when there is a mismatch between TinyGo version and the associated
runtime, or while developing the compiler package.
2023-08-04 11:59:11 +02:00
Ayke van Laethem f1e25a18d2 compiler: implement clear builtin for maps 2023-08-04 11:59:11 +02:00
Ayke van Laethem a2f886a67a compiler: implement clear builtin for slices 2023-08-04 11:59:11 +02:00
Ayke van Laethem f791c821ff compiler: add min and max builtin support 2023-08-04 11:59:11 +02:00
Ayke van Laethem a93f0ed12a all: Go 1.21 support 2023-08-04 11:59:11 +02:00
Ayke van Laethem c25dd0a972 testing: add Testing function
This is new in Go 1.21.
2023-08-04 11:59:11 +02:00
sago35 215dd3f0be machine/usb/hid: rename Handler() to TxHandler() 2023-08-04 09:43:53 +02:00
sago35 c51f5cea0b machine/usb/hid: add RxHandler interface 2023-08-04 09:43:53 +02:00
sago35 395ee2d338 machine/usb: refactor endpoint configuration 2023-08-02 09:16:29 +02:00
sago35 069e4f0d98 machine/usb: allow USB Endpoint settings to be changed externally 2023-08-02 09:16:29 +02:00
sago35 d1eb642d45 machine/usb: remove usbDescriptorConfig 2023-08-01 15:24:42 +02:00
Charlie Haley 5f2e72f371 compiler: add compiler-rt to wasm.json 2023-08-01 09:56:58 +02:00
Charlie Haley 5b581d83b3 compiler: add compiler-rt and wasm symbols to table 2023-07-31 14:52:26 +02:00
Ayke van Laethem d845f1e1b2 wasm: fix functions exported through //export
When a function is exported using //export, but also had a
//go:wasm-module pragma, the //export name was ignored. The
//go:wasm-module doesn't actually do anything besides breaking the
export (exported functions don't have a module name).

I've refactored and cleaned up the code, and in the process removed this
weird edge case.
2023-07-28 13:57:24 +02:00
Yurii Soldak 00d46bd25d avr: pin change interrupt 2023-07-27 18:15:22 +02:00
deadprogram 01d2ef327d sync: add implementation from upstream Go for OnceFunc, OnceValue, and OnceValues
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-07-20 08:09:03 +02:00
soypat 4da1f6bcbe rp2040:add NoPin support 2023-07-16 16:25:30 +02:00
Ayke van Laethem 14ddba8519 nrf: add I2C timeout
This commit adds I2C timeouts for nrf51 and nrf52 (but not yet for
others like nrf52840).

Tested on the PineTime, where I now got a timeout instead of hanging and
resetting due to a watchdog reset.
2023-07-16 10:27:33 +02:00
Patricio Whittingslow a7b205c26c machine.UART refactor (#3832)
* add gosched calls to UART

* add UART.flush() stubs for all supported architectures

* add comment un uart.go on flush functionality

* uart.writeByte as base of UART usage

* fix NXP having duplicate WriteByte

* fix writeByte not returning error on some platforms

* add flush method for fe310 device

* check for error in WriteByte call to writeByte
2023-07-15 11:24:53 -03:00
deadprogram c83f712c17 machine/rp2040: wait for 1000 us after flash reset to avoid issues with busy USB bus
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-07-07 22:13:26 +02:00
Ayke van Laethem fffad84a63 reflect: add SetZero
This was added in Go 1.20 and is required by encoding/json starting with
Go 1.21.
2023-07-07 18:12:57 +02:00
Ayke van Laethem e075e0591d main: use go env instead of doing all detection manually
This replaces our own manual detection of various variables (GOROOT,
GOPATH, Go version) with a simple call to `go env`.

If the `go` command is not found:

    error: could not find 'go' command: executable file not found in $PATH

If the Go version is too old:

    error: requires go version 1.18 through 1.20, got go1.17

If the Go tool itself outputs an error (using GOROOT=foobar here):

    go: cannot find GOROOT directory: foobar

This does break the case where `go` wasn't available in $PATH but we
would detect it anyway (via some hardcoded OS-dependent paths). I'm not
sure we want to fix that: I think it's better to tell users "make sure
`go version` prints the right value" than to do some automagic detection
of Go binary locations.
2023-07-07 16:55:59 +02:00
Achille Roussel 46d2696363 wasi: allow zero inodes when reading directories
Signed-off-by: Achille Roussel <achille.roussel@gmail.com>
2023-07-07 09:56:38 +02:00
Ayke van Laethem e98dfd6c46 reflect: implement Value.Grow
This was added in Go 1.20 and becomes necessary for encoding/json in Go
1.21.
2023-07-07 08:10:47 +02:00
sago35 9126b95737 machine/samd51: fix i2cTimeout was decreasing due to cache activation 2023-07-06 21:35:54 +02:00
deadprogram 3871b831af make: add make task to generate Renesas device wrappers
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-07-05 13:30:21 +02:00
deadprogram 7755f2385c tools/gen-device-svd: small changes needed for Renesas MCUs
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-07-05 13:30:21 +02:00
deadprogram 04601a29e8 modules: add submodule for Renesas SVD file mirror repo
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-07-05 13:30:21 +02:00
Ayke van Laethem 9aadea930f main: improve detection of filesystems
This is a rewrite of how filesystems are detected. Specifically, it
fixes an issue on Linux where the location of the FAT filesystem can
vary between distributions (for example, we supported most distros by
checking two different paths, but NixOS uses a different path): it now
uses the data in /proc/mounts instead which should be universal.
2023-07-03 13:37:38 +02:00
sago35 6efa94035e machine/macropad_rp2040: add machine.BUTTON 2023-07-03 11:44:44 +02:00
Mansour Behabadi db8d80755f rp2040: add missing suffix to CMD_READ_STATUS 2023-07-03 10:52:33 +02:00
Yurii Soldak dc91c96305 example: adjust time offset 2023-07-02 18:25:20 +02:00
Damian Gryski 08b3a4576d compiler: update .ll test output 2023-07-02 15:35:42 +02:00
Damian Gryski acba0748f1 compiler,reflect: NumMethods reports exported methods only
Fixes #3796
2023-07-02 15:35:42 +02:00
Damian Gryski ef72c5bb4e reflect: fix iterating over maps with interface{} keys
Fixes #3794
2023-07-02 11:47:08 +02:00
Rado M 93cc03b15a docker: update clang to version 15 2023-07-02 10:54:23 +02:00
Tyler Rockwood fdc4bbbfad reflect: Add FieldByNameFunc
This adds FieldByNameFunc, which some libraries like reflect2 need.

For my usecase I could also just stub FieldByNameFunc to panic, but
figured that it would work OK to just make it work. I'm not sure if
the overhead to FieldByName using a closure is acceptable.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
2023-07-02 09:14:36 +02:00
soypat dd4e9e86e7 reflect: remove unecessary heap allocations 2023-07-01 21:03:10 +02:00
sago35 ad32d26511 machine/usb/hid,joystick: fix hidreport (3) (#3802)
* machine/usb/hid,joystick: fix hidreport (3) and handling of logical, usage, and physical minimum/maximum values
2023-07-01 11:58:23 +02:00
Ayke van Laethem 4619896c19 nrf: wait for stop condition after reading from the I2C bus
Found while working on the PineTime. For some reason it still kind of
works in most cases, but I was hitting this issue when interacting with
two different I2C devices (the touch sensor and the BMA421).
2023-06-22 10:41:05 +02:00
Yurii Soldak cec237917f example: simplify pininterrupt 2023-06-18 10:59:23 +02:00
Ayke van Laethem 4d2a6d2bbe wasm: remove i64 workaround, use BigInt instead
Browsers previously didn't support the WebAssembly i64 type, so we had
to work around that limitation by converting the LLVM i64 type to
something else. Some people used a pair of i32 values, but we used a
pointer to a stack allocated i64.

Now however, all major browsers and Node.js do support WebAssembly
BigInt integration so that i64 values can be passed back and forth
between WebAssembly and JavaScript easily. Therefore, I think the time
has come to drop support for this workaround.

For more information: https://v8.dev/features/wasm-bigint (note that
TinyGo has used a slightly different way of passing i64 values between
JS and Wasm).

For information on browser support: https://webassembly.org/roadmap/
2023-06-17 18:08:09 +02:00
Ayke van Laethem 6d5f4c4be2 ci: update Node.js from version 14 to version 16
Node.js 14 is not maintained anymore, so we can drop support for it.
2023-06-17 18:08:09 +02:00
Ayke van Laethem 0cb5d336f4 reflect: use .key() instead of a type assert
This should be ever so slightly more efficient.
2023-06-17 15:58:03 +02:00
Stepan Rakitin 91ee4d0030 os: define ErrNoDeadline 2023-06-17 10:38:48 +02:00
Ayke van Laethem 785eb93b62 ci: rename release-double-zipped to something more useful
The Linux artifacts have clear names (linux-amd64-double-zipped etc),
but the MacOS and Windows ones didn't. This patch renames these artifact
names to be more readable, especially when downloading the artifacts.
2023-06-16 21:32:22 +02:00
sago35 e041a8ed88 goenv: update to new v0.29.0 development version 2023-06-16 11:36:41 +02:00
soypat d01d85930d rp2040: add spi busy waits on read and read/write transactions 2023-06-11 22:24:26 +02:00
Ayke van Laethem ac821d8295 goenv: fix version number to 0.28.1 (without -dev) 2023-06-11 18:56:38 +02:00
Ayke van Laethem 5c2753e54e all: release 0.28.0
These are some major or breaking changes:

 - Reflect support got improved a lot.
 - Interrupts became more strict: heap allocations an blocking
   operations, which have always been undefined behavior, now result in
   a panic.
 - `//go:wasmimport` was added
 - various new flags were added to `tinygo test`
 - the source location for panics is printed in the `-monitor` output
2023-06-10 17:11:37 +02:00
Damian Gryski 0212f0c008 compiler: limit level of pointer-to-pointer-to-... types 2023-06-09 17:30:02 +02:00
Damian Gryski f5f4751088 compiler,transform: fix for pointer-to-pointer type switches from @aykevl 2023-06-09 17:30:02 +02:00
Damian Gryski 62fb386d57 compiler,reflect: add tagged pointers for **T etc 2023-06-09 17:30:02 +02:00
ivoszz a59f92daf8 Add smoke test for target m5stick-c 2023-06-08 09:27:41 +02:00
ivoszz b7508818ee Support for the M5STACK M5StickC ESP32-PICO device 2023-06-08 09:27:41 +02:00
Damian Gryski 284e1acd87 compiler: update testdata 2023-06-08 07:55:37 +02:00
Damian Gryski 37849c4897 compiler,reflect: use two bits of the meta byte for comparable/isBinary
Fixes #3683
2023-06-08 07:55:37 +02:00
deadprogram 213e73ad84 build: only make comment on sizediff job when run from the main repo, take 2
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-06-07 12:54:15 +02:00
Ayke van Laethem 4a240827cb main: add -internal-nodwarf flag
This can be useful during development to avoid generating debug
information in IR.
2023-06-06 11:46:16 +02:00
Ayke van Laethem 92d9f856ab main: rename some flags to make them explicitly internal
These flags shouldn't be used by users, but they are occasionally
helpful for developers.
2023-06-06 11:46:16 +02:00
Damian Gryski ee5890f36f tools: use geomean for sizediff 2023-06-06 09:30:35 +02:00
soypat 744574193b machine/rp2040: fix i2c crash when getting abort while waiting for stop condition 2023-06-04 20:17:33 +02:00
soypat bbe755fb69 fix bug in rp2040 SetPeriod implementation 2023-06-03 13:16:32 +02:00
Pierre Constantineau 635d322703 Add bluemicro840 board 2023-06-01 21:04:36 +02:00
deadprogram ee90bdebff build: only make comment on sizediff job when run from the main repo
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-05-31 21:24:50 +02:00
soypat bcdb3fc681 fix go:noinlines in volatile package 2023-05-29 22:16:35 +02:00
Ayke van Laethem b7b23ace3f samd21: fix issue with WS2812 driver
The regular port access is around 4 cycles, instead of the usual 2
cycles for a store instruction on Cortex-M0+. The IOBUS however is
faster, I didn't measure exactly but I guess it's 2 cycles as expected.

This fixes a bug in the WS2812 driver that only happens on samd21 chips:
https://github.com/tinygo-org/drivers/issues/540
2023-05-29 20:45:31 +02:00
deadprogram f366cd53b7 build: explicitly pass the github token to GH action
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-05-23 11:06:02 +02:00
Ayke van Laethem da81784ee9 attiny1616: implement Pin.Get()
I didn't add this method in the initial PR.

Also, I found that a few of my assumptions were incorrect. I've changed
the code that configures the pin to make input (floating and pullup)
actually work. These chips really are quite different from all the older
AVRs.
2023-05-21 10:44:02 +02:00
Ayke van Laethem 481f60c5ea interp: add support for reading a pointer tag
This is necessary to get https://github.com/tinygo-org/tinygo/pull/3691
working.
2023-05-20 23:57:20 +02:00
Ayke van Laethem cf39db36fe interp: fix subtle bug in pointer xor
If a pointer value was xor'ed with a value other than 0, it would not
have been run at runtime but instead would fall through to the generic
integer operations. This would likely result in a "cannot convert
pointer to integer" panic.

This commit fixes this subtle case.
2023-05-20 23:57:20 +02:00
Ayke van Laethem 54c07b7de8 interp: move some often-repeated code into a function 2023-05-20 23:57:20 +02:00
Ayke van Laethem 2fb866ca86 avr: add attiny1616 support
This is just support for the chip, no boards are currently supported.
However, you can use this target on a custom board.

Notes:

  - This required a new runtime and machine implementation, because the
    hardware is actually very different (and much nicer than older
    AVRs!).
  - I had to update gen-device-avr to support this chip. This also
    affects the generated output of other AVRs, but I checked all chips
    we support and there shouldn't be any backwards incompatible
    changes.
  - I did not implement peripherals like UART, I2C, SPI, etc because I
    don't need them. That is left to do in the future.

You can flash these chips with only a UART and a 1kOhm resistor, which
is really nice (no special hardware needed). Here is the program I've
used for this purpose: https://pypi.org/project/pymcuprog/
2023-05-20 21:18:02 +02:00
Ayke van Laethem 4d11d552db avr: update gen-device-avr tool to support newer AVRs
This refactors gen-device-avr to output two different formats: one for
all the existing AVR chips (that don't really have the concept of a
peripheral, just a bunch of registers), and one for all the new chips
like the ATtiny1616 (tinyAVR 1-series and 2-series) that have
peripherals like the Cortex-M chips with type structs and instances.

I checked the generated code for all the AVR chips we have support for
(atmega1280, atmega1284p, atmega2560, atmega328p, atmega32u4, attiny85)
and while the generated Go code did change, it looks safe to me.
2023-05-20 21:18:02 +02:00
Ayke van Laethem b43bd9e62a avr: fix interrupt names for newer attiny chips
This only affects chips that aren't supported by TinyGo yet, so this
should be a safe change. Importantly, it fixes interrupts on the
ATtiny1616.
2023-05-20 21:18:02 +02:00
Rajat Jindal 572c22f66a add Settings to debug.BuildInfo
Signed-off-by: Rajat Jindal <rajatjindal83@gmail.com>
2023-05-20 14:49:31 +02:00
deadprogram 1b66da4dff build: add issues write permission to sizediff job
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-05-20 14:02:14 +02:00
Ayke van Laethem b08ff17f6b compiler: disallow most types in //go:wasmimport
This is for compatibility with upstream Go.
See https://github.com/golang/go/issues/59149 for more context.
2023-05-20 11:24:20 +02:00
Ayke van Laethem 41e787d504 compiler: add tests for error messages
The test is currently empty, but will be used in the next commit.
2023-05-20 11:24:20 +02:00
Ayke van Laethem 6dba16f28e compiler: only calculate functionInfo once
This is a small change that's not really important in itself, but it
avoids duplicate errors in a future commit that adds error messages to
//go:wasmimport.
2023-05-20 11:24:20 +02:00
deadprogram b336a1561f build: update GH actions-comment-pull-request to v2.3.1
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-05-17 17:54:47 +02:00
Ayke van Laethem 4c682680ca compileopts: don't filter build tags, use specific build tags instead
This basically reverts https://github.com/tinygo-org/tinygo/pull/3357
and replaces it with a different mechanism to get to the same goal.

I do not think filtering tags like this is a good idea: it's the wrong
part of the compiler to be concerned with such tags (that part sets
tags, but doesn't modify existing tags). Instead, I've written the
//go:build lines in such a way that it has the same effect: WASI
defaults to leveldb, everything else defaults to fnv, and it's possible
to override the default using build tags.
2023-05-17 11:21:15 +02:00
Ayke van Laethem af76c807e2 windows: re-enable parallelism
This reverts https://github.com/tinygo-org/tinygo/pull/3525, because
that change didn't seem to stop the CI failures we have been seeing.
Instead, I've added thread support in
https://github.com/tinygo-org/tinygo/pull/3130 which IIRC fixed most of
the CI crashes.

Re-enabling parallelism should improve the performance of TinyGo a bit
on Windows.
2023-05-16 21:47:24 +02:00
sago35 cdbd850f80 machine: add DefaultUART to xiao 2023-05-16 20:10:44 +02:00
Damian Gryski d256804af7 src/reflect: remove overflow checks from uvarint32 2023-05-16 19:02:08 +02:00
Damian Gryski e3c96803c3 runtime: fix structField.data comment 2023-05-16 19:02:08 +02:00
Damian Gryski f55bb8e030 builder: bump sizes_test 2023-05-16 19:02:08 +02:00
Damian Gryski 07fb3a0cad compiler,reflect: make field offsets varints
Fixes #3686
2023-05-16 19:02:08 +02:00
deadprogram 02913563df build: add write permission to sizediff GH actions job to always be able to add comments
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-05-16 18:41:45 +02:00
Ayke van Laethem 535e64adbc reflect: optimize Zero() a little bit
It could be expensive to call Size() three times, and it is unnecessary.
Instead, do it only once.

This results in a very small reduction of binary size if Zero() is used.
2023-05-14 18:23:23 +02:00
Ayke van Laethem af936f3261 ci: add comment with binary size difference
This makes reviewing PRs a lot easier because I don't have to run this
myself :)

This only uses the drivers repo so far, which is a good starting point
but doesn't include binary size changes for WebAssembly for example. A
future change could add some real-world programs to get a better idea of
the real-world impact.

To be clear: the intention is not to just look at the number at the
bottom. It is important to look at the actual size difference to see the
overall pattern (like, the difference may be due to a few outlier).
2023-05-14 15:38:57 +02:00
sago35 d1a45f2efc machine/usb/hid: fix hidreport (2) 2023-05-14 12:17:01 +02:00
deadprogram b56a263d0d machine/flash: remove FlashBuffer, modify flash example to use BlockDevice interface
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-05-14 10:41:03 +02:00
Ayke van Laethem 6435f62dcc builder: implement Nordic DFU file writer in Go
This avoids a dependency on nrfutil. I have verified that it creates
equivalent zip files to a wasp-os DFU zip file I downloaded here:
https://github.com/wasp-os/wasp-os/releases/
I have also tested that it produces valid DFU files that can be uploaded
using the dfu.py program here to my PineTime:
https://github.com/wasp-os/ota-dfu-python/tree/3d6fd30d33c2b20bc86ff6b9269fddf4a1d4c7c6

There are some minor differences in the generated file that should not
matter in practice (JSON whitespace, firmware file name, zip
compression).
2023-05-13 09:52:42 +02:00
Ayke van Laethem f4c8c37b7b nrf: add ADC oversampling support
This is a lot easier to support than on other chips, and results in
noticeably better output when set to a higher value.
2023-05-09 19:51:05 +02:00
Ayke van Laethem 868812717f nrf: add sample time to ADC
This is important for inputs with a high input resistance. In those
cases, the sample time needs to be longer.
2023-05-09 19:51:05 +02:00
Ayke van Laethem e82f595f37 nrf: add ability to set the reference voltage
The reference voltage can't be 3.3V, so we pick 3.0V as this was the
previous default.
2023-05-09 19:51:05 +02:00
Ayke van Laethem e5af121553 nrf: refactor ADC code a little bit
* Initialize the ADC in Configure() (instead of in Get()).
  * Do not set all channels to "not connected" - that's already the
    reset value.
  * Don't disable the ADC after use. It's not necessary to disable
    (current consumption appears to remain the same whether enabled or
    disabled).
2023-05-09 19:51:05 +02:00
Ayke van Laethem 20fdbc1f9d pinetime: update the target file
* Rename pinetime-devkit0 to pinetime because the production device is
    almost the same hardware (the only noticeable difference is a
    different accelerometer, which isn't part of the board file).
  * Remove the UART and set serial to none. The UART uses a lot of
    current by default, so it seems better to disable it.

This is a breaking change, but honestly I think I'm the only one who has
ever actually used TinyGo for the PineTime and I'm fine with this
change :)
2023-05-09 19:44:00 +02:00
sago35 14fed59827 machine/usb/hid: fix hidreport 2023-05-07 10:25:40 +02:00
deadprogram d331aca296 machine/rp2040: correct write block size for flash
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-05-07 00:49:10 +02:00
deadprogram 7e8a2e8934 machine/rp2040: correct param for number of bytes to be erased by flash
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-05-07 00:49:10 +02:00
deadprogram e7363966a5 machine/atsam*, nrf, rp2040, stm32: correct error flashBlockDevice pad() function
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-05-06 23:24:01 +02:00
Daz Wilkin 373ab34492 Add dummy package for runtime/metrics to that modules that depend upon it (e.g. [Prometheus Go client library](https://github.com/prometheus/client_golang/blob/main/prometheus/internal/go_runtime_metrics.go)) will compile.
Avoids:
```console
package runtime/metrics is not in GOROOT
```

Fixes #3705
2023-05-06 14:55:17 +02:00
Achille 602f35a5ca os: implement os.(*File).WriteAt (#3697)
os: implement os.(*File).WriteAt

Signed-off-by: Achille Roussel <achille.roussel@gmail.com>
2023-05-05 09:40:15 +02:00
deadprogram 1d5c5ca2ef machine/usb/descriptor: further refactor HID report creation
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-05-05 07:44:03 +02:00
deadprogram 90935703e6 machine/usb/descriptor: rename and export Append() to make it easier to create new descriptors in user code
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-05-05 07:44:03 +02:00
deadprogram d8ee520bdc machine/usb/descriptor: refactor HID report creation
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-05-05 07:44:03 +02:00
Ayke van Laethem e4da35486b tools: add sizediff tool
This tool can be very useful to compare binary sizes as output by
`-size=short`.

This is a tool I wrote a while ago. It's not perfect (we should probably
use a geomean) but it works well enough to get a good idea on the binary
size impact of a change.
2023-05-04 21:46:53 +02:00
Edoardo Vacchi 4e41e9084a cgo: allow LDFLAGS: --export=...
Signed-off-by: Edoardo Vacchi <evacchi@users.noreply.github.com>
2023-05-04 20:45:02 +02:00
Achille Roussel ee3af40cab os: implement os.(*File).ReadDir for -target=wasi
Signed-off-by: Achille Roussel <achille.roussel@gmail.com>
2023-05-03 21:24:11 +02:00
Achille Roussel 666312f63f implement Sync on stdioFileHandle
Signed-off-by: Achille Roussel <achille.roussel@gmail.com>
2023-05-03 19:37:53 +02:00
Achille Roussel ccfe92a58c os: add os.(*File).Sync
Signed-off-by: Achille Roussel <achille.roussel@gmail.com>
2023-05-03 19:37:53 +02:00
Achille Roussel 4fa6a132e2 syscall: add fsync using libc
Signed-off-by: Achille Roussel <achille.roussel@gmail.com>
2023-05-03 19:37:53 +02:00
deadprogram 1a67795fd3 examples/usb-midi: remove serial communication from MIDI example
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-04-29 10:06:52 +02:00
deadprogram c70daa2497 machine/usb: move MIDI under usb/adc (Audio Device Class) package
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-04-29 10:06:52 +02:00
sago35 d28b58e4dd machine/usb/hid/mouse: add support for mouse back and forward 2023-04-28 17:41:00 +02:00
deadprogram 25b03414dc machine/usb/hid/joystick: handle case where we cannot find the correct HID descriptor
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-04-28 15:15:54 +02:00
deadprogram 2ab7ee6a8a machine/usb: refactoring descriptors into subpackage for modularity
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-04-28 15:15:54 +02:00
Damian Gryski 6a2dd35fe6 builder: bump sizes test values 2023-04-27 11:15:41 +02:00
Damian Gryski 4c0fbbfc7f add struct size and field offsets to reflect data 2023-04-27 11:15:41 +02:00
deadprogram 36bd66a858 docs: update README for brevity and to add further info about webassembly
also, add links to guides about OS-specific development on website
      for macOS and Windows.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-04-27 09:08:37 +02:00
deadprogram 9d7dd3dd4b docs: update LICENSE year
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-04-27 09:08:37 +02:00
Ayke van Laethem 9bf5d6a4aa builder: add link to compatibility matrix
For context, see: https://github.com/tinygo-org/tinygo-site/pull/327

It only needs to be updated every half year, so it's not too bad, and it
could be very useful to some people.
2023-04-27 02:44:58 +02:00
Ayke van Laethem 839edec64c cortexm: fix stack size offset
The old code was broken and led to a HardFault in a rather convoluted
way:

 1. The CFA offset was incorrect, in fact it was not aligned (the stack
    is supposed to always be aligned to 4 bytes at least).
 2. This unaligned size was then used for stack size calculations.
 3. A stack that wasn't a multiple of 4 was allocated.
 4. The calleeSavedRegs struct (in `(internal/task.state).archInit`) was
    not correctly aligned.
 5. Writing to this struct resulted in a HardFault.
2023-04-27 00:11:53 +02:00
Ayke van Laethem 7e05c92420 cortexm: add "gdb" as a debugger
At least on Arch Linux ARM, there is no gdb-multiarch or something, just
"gdb" and it works for 32-bit ARM as well.
2023-04-26 23:07:52 +02:00
Ayke van Laethem 0b2aec1164 runtime: improve panic message when heap allocating in an interrupt
The old message may have been confusing. With the new message, it should
be more clear that we mean a _heap_ allocation.
2023-04-26 20:04:06 +02:00
Ayke van Laethem ae381e74a5 main: print source location when a panic happens in -monitor
The previous commit started printing the instruction address for runtime
panics. This commit starts using this address to print the source
location.

Here is an example where this feature is very useful. There is a heap
allocation in the Bluetooth package, but we don't know where exactly.
Printing the instruction address of the panic is already useful, but
what is even more useful is looking up this address in the DWARF debug
information that's part of the binary:

    $ tinygo flash -target=circuitplay-bluefruit -monitor ./examples/heartrate
    Connected to /dev/ttyACM0. Press Ctrl-C to exit.
    tick 00:00.810
    tick 00:01.587
    tick 00:02.387
    tick 00:03.244
    panic: runtime error at 0x00027c4d: alloc in interrupt
    [tinygo: panic at /home/ayke/src/tinygo/bluetooth/adapter_sd.go:74:4]

To be clear, this path isn't stored on the microcontroller. It's stored
as part of the build, and `-monitor` just looks up the path from the
panic message.

Possible enhancements:

  - Print such an address for regular panics as well. I'm not sure
    that's so useful, as it's usually a lot easier to look up panics
    just by their message.
  - Use runtimePanicAt (instead of runtimePanic) in other locations, if
    that proves to be beneficial.
  - Print the TinyGo-generated output in some other color, to
    distinguish it from the regular console output.
  - Print more details when panicking (registers, stack values), and
    print an actual backtrace.
2023-04-26 18:40:35 +02:00
Ayke van Laethem 3392827c3e runtime: print the address where a panic happened
This is not very useful in itself, but makes it possible to detect this
address in the output. See the next commit.

This adds around 50 bytes to each binary (except for AVR and wasm). This
is unfortunate, but I think this feature is quite useful still.
A future enhancement might be to create a build tag for extended panic
information that's not set by default.
2023-04-26 18:40:35 +02:00
Scott Feldman 59838338ba Add machine.CPUReset() (#3595)
machine: Add machine.CPUReset() for cortexm
2023-04-25 19:10:47 +02:00
Ron Evans 76303f9db4 Revert "all: better errors when multiple mcus share VID/PID"
This reverts commit af9f19615b.
2023-04-25 18:18:23 +02:00
Ron Evans 4bf8b618e5 Revert "all: honour port for -monitor flash flag"
This reverts commit 7aac1a1391.
2023-04-25 18:18:23 +02:00
deadprogram c89a684ad2 machine/gba: rename display and make pointer receivers
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-04-25 16:43:29 +02:00
Kenneth Bell 7aac1a1391 all: honour port for -monitor flash flag 2023-04-25 11:21:16 +02:00
Kenneth Bell af9f19615b all: better errors when multiple mcus share VID/PID 2023-04-25 11:21:16 +02:00
deadprogram 79b63dd041 device/gba: additional IO mapping for sound, DMA, SIO, and sprites
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-04-24 18:11:29 +02:00
Damian Gryski 06e34caa5f builder: print the status of the job that just completed 2023-04-22 10:01:02 +02:00
cui fliter 4e9f9e2773 fix some comments
Signed-off-by: cui fliter <imcusg@gmail.com>
2023-04-18 22:51:49 +02:00
Ayke van Laethem 64957c5254 samd51: fix ADC multisampling
Multisampling/averaging (using the Samples configuration property) was
returning incorrect values. When I investigated this, I found that the
samd51 gives erratic values when using multisampling together with fewer
than 16 bits resolution.

I fixed this by forcing 16 bit resolution when multisampling, and
adjusting the output to account for multisampling.

Found while reading the battery value on a pybadge, which gave
non-sensible values with Samples set to a value larger than 1.
2023-04-18 19:00:11 +02:00
Kenneth Bell 1bba5f5d7b targets: make msd-volume-name an array 2023-04-17 18:56:32 +02:00
deadprogram 48ef68dd86 examples: replace fmt with encoding/hex in usb-midi example
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-04-17 08:54:06 +02:00
Damian Gryski 8b9bee4cad main: don't print ok for a successful compile-only 2023-04-16 03:38:33 +02:00
Elliott Sales de Andrade b4c9b579b8 Switch interp tests to opaque pointers 2023-04-16 03:34:46 +02:00
Damian Gryski 2b1dc4fee5 testing: add -test.shuffle to order randomize test and benchmark order 2023-04-12 20:43:41 +02:00
Damian Gryski 0244bed033 testdata: add test for else/defer bug 2023-04-11 18:54:05 -07:00
Damian Gryski 60b23a7035 compiler: update test outputs 2023-04-11 18:54:05 -07:00
Damian Gryski 4326c8f10e compiler: ensure all defers have been seen before creating rundefers
Fixes #3643
2023-04-11 18:54:05 -07:00
Damian Gryski 1672610749 testing: move runtime.GC() call to runN to match upstream 2023-04-11 12:16:25 +02:00
Damian Gryski e00a2395d9 testing: fix benchmark logging output 2023-04-11 12:16:25 +02:00
sago35 42175496eb machine/atsamd51: remove extra BK0RDY clear 2023-04-10 09:16:52 +02:00
Ayke van Laethem 3b4e543f4e rp2040: use DMA for send-only SPI transfers
This improves slightly. It also is some groundwork for better DMA
support in TinyGo in the future.

I'm not entirely sure why it improves performance (in theory the old
code should already saturate the SPI bus) but it does, so 🤷
2023-04-04 12:22:52 +02:00
Kenneth Bell ad3e9e1a77 i2c: implement target mode for rp2040 and nrf 2023-04-04 09:36:42 +02:00
Kenneth Bell e0385e48d0 nrf: new peripheral type for nrf528xx chips 2023-04-04 09:36:42 +02:00
Kenneth Bell feadb9c85c nrf: move nrf52 family code to correct file name 2023-04-04 09:36:42 +02:00
Kenneth Bell 4bf7308d26 machine: make gosched available to machine package 2023-04-04 09:36:42 +02:00
Ayke van Laethem 19e4db45db samd51: use correct SPI frequency
The SPI frequency was rounded up, not rounded down. This meant that if
you wanted to configure 15MHz for example, it would pick the next
available frequency (24MHz). That's unsafe, the safe option is to round
down and the SPI support for most other chips also rounds down for this
reason.

In addition, I've improved SPI clock selection so that it will pick the
best clock of the two, widening the available frequencies. See the
comments in the patch for details.
2023-04-03 19:40:20 +02:00
sago35 71b44e79b3 machine/usb/hid/joystick: allow joystick settings override 2023-04-03 00:50:30 +02:00
deadprogram 9e97566b5f machine/usb/hid/joystick: move joystick under HID as it belongs and also remove duplicate code
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-04-03 00:50:30 +02:00
Ayke van Laethem 7d83e76833 rp2040: use 4MHz as default frequency for SPI
This matches other SPI implementations. I think the original value of
115200 was from a confusion with UART.
2023-04-02 01:04:37 +02:00
Damian Gryski 9e7882b1b7 reflect: uncomment a another test the fails and doc some that don't 2023-04-01 22:46:46 +02:00
Damian Gryski 0c4f9d1f19 reflect; uncomment SetZero (but comment out the parts that fail) 2023-04-01 22:46:46 +02:00
Damian Gryski a85cb22193 reflect: uncomment TestAppend and fix a bug it found 2023-04-01 22:46:46 +02:00
Damian Gryski 60bb832c89 reflect: handle Convert'ing between identical underlying types
Needed for go-jose/v3
2023-04-01 22:46:46 +02:00
Ayke van Laethem 6eda52a289 rp2040: remove SPI deadline
Removing it improves SPI performance by about 20% for me (updating the
display of a Gopher Badge).
2023-04-01 11:18:51 +02:00
Damian Gryski 8badf79af9 testing: remove unused variable left over from count prototyping 2023-03-31 19:17:02 -07:00
Damian Gryski 66d3c4edb8 main: fix typos in flag usage messages 2023-03-31 19:17:02 -07:00
Damian Gryski 63aaa43072 testing: add test.skip
Fixes #3056
2023-03-31 19:17:02 -07:00
Damian Gryski ee81c31884 testing: import new version of match.go 2023-03-31 19:17:02 -07:00
Damian Gryski 50d681359d main: set WASMTIME_BACKTRACE_DETAILS when running in wasmtime.
I find myself consistently running tests, seeing them panic, and then
immediately running them again with this environment variable set.  It's
easier to just have tinygo do this for me.
2023-03-31 13:06:23 -07:00
Damian Gryski d50c54fce0 Makefile: compress/lzw seems to work on wasi now. 2023-03-31 20:41:51 +02:00
Damian Gryski 4a81cac53b main: make sure all testing output goes to the same place 2023-03-31 09:07:13 +02:00
Damian Gryski 84a3273131 main: fix tests with default TestConfig.Count=0 doesn't skip all tests 2023-03-31 09:07:13 +02:00
Damian Gryski 9182664845 testing: make test output unbuffered when verbose
Fixes #3579
2023-03-31 09:07:13 +02:00
Damian Gryski a2f95d6b87 main: stuff test runner options into their own struct
Fixes #2406
2023-03-31 09:07:13 +02:00
Damian Gryski 698b1f19c6 testing: support -test.count
This makes running benchmarks repeatedly easier.
2023-03-31 09:07:13 +02:00
Damian Gryski e6ccdd9d1a reflect: another obscure RO bug 2023-03-31 01:08:04 +02:00
Damian Gryski b39a982067 reflect: uncomment another test and fix RO logic issues it uncovered 2023-03-31 01:08:04 +02:00
Ayke van Laethem e0bf376068 rp2040: unify all linker scripts using LDFLAGS
The only thing that's different between all these chips is the flash
size, which can easily be passed as a linker flag instead. This removes
a bunch of duplicate code in an uncommon language (linker script).

I've also fixed a few boards with incorrect flash sizes:

  * nano-rp2040 has 16MB instead of 2MB
  * macropad-rp2040 has 8MB instead of 2MB
  * gopher-badge has 8MB instead of 1MB
2023-03-30 23:49:02 +02:00
Damian Gryski b044d4ff3d reflect: add more RO checks 2023-03-30 21:10:54 +02:00
Damian Gryski 0cd93a3a9e reflect: add valueFlagRO 2023-03-30 21:10:54 +02:00
Damian Gryski 5faff2e13a reflect: add sipmlified strconv.Quote() implementation for struct tags 2023-03-30 21:10:54 +02:00
Damian Gryski 195de23d3b reflect: Fix Kind(-1).String() and enable test 2023-03-30 21:10:54 +02:00
Damian Gryski d4bdd836bc reflect: implement and test Value.Comparable 2023-03-30 21:10:54 +02:00
Damian Gryski a11f2436e3 reflect: TestAliasNames passes 2023-03-30 21:10:54 +02:00
Damian Gryski 017ab4c352 reflect: fix TestCanSetField 2023-03-30 21:10:54 +02:00
Damian Gryski 181d2ad2b4 reflect: add CanInt() and friends and uncomments tests that pass 2023-03-30 21:10:54 +02:00
Damian Gryski 53b95cad08 reflect: uncomment Type.String() tests that pass 2023-03-30 21:10:54 +02:00
Damian Gryski e7bd22edf2 reflect: print struct tags in Type.String() (with a caveat) 2023-03-30 21:10:54 +02:00
Damian Gryski 1a60a1f526 reflect: stub channel select routines/types 2023-03-30 21:10:54 +02:00
Damian Gryski 3fbd3c4d93 compiler,reflect: support channel directions 2023-03-30 21:10:54 +02:00
deadprogram 1213a45197 build: add GH workflow to build LLVM image when needed
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-30 12:40:02 +02:00
Damian Gryski 4e4e4eee04 runtime: use unsafe.Add() in hashmap code 2023-03-30 00:08:07 +02:00
Damian Gryski bf20c652e2 runtime: take max hash size into account when preallocating with size hint 2023-03-30 00:08:07 +02:00
Damian Gryski a3afd4e8ac runtime: factor duplicate hashmap snippts to functions 2023-03-30 00:08:07 +02:00
Damian Gryski cb9c6f0074 runtime: zero map key/value on deletion to so GC doesn't see them 2023-03-30 00:08:07 +02:00
Damian Gryski 5fee3428bc runtime: preallocate maps to size hint actually works 2023-03-30 00:08:07 +02:00
Ayke van Laethem 464ebc4fe1 compiler: implement most math/bits functions
These functions can be implemented more efficiently using LLVM
intrinsics. That makes them the Go equivalent of functions like
__builtin_clz which are also implemented using these LLVM intrinsics.

I believe the Go compiler does something very similar: IIRC it converts
calls to these functions into optimal instructions for the given
architecture.

I tested these by running `tinygo test math/bits` after uncommenting the
tests that would always fail (the *PanicZero and *PanicOverflow tests).
2023-03-29 20:55:09 +02:00
Ayke van Laethem 568c2a4363 rp2040: remove SPI DataBits property
As discussed on Slack, I believe this property does more harm than good:

  * I don't think it's used anywhere. None of the drivers use it.
  * It is not fully implemented. While values <= 8 might work fine,
    values larger than 8 result in extra zero bits (instead of anything
    sensible).
  * Worse, it doesn't return an error when it's out of range. This is
    not an optional property: if the SPI peripheral doesn't support a
    particular number of bits, it should return an error instead of
    silently limiting the number of bits. This will be confusing to
    users.

Therefore, I propose we drop it. Maybe there are good uses for it
(perhaps for displays that use big endian 16-bit values?), but without a
good use case like a driver in tinygo.org/x/drivers, I think it's more
trouble than it's worth.
2023-03-29 09:30:16 +02:00
Kenneth Bell c611c72526 build: test net on linux & mac only (random CI fails on windows) 2023-03-29 07:57:55 +02:00
deadprogram dfb8c996a1 machine/lorae5: correct mapping for I2C bus, add pin mapping to enable power
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-28 15:28:14 +02:00
Achille Roussel 85da9a0aac fix resource leak in os.(*File).Close
Signed-off-by: Achille Roussel <achille.roussel@gmail.com>
2023-03-28 13:12:21 +02:00
Ayke van Laethem 17bc0d6663 compiler: only support //go:wasmimport on declared functions
Don't support this pragma on defined functions. It is only meant for
importing, not for exporting.
2023-03-28 09:31:09 +02:00
Ayke van Laethem 31043628d8 reflect: use direct calls to runtime string functions
The runtime.stringFromBytesTyped and runtime.stringToBytesTyped
functions aren't really necessary, because they have the same LLVM IR
signature. Therefore, remove them and link directly to the functions
that the compiler uses internally.
2023-03-27 22:24:20 +02:00
Damian Gryski 2c0f61cad1 reflect: fix bug found by Convert() tests on wasi 2023-03-27 18:53:37 +02:00
Damian Gryski 97ece754f6 reflect: add missing Uintptr type and some numerical tests 2023-03-27 18:53:37 +02:00
Damian Gryski 39f76f43fc reflect: fix indirect issues with makeInt/makeUint/makeFloat 2023-03-27 18:53:37 +02:00
Damian Gryski f239e8e2d9 reflect: typo in uint test 2023-03-27 18:53:37 +02:00
Damian Gryski 6b73b5e486 reflect: document which Convert() cases are still unimplemented 2023-03-27 18:53:37 +02:00
Damian Gryski 855e12df51 reflect: Convert(): add Float() conversions 2023-03-27 18:53:37 +02:00
Damian Gryski 0b6bb12e9e reflect: add Convert() for string -> []byte and []byte -> string 2023-03-27 18:53:37 +02:00
Damian Gryski 72c7adf94a reflect: Convert() for integer and float types 2023-03-27 18:53:37 +02:00
waj334 13fb5aa7e7 Update task_stack_cortexm.c
Added build tag.
2023-03-27 12:35:39 +02:00
Justin A. Wilson a3fdbec13d Refactor SystemStack function for arm targets.
Removing usage of AsmFull in favor of writing inline assembly in C.
2023-03-27 12:35:39 +02:00
Damian Gryski 360f6904f5 reflect: add test for map[interface{}]T 2023-03-25 22:32:29 +01:00
Damian Gryski 7201b13085 reflect: fix key type logic for maps 2023-03-25 22:32:29 +01:00
Damian Gryski 9c0bf8bd2c reflect: Value.Set: fix direction of assignment check 2023-03-25 22:32:29 +01:00
Damian Gryski 63c7a41337 reflect: convert non-interface to interface in Set() 2023-03-25 22:32:29 +01:00
Damian Gryski c0f8f129c0 reflect: convert map elements to an interface, if needed 2023-03-25 22:32:29 +01:00
Damian Gryski adaa7ca27a reflect: SetMapIndex: use AssignableTo() instead of type equality 2023-03-25 22:32:29 +01:00
Damian Gryski a5ddc68845 reflect: unpack interfaces in MapKeys() if needed 2023-03-25 22:32:29 +01:00
Damian Gryski f7880e73d8 reflect: tweak v.typecode.Key().(*rawType) -> v.typecode.key() 2023-03-25 22:32:29 +01:00
Damian Gryski 3aa8c8e0d1 reflect: fix typo in unit test 2023-03-25 22:32:29 +01:00
Damian Gryski 6cb7f29d9b reflect: add tests for map interface lookup fixes 2023-03-25 22:32:29 +01:00
Damian Gryski 21527353f7 compiler: for interface maps, use the original named type if available 2023-03-25 22:32:29 +01:00
Damian Gryski bedd27b20e reflect: handle map-keys-as-interfaces for MapIter() 2023-03-25 22:32:29 +01:00
Damian Gryski 3612b7749e reflect: uncomment all(?) the tests that pass 2023-03-25 13:57:00 +01:00
Damian Gryski 45c916f5c0 reflect: rename tests in value_test to avoid conflicts upstream tests 2023-03-25 13:57:00 +01:00
Damian Gryski 688a5dbf8d reflct: reenable DeepEqual tests 2023-03-25 13:57:00 +01:00
Damian Gryski 35dcf135c0 reflect: comment out all tests but keep imports 2023-03-25 13:57:00 +01:00
Damian Gryski c482d65397 reflect: replace all_test with copy from upstream 2023-03-25 13:57:00 +01:00
shivay d73e12db63 feat: fix typos 2023-03-24 09:22:38 -07:00
Daniel Esteban 4b0e56cbec Added Gopher Badge support 2023-03-22 16:17:12 +01:00
Ayke van Laethem 62e1c3ebb7 wasm: implement the //go:wasmimport directive
It is implemented upstream and looks pretty stable.
2023-03-22 11:29:26 +01:00
deadprogram a4a1001dd3 examples: use hid-keyboard example to show how to to override default USB VID, PID, manufacturer name, and product name
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-22 08:35:42 +01:00
deadprogram e8f6df928c machine/usb: add ability to override default VID, PID, manufacturer name, and product name
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-22 08:35:42 +01:00
Ayke van Laethem f180339d6b compiler: add alloc attributes to runtime.alloc
This gives a small improvement now, and is needed to be able to use the
Heap2Stack transform that's available in the Attributor pass. This
Heap2Stack transform could replace our custom OptimizeAllocs pass.

Most of the changes are just IR that changed, the actual change is
relatively small.

To give an example of why this is useful, here is the code size before
this change:

    $ tinygo build -o test -size=short ./testdata/stdlib.go
       code    data     bss |   flash     ram
      95620    1812     968 |   97432    2780

    $ tinygo build -o test -size=short ./testdata/stdlib.go
       code    data     bss |   flash     ram
      95380    1812     968 |   97192    2780

That's a 0.25% reduction. Not a whole lot, but nice for such a small
patch.
2023-03-22 00:34:43 +01:00
Ayke van Laethem 5ed0cecf0d nrf: fix memory issue in ADC read
There was a very subtle bug in the ADC read code: it stores a pointer to
a variable in a register, waits for the hardware to complete the read,
and then reads the value again from the local variable. Unfortunately,
the compiler doesn't know there is some form of synchronization
happening in between.

This can be fixed in roughly two ways:
  * Introduce some sort of synchronization.
  * Do a volatile read from the variable.

I chose the second one as it is probably the least intrusive. We
certainly don't need atomic instructions (the chip is single threaded),
we just need to tell the compiler the value could have changed by making
the read volatile.
2023-03-22 00:34:43 +01:00
Ayke van Laethem 523c6c0e3b compiler: correctly generate code for local named types
It is possible to create function-local named types:

    func foo() any {
        type named int
        return named(0)
    }

This patch makes sure they don't alias with named types declared at the
package scope.

Bug originally found by Damian Gryski while working on reflect support.
2023-03-21 22:22:03 +01:00
Damian Gryski 17f5fb1071 reflect; SetLen() requires an addressable value 2023-03-21 20:53:37 +01:00
Damian Gryski 4d43df75d5 reflect: fix some vet issues 2023-03-21 20:53:37 +01:00
Damian Gryski 57b0c21492 reflect: tweak Type.String() for interfaces to make encoding/xml happy 2023-03-19 13:50:38 -07:00
Damian Gryski 8fb5877d9e reflect: fix isBinary() for float types 2023-03-19 13:49:55 -07:00
Damian Gryski 6fbe6fa2ae reflect: tweak Type.String() to match what encoding/json expects for empty structs 2023-03-19 20:37:57 +01:00
Damian Gryski 24b4dc31a4 reflect: stub MapOf() 2023-03-19 19:12:34 +01:00
Damian Gryski 4f8127d0bf builder: bump sizes tests 2023-03-19 17:45:43 +01:00
Damian Gryski e0329b25de transform: fix OptimizeReflectImplements pass for new named elem offset 2023-03-19 17:45:43 +01:00
Damian Gryski 229f479a7d reflect: make sure pointerTo() works for named types 2023-03-19 17:45:43 +01:00
Damian Gryski 876f08979f compiler,reflect: sort out pkg path vs pkg name for named types 2023-03-19 17:45:43 +01:00
Damian Gryski f2cc98caa5 compiler,reflect: adjust struct layout for type info 2023-03-19 17:45:43 +01:00
Damian Gryski 0d65b4dd26 compiler: only define the package path once
Adding https://github.com/tinygo-org/tinygo/pull/3534 by hand to avoid conflicts when I rebase.
2023-03-19 17:45:43 +01:00
Damian Gryski 6a685b2a8d reflect: add test for Type.NumMethod() 2023-03-19 17:45:43 +01:00
Damian Gryski 569817a514 refect: Type.String() should use a shortened package name 2023-03-19 17:45:43 +01:00
Damian Gryski 7a96f0f609 compiler,reflect: add reflect.Type.NumMethods() 2023-03-19 17:45:43 +01:00
deadprogram 821227a03b docker: correct path for GHCR dev container build
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-19 16:16:42 +01:00
Ayke van Laethem 5b42871baa compiler: support all kinds of recursive types
Previously we only supported recursive types in structs. But there can
be other kinds of recursive types, like slices:

    type RecursiveSlice []RecursiveSlice

This doesn't involve structs, so it led to infinite recursion in the
compiler. This fix avoids recursion at the proper level: at the place
where the named type is defined.
2023-03-18 17:53:47 +01:00
deadprogram c5598630c9 machine/stm32: correct Flash implementation
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-18 11:18:17 +01:00
Ayke van Laethem 6c40ee93fe transform: update wasm-abi to use opaque pointers 2023-03-16 13:46:03 -07:00
Ayke van Laethem 4acb1a5845 transform: update stringtobytes test to opaque pointers 2023-03-16 13:46:03 -07:00
Ayke van Laethem e0f3333cc3 transform: update stringequal test to opaque pointers 2023-03-16 13:46:03 -07:00
Ayke van Laethem af247e27ff transform: update stacksize test to opaque pointers 2023-03-16 13:46:03 -07:00
Ayke van Laethem ec3a4da4df transform: update panic test to opaque pointers 2023-03-16 13:46:03 -07:00
Ayke van Laethem 905269bf11 transform: update maps test to opaque pointers 2023-03-16 13:46:03 -07:00
Ayke van Laethem e4f29ae2f9 transform: update interrupt test to opaque pointers 2023-03-16 13:46:03 -07:00
Ayke van Laethem 7fb23824e2 transform: update interface test to opaque pointers 2023-03-16 13:46:03 -07:00
Ayke van Laethem f8a6e662d8 transform: update gc-stackslots test to opaque pointers 2023-03-16 13:46:03 -07:00
Ayke van Laethem 0ddd65658e transform: update allocs test to opaque pointers
Also, rename most of the SSA values while we're at it.
2023-03-16 13:46:03 -07:00
Ayke van Laethem db08b5aaa5 transform: update reflect-implements test to opaque pointers 2023-03-16 13:46:03 -07:00
deadprogram 383e7ae14a machine, runtime/interrupt: switch to use register definitions from device/gba
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-16 15:27:15 +01:00
deadprogram 4f7864b757 device/gba: add mostly complete hand-written register definitions
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-16 15:27:15 +01:00
Damian Gryski 833c91fceb builder: fix binary size rodata value 2023-03-15 21:53:57 +01:00
Damian Gryski 344e493ac8 compiler,reflect: fix pkgpath for struct fields 2023-03-15 21:53:57 +01:00
Damian Gryski 1626b50457 reflect: set PkgPath in StructField 2023-03-15 21:53:57 +01:00
Damian Gryski 93fb897feb compiler, reflect: properly handle embedded structs 2023-03-15 21:53:57 +01:00
Damian Gryski 15109a2924 reflect: disable visiblefields test for FieldByIndexErr 2023-03-15 21:53:57 +01:00
Damian Gryski d9c6f7c11f reflect: import visiblefields code and tests from upstream 2023-03-15 21:53:57 +01:00
Damian Gryski fa4f361ca7 reflect: add FieldByName(), and FieldByIndex() 2023-03-15 21:53:57 +01:00
Damian Gryski 9f02340a26 reflect: fix Type.Name to return empty string for non-named types
// Name returns the type's name within its package for a defined type.
    // For other (non-defined) types it returns the empty string.
2023-03-15 13:14:21 -07:00
Damian Gryski c6728643e6 reflect: loosen unaddressable array rules for Copy() 2023-03-15 10:49:08 -07:00
Damian Gryski e849901ad6 Update src/reflect/value.go
Co-authored-by: Ayke <aykevanlaethem@gmail.com>
2023-03-15 10:06:19 -07:00
Damian Gryski 91d6ca057c reflect: add SetBytes() 2023-03-15 10:06:19 -07:00
Damian Gryski 0da97e2427 reflect: fix IsNil() for interfaces 2023-03-15 16:23:52 +01:00
Damian Gryski ac36f232bc reflect: MapIter.Next() needs to allocate new keys/values every time 2023-03-15 15:17:16 +01:00
Damian Gryski 94a54bc105 reflect: add UnsafePointer() for Func types 2023-03-15 15:08:26 +01:00
Damian Gryski b044d27dff reflect: move StructField.Anonymous field to match upstream location 2023-03-15 00:13:08 +01:00
Damian Gryski 6768af91e7 reflect: TypeOf(nil) should be nil 2023-03-14 23:58:27 +01:00
Damian Gryski a366c014c7 reflect: call decomposeInterface() directly in TypeOf() 2023-03-14 09:53:45 -07:00
Damian Gryski 584a2718d0 reflect: add type check to Value.Field() 2023-03-14 09:53:00 -07:00
Damian Gryski 069c397975 reflect: fix off-by-one in Zero sizing
Without this, pointers wouldn't be set to nil.  Add some tests.
2023-03-14 09:42:51 -07:00
Damian Gryski e0aee1f23c reflect: Type.AssignableTo(): you can assign anything to interface{} 2023-03-14 17:07:23 +01:00
Damian Gryski ad9f790dfc reflect: set Index field in Field() 2023-03-14 17:04:24 +01:00
Damian Gryski f42d8b3056 debug: stub SetGCPercent() 2023-03-14 16:54:44 +01:00
Damian Gryski 04412cba0e reflect: add stub for StructOf() 2023-03-14 16:54:44 +01:00
Damian Gryski 3b2763896f reflect: add stubs for Method(), CanConvert(), ArrayOf() 2023-03-14 16:54:44 +01:00
Damian Gryski fb394c7685 reflect: add UnsafeAddr() 2023-03-14 16:53:57 +01:00
Damian Gryski a52cad3825 reflect: fix Addr() indirect value/flags and add tests. 2023-03-14 16:49:05 +01:00
Ayke van Laethem 0e94553b26 builder: add test to check for changes in binary size
This test only applies when using the built-in LLVM version. This way,
we have a stable LLVM version to test against. Distribution versions of
LLVM (especially Debian) tend to be patched in a way that affect the
results.
2023-03-13 22:57:02 +01:00
deadprogram e6580bfff4 machine/rp2040: correct Flash implementation
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-12 23:53:59 +01:00
deadprogram 5db83f11df machine/flash: refactor to keep use of pure offset relative to start
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-12 23:53:59 +01:00
deadprogram 60366adfa8 machine/rp2040: implement Flash interface
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-12 23:53:59 +01:00
Kenneth Bell faa449a9e1 arm: enable functions in RAM for go & cgo 2023-03-12 23:53:59 +01:00
sago35 08cf2b25c5 machine/rp2040: change uart to allow for a single pin 2023-03-12 13:41:29 +01:00
sago35 d6103222f7 wioterminal: fix pin definition of BCM13 2023-03-12 10:52:15 +01:00
Damian Gryski 69e5c5088d reflect: add support for remaining map types 2023-03-10 16:28:22 -08:00
Damian Gryski a6084767b3 syscall: remove misleading comment about Stat_t fields 2023-03-10 15:01:48 -08:00
Damian Gryski cf4a6d3253 syscall: add Timespec.Unix() for wasi.
This allows archive/tar to build (but not yet pass).
2023-03-10 15:01:48 -08:00
Damian Gryski 4716298044 os,syscall: Stat_t timespec fields are Atimespec on darwin
This allows archive/tar to build and pass.
2023-03-10 15:01:48 -08:00
Justin A. Wilson 7706c41bf6 Added missing TCPAddr and UDPAddr implementations to the net package 2023-03-10 10:11:32 -08:00
deadprogram 0bc19735f3 machine/samd51: disable/restore Flash cache on write/erase
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-09 06:42:41 +01:00
deadprogram 51c1579c3d machine/samd51: implement Flash interface
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-09 06:42:41 +01:00
Damian Gryski 6a45b73fcb compiler, reflect: replace package and name length with null-byte termination 2023-03-08 09:38:49 -08:00
Damian Gryski 2de64d3f4e compiler, reflect: add Type.PkgPath 2023-03-08 09:38:49 -08:00
Damian Gryski c192c7376e targets: bump cortex-m-qemu default stack size 2023-03-08 09:38:49 -08:00
Damian Gryski 2a821d2a66 reflect: improve Value.String() 2023-03-08 09:38:49 -08:00
Damian Gryski 90af41d089 reflect: add Type.String() 2023-03-08 09:38:49 -08:00
Damian Gryski 7654d86d2c compiler, reflect: add support for named types 2023-03-08 09:38:49 -08:00
sago35 45f119de34 machine/atsamd51: remove extra BK0RDY clear 2023-03-08 09:40:01 +01:00
Ayke van Laethem 71be24e4f9 transform: add debug information to internal/task.stackSize
This has two benefits:
 1. It attributes these bytes to the internal/task package (in
    -size=full), instead of (unknown).
 2. It makes it possible to print the stack sizes variable in GDB.

This is what it might look like in GDB:

    (gdb) p 'internal/task.stackSizes'
    $13 = {344, 120, 80, 2048, 360, 112, 80, 120, 2048, 2048}
2023-03-08 07:09:46 +01:00
Ayke van Laethem 3701e6eac1 compiler: account for alignment with -size=full 2023-03-08 07:09:46 +01:00
Ayke van Laethem 0463d34887 compiler: emit correct alignment in debug info for global variables
Previously we were using a really weird calculation to determine the
alignment in bits - written by me (no idea what I was thinking at the
time, it's obviously incorrect). Just replace it with the much more
obviously correct multiplication by 8 to get bits from bytes.

Found while working on properly dealing with alignment in `-size=full`.
2023-03-08 07:09:46 +01:00
Ayke van Laethem 0b47b99448 builder: improve reading of DWARF variables
The compiler now uses DW_OP_plus_uconst in the address attribute of
DWARF variables. To be able to understand these addresses, we need to be
able to parse this opcode.

This commit should also improve the reliability of address parsing a
bit.
2023-03-08 07:09:46 +01:00
Ayke van Laethem ea97c60959 builder: sizes: list interrupt vector as a pseudo-package for -size=full
This is another bit of memory that is now correctly accounted for in
`-size=full`.
2023-03-08 07:09:46 +01:00
Ayke van Laethem de281191e0 builder: detect compiler-rt size usage
Previously the code size of the compiler-rt library might be displayed
like this:

```
   1050       0       0       0 |    1050       0 | /home/ayke/src/tinygo/tinygo/llvm-project/compiler-rt/lib/builtins
    146       0       0       0 |     146       0 | /home/ayke/src/tinygo/tinygo/llvm-project/compiler-rt/lib/builtins/arm
```

With this change, it is displayed nicely like this:

```
   1196       0       0       0 |    1196       0 | C compiler-rt
```
2023-03-08 07:09:46 +01:00
Ron Evans fc28f513c7 machine/samd21: implement Flash interface (#3496)
machine/samd21: implement Flash interface
2023-03-08 06:06:49 +01:00
Ayke van Laethem 34ba0c1be1 ci: build LLVM with thread support on Windows
This should fix a number of concurrency/threading issues.

I had to force-disable concurrency in the linker using a hack. I'm not
entirely sure what the cause is, possibly the MinGW version (version 12
appears to work for me, while version 11 as used on the GitHub runner
image seems to be broken).
There are a few ways to fix this in a better way:
  * Fix the underlying cause (possibly by upgrading to MinGW-w64 12).
  * Add the `--threads` flag to the LLD MinGW linker, so we can use a
    regular parameter instead of this hack.
2023-03-07 22:38:14 +01:00
sago35 7ca45d61fc machine/rp2040: correct issue with spi pin validation 2023-03-07 21:11:57 +09:00
deadprogram 871cd66b98 build/linux: switch to ubuntu-20.04 for arm builds since ubuntu-18.04 is deprecated for GH actions runner
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-03-07 07:25:08 +01:00
Ayke van Laethem 192a55970f windows: disable parallelism on Windows
This is an attempt to figure out why the Windows CI keeps crashing. It
should be removed before the next release, by which point we should know
whether this has helped or not.
2023-03-06 18:48:55 +01:00
Ayke van Laethem 8babc47638 compiler: fix a race condition
There was a mostly benign race condition in the compiler. The issue was
that there is a check for type aliases (which can alias types in another
function), but this check was _after_ accessing a property of the
function that might not have been completed.

I don't think this can have any serious effects, as the function is
skipped anyway, but such bugs should certainly be fixed.
2023-03-06 09:30:11 +01:00
Ayke van Laethem 1cb702ac4c compiler: try harder to find source locations for constants
If there is no source location, at least use the file (but not line) for
debug information.

This attributes almost 1kB of string data for ./testdata/stdlib.go when
compiling for WASI.
2023-03-05 17:13:16 -08:00
Ayke van Laethem c6ac1cc969 compiler: add debug location to string values
This is helpful for WebAssembly: it makes it possible to attribute many
more data to locations in the source code, which makes `-size=full` more
useful.
2023-03-05 17:13:16 -08:00
Ayke van Laethem 0ce539ad42 compiler; add position information to createConstant
Non-functional change. The position information will be used later to
emit debug info locations to string constants.
2023-03-05 17:13:16 -08:00
Christian Stewart 930255ff46 os: add IsTimeout function
Fixes build error: undefined: os.IsTimeout

Signed-off-by: Christian Stewart <christian@paral.in>
2023-03-05 22:24:36 +01:00
Damian Gryski 57ecf1acdc testdata: add brandondube/pctl to corpus 2023-03-05 10:08:36 -08:00
Justin A. Wilson 313c9e31dd Refactor EnableInterrupts and DisableInterrupts
Removes usage of AsmFull which required an optimization pass to remove the map parameter passed into it. This caused issues when compiling with -opt=0 where memory for the map was being allocated as an unintended side-effect of using AsmFull with no optimizations enabled.
2023-03-05 17:34:48 +01:00
Ayke van Laethem d87e3ce330 compiler: add debug information to []embed.file slice global 2023-03-05 07:50:42 -08:00
Ayke van Laethem 11a6c84ea5 compiler: add debug information to //go:embed slice data 2023-03-05 07:50:42 -08:00
Ayke van Laethem 1d86b3f425 compiler: add debug info to []embed.files backing array 2023-03-05 07:50:42 -08:00
Damian Gryski f9b6f8339b reflect: ensure all ValueError panics have Kind fields 2023-03-03 10:18:32 -08:00
Damian Gryski 0ff243e5e2 reflect: add OverflowFloat(), OverflowInt(), OverflowUint() 2023-03-03 10:18:32 -08:00
Damian Gryski 79930a209c reflect: add Addr() 2023-03-03 10:18:32 -08:00
Damian Gryski bbc79ee40a reflect: add Zero() 2023-03-03 10:18:32 -08:00
Damian Gryski 960a0b79bf reflect: add SetLen() 2023-03-03 10:18:32 -08:00
Damian Gryski e4ef6f85ac reflect: allow nil rawType to call Kind() 2023-03-03 10:18:32 -08:00
Damian Gryski 3a3de8a778 reflect: add pointerTo() 2023-03-03 10:18:32 -08:00
Ayke van Laethem ca823f9a0d compiler: remove unsafe.Pointer(uintptr(v) + idx) optimization
I have checked this conversion is not needed anymore after the previous
commit, by running various smoke tests of which none triggered this
optimization. The only case where the optimization would have kicked in
is in syscall/syscall_windows.go:76 of the Go standard library.
Therefore, I prefer to remove it to reduce code complexity.
2023-03-03 16:55:13 +01:00
Ayke van Laethem 4ec1e58aa6 all: use unsafe.Add instead of unsafe.Pointer(uintptr(...) + ...)
We have an optimization for this specific pattern, but it's really just
a hack. With the addition of unsafe.Add in Go 1.17 we can directly
specify the intent instead and eventually remove this special case.

The code is also easier to read.
2023-03-03 16:55:13 +01:00
Damian Gryski d98c0afbab reflect: add Bytes() 2023-03-03 05:21:02 -08:00
Damian Gryski 12e3d1d81d reflect: add Copy() 2023-03-03 05:21:02 -08:00
Damian Gryski a7e3cf0826 reflect: add Slice3() 2023-03-03 05:21:02 -08:00
Damian Gryski 43a4b256bd reflect: add Slice() 2023-03-03 05:21:02 -08:00
Damian Gryski 5cc5f11b58 reflect: add MakeSlice() 2023-03-03 05:21:02 -08:00
Damian Gryski 836689fdd2 reflect: add Append() 2023-03-03 05:21:02 -08:00
Damian Gryski 9b86080c80 runtime: add sliceGrow function for reflect 2023-03-03 05:21:02 -08:00
Ayke van Laethem 517098c468 transform: fix non-determinism in the interface lowering pass
This non-determinism was introduced in
https://github.com/tinygo-org/tinygo/pull/2640. Non-determinism in the
compiler is a bug because it makes it harder to find whether a compiler
change actually affected the binary.

Fixes https://github.com/tinygo-org/tinygo/issues/3504
2023-03-02 18:47:09 +01:00
Damian Gryski 1cce1ea423 reflect: uncomment some DeepEqual tests that now pass 2023-02-28 13:10:40 -08:00
Damian Gryski a2bb1d3805 reflect: add MapKeys() 2023-02-28 13:10:40 -08:00
Damian Gryski c4dadbaaab reflect: add MakeMap() 2023-02-28 13:10:40 -08:00
Damian Gryski 828c3169ab reflect: add SetMapIndex() 2023-02-28 13:10:40 -08:00
Damian Gryski f6ee470eda reflect: add MapRange/MapIter 2023-02-28 13:10:40 -08:00
Damian Gryski d0f4702f8b reflect: add MapIndex() 2023-02-28 13:10:40 -08:00
Damian Gryski c0a50e9b47 runtime: add unsafe.pointer reflect wrappers for hashmap calls 2023-02-28 13:10:40 -08:00
Damian Gryski 9541525402 reflect: add Type.Elem() and Type.Key() for Maps 2023-02-28 13:10:40 -08:00
Damian Gryski 60a93e8e2d compiler, reflect: add map key and element type info 2023-02-28 13:10:40 -08:00
Federico G. Schwindt cdf785629a Fail earlier if Go is not available 2023-02-28 08:25:33 +01:00
Ayke van Laethem ea183e9197 compiler: add llvm.ident metadata
This metadata is emitted by Clang and I found it is important for source
level debugging on MacOS. This patch does not get source level debugging
to work yet (for that, it seems like packages need to be built
separately), but it is a step in the right direction.
2023-02-27 23:11:22 +01:00
deadprogram 74160c0e32 runtime/atsamd51: enable CMCC cache for greatly improved performance on SAMD51
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-02-27 20:40:41 +01:00
Ron Evans 6e1b8a54aa machine/stm32, nrf: flash API (#3472)
machine/stm32, nrf: implement machine.Flash

Implements the machine.Flash interface using the same definition as the tinyfs BlockDevice.

This implementation covers the stm32f4, stm32l4, stm32wlx, nrf51, nrf52, and nrf528xx processors.
2023-02-27 13:55:38 +01:00
Ayke van Laethem 8bf94b9231 internal/task: disallow blocking inside an interrupt
Blocking inside an interrupt is always unsafe and will lead to all kinds
of bad behavior (even if it might appear to work sometimes). So disallow
it, just like allocating heap memory inside an interrupt is not allowed.

I suspect this will usually be caused by channel sends, like this:

    ch <- someValue

The easy workaround is to make it a non-blocking send instead:

    select {
    case ch <- someValue:
    default:
    }

This does mean the application might become a bit more complex to be
able to deal with this case, but the alternative (undefined behavior) is
IMHO much worse.
2023-02-26 22:42:24 +01:00
Ayke van Laethem 488174767b builder: remove non-ThinLTO build mode
All targets now support ThinLTO so let's remove the old unused code.
2023-02-26 19:22:10 +01:00
Ayke van Laethem 201592d93b ci: add AVR timers test
Add the timers test because they now work correctly on AVR, probably as
a result of the reflect refactor: https://github.com/tinygo-org/tinygo/pull/2640

I've also updated a few of the other tests to indicate the new status
and why they don't work. It's no longer because of compiler errors, but
because of linker or runtime errors (which is at least some progress).
For example, I found that testdata/reflect.go works if you disable
`testAppendSlice` and increase the stack size.
2023-02-26 17:14:04 +01:00
Damian Gryski 476621736c compiler: zero struct padding during map operations
Fixes #3358
2023-02-25 22:40:08 +01:00
Damian Gryski 7b44fcd865 runtime: properly turn pointer into empty interface when hashing 2023-02-25 06:42:30 -08:00
Bjoern Poetzschke cfe971d723 Rearrange switch case for get pin cfg 2023-02-24 08:53:51 +01:00
John Clark bad7bfc4d5 Pins D4 & D5 are I2C1. Use pins D2 & D3 for I2C0.
Signed-off-by: John Clark <inindev@gmail.com>
2023-02-24 02:20:26 +01:00
deadprogram ad1da7d26f machine/rp2040: correct issue with spi pin validation
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-02-24 01:05:58 +01:00
deadprogram 6df303ff19 machine/rp2040: correct issue with i2c pin validation
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-02-24 01:05:58 +01:00
Patricio Whittingslow 96b70fd619 rp2040: provide better errors for invalid pins on i2c and spi (#3443)
machine/rp2040: provide better errors for invalid pins on i2c and spi
2023-02-23 13:26:14 +01:00
Yurii Soldak 4d0dfbd6fd rp2040: rtc delayed interrupt 2023-02-23 09:23:37 +01:00
deadprogram 1065f06e57 machine/lorae5: add needed definition for UART2
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-02-20 14:15:31 +01:00
Ayke van Laethem ec27d9fb48 ci: don't pass -v to go test
It can be difficult to find what went wrong in a test. Omitting -v
should make it easier to see the failing tests and the output for them
(note that output is still printed for tests that fail).
2023-02-20 00:23:52 +01:00
Ayke van Laethem cce9c6d5a1 arm64: fix register save/restore to include vector registers
Some vector registers must be preserved across calls, but this wasn't
happening on Linux and MacOS. When I added support for windows/arm64, I
saw that it required these vector registers to be preserved and assumed
this was Windows deviating from the standard calling convention. But
actually, Windows was just implementing the standard calling convention
and the bug was on Linux and MacOS.

This commit fixes the bug on Linux and MacOS and at the same time merges
the Go and assembly files as they no longer need to be separate.
2023-02-19 20:48:32 +01:00
Ayke van Laethem f41b6a3b96 runtime: check for heap allocations inside interrupts
This is unsafe and should never be done.
2023-02-19 11:33:24 +01:00
deadprogram e066e67baf machine/rp2040: change calling order for device enumeration fix to do first
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-02-19 08:32:39 +01:00
Ayke van Laethem cacb452aa6 main: support qemu-user debugging
Running binaries in QEMU (when debugging on Linux for example) did not
work correctly as qemu-user expects the `-g` flag to be first on the
command line before the program name. Putting it after will make it a
command line parameter for the emulated program, which is not what we
want.

I don't think this ever worked correctly.
2023-02-19 01:35:10 +01:00
Andy Shinn 9296332151 fix bad qt py pin assignment 2023-02-19 00:39:41 +01:00
deadprogram 1125d42149 build/docker: use build context from pre-saved LLVM container to avoid rebuilding
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-02-18 19:41:11 +01:00
deadprogram 7982d26db0 docker: ignore changes to CI itself to avoid breaking cache on images
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-02-18 19:41:11 +01:00
deadprogram f6758d22d8 build/linux: install wasmtime directly from github release
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-02-18 19:41:11 +01:00
deadprogram 87cfe6a538 build/docker: trigger all builds in tinygo ecosystem repos using GH actions
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-02-18 19:41:11 +01:00
Ayke van Laethem c02cc339c5 runtime: implement KeepAlive using inline assembly 2023-02-18 10:50:26 +01:00
Anton D. Kachalov 361ecf9ea4 Better handling of sub-clusters in SVD (#3335)
gen: Better handling of sub-clusters in SVD
2023-02-18 09:10:23 +01:00
sago35 e21ab04fad machine/usb/hid: add MediaKey support (#3436)
machine/usb/hid: add MediaKey support
2023-02-18 01:27:15 +01:00
Ayke van Laethem 4e8453167f all: refactor reflect package
This is a big commit that changes the way runtime type information is stored in
the binary. Instead of compressing it and storing it in a number of sidetables,
it is stored similar to how the Go compiler toolchain stores it (but still more
compactly).

This has a number of advantages:

  * It is much easier to add new features to reflect support. They can simply
    be added to these structs without requiring massive changes (especially in
    the reflect lowering pass).
  * It removes the reflect lowering pass, which was a large amount of hard to
    understand and debug code.
  * The reflect lowering pass also required merging all LLVM IR into one
    module, which is terrible for performance especially when compiling large
    amounts of code. See issue 2870 for details.
  * It is (probably!) easier to reason about for the compiler.

The downside is that it increases code size a bit, especially when reflect is
involved. I hope to fix some of that in later patches.
2023-02-17 22:54:34 +01:00
Ayke van Laethem ebb410afd9 reflect: make sure null bytes are supported in tags 2023-02-17 22:54:34 +01:00
Ron Evans 012bdfae80 build: always cache LLVM source/build even if the tests fail to avoid extra rebuilds (#3453)
builds/macos, linux, windows: update to explicit restore/save for LLVM source and LLVM builds
2023-02-17 17:52:15 +01:00
Anuraag Agrawal f6df276118 runtime: allow custom-gc SetFinalizer and clarify KeepAlive 2023-02-17 00:51:51 +01:00
Anuraag Agrawal e0a5fc2555 Filter target build-tags if user specified an overriding option (#3357)
compileopts: Filter target build-tags if user specified an overriding option
2023-02-14 23:21:28 +01:00
sago35 cecb80b8bf goenv: update to new v0.28.0 development version 2023-02-14 19:32:02 +01:00
Damian Gryski d899895e32 Makefile: more stdlib tests for CI 2023-02-14 05:17:46 -08:00
Ayke van Laethem 0d56dee00f ci: don't link with libzstd in release builds
libzstd was added in LLVM 15, but we don't currently use it. So let's
disable it in LLVM just like libzlib.

See: https://reviews.llvm.org/D128465
2023-02-11 09:14:15 +01:00
Ayke van Laethem 1f0bf9ba63 ci: switch to actions/checkout@v3
I saw the following warning on GitHub Actions:

    Node.js 12 actions are deprecated. Please update the following
    actions to use Node.js 16: actions/checkout@v2. For more information
    see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/.

Updating seems quite reasonable to me.
2023-02-07 22:00:21 +01:00
Ayke van Laethem 0b0ae19656 all: update x/tools/go/ssa to include slice-to-array bugfix
For the bugfix, see: https://github.com/golang/go/issues/57790
2023-02-07 10:21:35 +01:00
Ayke van Laethem 9027c50405 all: update to version 0.27.0 2023-02-03 07:38:40 -08:00
Ayke van Laethem 4ce54ede15 ci: switch to Go 1.20 2023-02-03 07:31:38 -08:00
Ayke van Laethem d8b1fac690 syscall: add more stubs as needed for Go 1.20 support 2023-02-03 07:31:38 -08:00
Ayke van Laethem 1996fad075 windows: add support for syscall.runtimeSetenv
I missed this in https://github.com/tinygo-org/tinygo/pull/3391 (because
I didn't test on Windows, my fault).
2023-02-03 07:31:38 -08:00
Ayke van Laethem 7fe996e7ba runtime: implement internal/godebug.setUpdate
This function was a stub, but it really needs to be implemented for full
Go 1.20 support. Without it, the archive/zip tests will fail.
2023-02-03 07:31:38 -08:00
Anuraag Agrawal 47ca1c037b Add custom-gc stub for ReadMemStats 2023-01-31 16:41:49 +01:00
Ayke van Laethem df0f5ae1da windows: add ARM64 support
This was actually surprising once I got TinyGo to build on Windows 11
ARM64. All the changes are exactly what you'd expect for a new
architecture, there was no special weirdness just for arm64.

Actually getting TinyGo to build was kind of involved though. The very
short summary is: install arm64 versions of some pieces of software
(like golang, cmake) instead of installing them though choco. In
particular, use the llvm-mingw[1] toolchain instead of using standard
mingw.

[1]: https://github.com/mstorsjo/llvm-mingw/releases
2023-01-30 21:42:47 +01:00
John Clark 45c8817ddd Support for the Espressif ESP32-C3-DevKit-RUST-1 development board
Signed-off-by: John Clark <inindev@gmail.com>
2023-01-29 22:50:12 +01:00
Anuraag Agrawal eebd2f648b Add -gc=custom option (#3302)
* Add -gc=custom option
2023-01-28 20:24:56 +01:00
Takeshi Yoneda 13698b17f7 runtime/debug: stubs PrintStack
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
2023-01-27 10:24:54 +01:00
deadprogram dd9c2273e4 runtime/stm32wlx: change order for init so clock speeds are set before peripheral start
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-27 00:08:38 +01:00
John Clark 1adfdf8fa5 Support for Makerfabs ESP32C3SPI35 TFT Touchscreen board
Signed-off-by: John Clark <inindev@gmail.com>
2023-01-26 20:16:11 +01:00
Ayke van Laethem da362b8a24 wasm: support ThinLTO
Using ThinLTO manages to optimize binaries quite significantly. The
exact amount varies a lot by program but it's about 10-15% usually.

Don't remove non-ThinLTO support yet. It would not surprise me if this
triggered some unintended side effect. Eventually, non-ThinLTO support
should be removed though.
2023-01-25 18:43:00 +01:00
Olivier Fauchon 7fa13ed0a6 Target MCU was not properly defined for LGT92 target
Change openocd interface from stlink-v2 to stlink (interface/stlink-v2.cfg is deprecated)
2023-01-25 14:11:28 +01:00
Olivier Fauchon eec915170d stm32wl: Fix incomplete RNG initialisation 2023-01-24 16:16:56 +01:00
Adrian Cole 334a12818d Allows the emulator to expand {tmpDir}
This allows you to expand {tmpDir} in the json "emulator" field, and
uses it in wasmtime instead of custom TMPDIR mapping logic.

Before, we had custom logic for wasmtime to create a separate tmpDir
when running go tests. This overwrite the TMPDIR variable when running,
after making a mount point. A simpler way to accomplish the end goal of
writing temp files is to use wasmtime's map-dir instead. When code is
compiled to wasm with the wasi target, tempDir is always /tmp, so we
don't need to add variables (since we know what it is). Further, the
test code is the same between normal go and run through wasmtime. So, we
don't need to make a separate temp dir first, and avoiding that reduces
logic, as well makes it easier to swap out the emulator (for wazero
which has no depedencies). To map the correct directory, this introduces
a {tmpDir} token whose value is the host-specific value taken from
`os.TempDir()`.

The motivation I have for this isn't so much to clean up the wasmtime
code, but allow wazero to execute the same tests. After this change, the
only thing needed to pass tests is to change the emulator, due to
differences in how wazero deals with relative lookups (they aren't
restricted by default, so there's not a huge amount of custom logic
needed).

In other words, installing wazero from main, `make tinygo-test-wasi`
works with no other changes except this PR and patching
`targets/wasi.json`.
```json
	"emulator":      "wazero run -mount=.:/ -mount={tmpDir}:/tmp {}",
```

On that note, if there's a way to override the emulator via arg or env,
this would be even better, but in any case patching json is fine.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2023-01-19 20:06:18 +01:00
Damian Gryski 0504e4a201 compiler,runtime: make keySize and valueSize uintptr 2023-01-18 09:48:00 +01:00
Damian Gryski 530ca0838d compiler,runtime: allow map values >256 bytes 2023-01-18 09:48:00 +01:00
Ayke van Laethem c41a212712 wasm: avoid miscompile with ThinLTO
I found that when I enable ThinLTO, a miscompilation triggers that had
been hidden all the time previously. The bug appears to happen as
follows:

 1. TinyGo generates a function with a runtime.trackPointer call, but
    without an alloca (or the alloca gets optimized away).
 2. LLVM sees that no alloca needs to be kept alive across the
    runtime.trackPointer call, and therefore it adds the 'tail' flag.
    One of the effects of this flag is that it makes it undefined
    behavior to keep allocas alive across the call (which is still safe
    at that point).
 3. The GC lowering pass adds a stack slot alloca and converts
    runtime.trackPointer calls into alloca stores.

The last step triggers the bug: the compiler inserts an alloca where
there was none before but that's not valid as long as the 'tail' flag is
present.

This patch fixes the bug in a somewhat dirty way, by always creating a
dummy alloca so that LLVM won't do the optimization in step 2 (and
possibly other optimizations that rely on there being no alloca
instruction).
2023-01-18 08:24:42 +01:00
Ayke van Laethem 27824e3c80 compiler: move some llvmutil code into the compiler
This is purely a refactor, to make the next change simpler.
The wordpack functionality used to be necessary in transform passes, but
now it isn't anymore so let's not complicate this more than necessary.
2023-01-18 08:24:42 +01:00
Ayke van Laethem 159317a5fe all: remove remaining +build lines 2023-01-17 23:35:53 +01:00
Ayke van Laethem 655075e5e0 runtime: implement precise GC
This implements the block-based GC as a partially precise GC. This means
that for most heap allocations it is known which words contain a pointer
and which don't. This should in theory make the GC faster (because it
can skip non-pointer object) and have fewer false positives in a GC
cycle. It does however use a bit more RAM to store the layout of each
object.

Right now this GC seems to be slower than the conservative GC, but
should be less likely to run out of memory as a result of false
positives.
2023-01-17 19:32:18 +01:00
Ayke van Laethem f9d0ff3bec all: store data layout as little endian value
This makes it much easier to read the value at runtime, as pointer
indices are naturally little endian. It should not affect anything else
in the program.
2023-01-17 19:32:18 +01:00
Ayke van Laethem 17176a2cea runtime: zero freed memory
This helps to find bugs in the GC. It does have a performance impact so
it's only enabled when asserts are enabled.
2023-01-17 19:32:18 +01:00
Ayke van Laethem fb73074325 runtime: move GC code around to prepare for precise GC
Most of the code of the conservative GC can be reused for the precise
GC. So before adding precise GC support, this commit just moves code
around to make the next commit cleaner. It is a non-functional change.
2023-01-17 19:32:18 +01:00
Ayke van Laethem 187d9c6aca riscv: use 16-byte alignment everywhere
Source: https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf
2023-01-17 19:32:18 +01:00
Ayke van Laethem 35f427c8cc xtensa: use 8-byte alignment
This is probably not necessary on Espressif chips, but let's strictly
follow the ABI to be sure.
2023-01-17 19:32:18 +01:00
Ayke van Laethem 26b6d0b06d runtime: arm actually has 8-byte alignment
Specification:
https://developer.arm.com/documentation/dui0472/k/C-and-C---Implementation-Details/Basic-data-types-in-ARM-C-and-C--
There are multiple types that have an 8-byte alignment (long long,
double) so we need to use the same maximum alignment in TinyGo.

Fixing this is necessary for the precise GC.
2023-01-17 19:32:18 +01:00
Ayke van Laethem 38252e338f runtime: arm64 actually has 16-byte alignment like amd64
Proof: https://godbolt.org/z/as4EM3713
Essentially, this means that there are objects on arm64 that have a
16-byte alignment and so we have to respect that when we allocate things
on the heap.
2023-01-17 19:32:18 +01:00
Marcus Sorensen e7ba07dd5a Add PDM support for circuitplay-bluefruit (#3359)
machine/nrf52840: add PDM support

Signed-off-by: Marcus Sorensen <marcus@turboio.com>
2023-01-17 12:32:01 +01:00
Ayke van Laethem 0d646d8e95 builder: add support for Go 1.20
Not all features work yet, but allow it to compile with this Go version.
2023-01-17 08:38:54 +01:00
Ayke van Laethem 3177591b31 syscall: implement setenv/unsetenv in the runtime
This is expected starting with Go 1.20.

I've also applied the same modification to syscall_libc.go so that
setenv is only called in a single place.
2023-01-17 08:38:54 +01:00
Ayke van Laethem 19db0144ae runtime: implement internal/godebug.setUpdate as a stub
This function provides a mechanism to watch for changes to the GODEBUG
environment variable. For now, we'll not implement it. It might be
useful in the future, when it can always be added.
2023-01-17 08:38:54 +01:00
Ayke van Laethem d639e01650 runtime: implement math/rand.fastrand64 to fix linker error
This is needed for Go 1.20 support.
2023-01-17 08:38:54 +01:00
Ayke van Laethem c43958972c compiler: add support for new unsafe slice/string functions
This adds support for unsafe.SliceData, unsafe.String, and
unsafe.SringData that were introduced in Go 1.20.
2023-01-17 08:38:54 +01:00
Ayke van Laethem 33489d6344 testing: implement t.Setenv
This method has been added in Go 1.17 and is used in archive/zip
starting with Go 1.20. Therefore, this method is now needed in Go 1.20.

I've left out the parts that disable parallel execution of tests,
because we don't do that in TinyGo.

See:
* https://github.com/golang/go/issues/41260
* https://go-review.googlesource.com/c/go/+/260577
2023-01-15 11:48:05 +01:00
Ayke van Laethem 80077ef276 test: print package name when compilation failed
Before this patch, a compile error would prevent the 'ok' or 'FAIL' line
to be printed. That's unexpected. This patch changes the code in such a
way that it's obvious a test result line is printed in all cases.

To be able to also print the package name, I had to make sure the build
result is passed through everywhere even on all the failure paths. This
results in a bit of churn, but it's all relatively straightforward.

Found while working on Go 1.20.
2023-01-15 08:49:18 +01:00
Ayke van Laethem 911ce3a4bc compiler: update golang.org/x/tools/ssa
This package needs to be updated to support Go 1.20. There were a few
backwards incompatible changes that required updates to the compiler
package.
2023-01-14 22:08:38 +01:00
joey 776dabb2c8 add a stub for os.Chtimes 2023-01-12 15:58:08 +01:00
Ayke van Laethem e11df5c212 cgo: add support for bitwise operators 2023-01-12 08:51:03 +01:00
deadprogram 656805d91f docs: update README with missing boards
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-11 21:51:03 +01:00
Thomas Richner 05ec4e6bd0 Support for Adafruit Feather M0 Express board 2023-01-11 10:07:11 +01:00
Achille Roussel ae65b37762 add comment about where src/os/file.go came from
Signed-off-by: Achille Roussel <achille.roussel@gmail.com>
2023-01-10 20:40:53 +01:00
John Clark aa12579864 Add SPI support for for the ESP32-C3 device.
Signed-off-by: John Clark <inindev@gmail.com>
2023-01-10 15:52:25 +01:00
Damian Gryski 715b269f78 src/runtime: add xorshift-based fastrand64 2023-01-08 10:35:31 +01:00
sago35 5f3534fe72 machine/usb: change to not send before endpoint initialization 2023-01-08 08:44:27 +01:00
irieda a7ff2731b9 Add USB HID joystick support (#3366)
machine/usb: add USB HID joystick support
2023-01-07 22:30:40 +01:00
Anuraag Agrawal 0566bbfeb4 Use renamed EXTRA_CFLAGS when building wasi-libc 2023-01-07 19:53:48 +01:00
sago35 70c4e1cf96 machine/usb: improve buffer size definition 2023-01-07 17:57:19 +01:00
Ayke van Laethem 9fd0567fb5 compiler: fix stack overflow when creating recursive pointer types
There were two types that could result in a compiler stack overflow.
This is difficult to fix in LLVM 14, so I won't even bother. However,
this is trivial to fix with opaque pointers in LLVM 15. Therefore, this
fix is for LLVM 15 only.

Fixes: https://github.com/tinygo-org/tinygo/issues/3341
2022-12-22 17:45:05 +01:00
BCG 481aba6536 board: Adafruit KB2040 (https://www.adafruit.com/product/5302) 2022-12-22 11:49:31 +01:00
Adrian Cole a700f58581 wasi: makes wasmtime "run" explicit
wasmtime by default will assume the subcommand is "run" vs one of its
others, but being explicit helps clarify the actual command invoked.

For example, we pass similar looking args to wasmtime and also wasi.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-12-22 09:22:17 +01:00
Jesús Espino e71e289e8b Add basic atmega32u support (#3337)
machine/atmega32u: add support for arduino leonardo
2022-12-20 16:57:55 +01:00
sago35 6cdc718bfb rp2040: drop deprecated build tags 2022-12-20 15:53:02 +01:00
sago35 70c94c6d01 rp2040: add version check for RP2040-E5 2022-12-20 15:53:02 +01:00
sago35 762a6f1256 rp2040: fix usb device enumeration (RP2040-E5) 2022-12-20 15:53:02 +01:00
Yurii Soldak 8d4d3c6201 build: drop deprecated build tags 2022-12-19 23:20:11 +01:00
Yurii Soldak 146e2cd376 build: generate files with go:build tags 2022-12-19 23:20:11 +01:00
Jesús Espino d304e6706b Adding support for waveshare rp2040-zero (#3321)
machine: adding support for waveshare rp2040-zero
2022-12-19 12:15:03 +01:00
deadprogram c5c6464175 compileopts: replace 'retries' with more correct 'timeout' param
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-12-19 08:44:39 +01:00
sago35 c90ff1e1cf rp2040: fix interrupt issue (2) 2022-12-19 08:43:56 +01:00
sago35 0f6dfedcfd rp2040: fix interrupt issue 2022-12-17 12:52:19 +01:00
Ron Evans 69a284bd36 Revert "Bump CMSIS to 5.9.0"
This reverts commit 92be61534e.
2022-12-16 21:26:49 +01:00
Anton D. Kachalov 92be61534e Bump CMSIS to 5.9.0 2022-12-16 15:42:35 +01:00
Damian Gryski 675b8e3f3c builder: always run wasm-opt for wasm32 binaries 2022-12-16 10:11:39 +01:00
Ayke van Laethem f3d0195d35 runtime: move KeepAlive/SetFinalizer to common code
We don't support these yet so let's just put them in a central location.
Once these functions are supported we can think about how to structure
the code again.
2022-12-15 19:25:27 +01:00
sago35 398c284480 usbhid: change usage-maximum to 0xFF 2022-12-15 18:24:54 +01:00
Damian Gryski 86f125cf72 reflect: track flags when size changes from fits-in-pointer to not
Fixes #3328
2022-12-07 23:11:40 +01:00
sago35 5293d3e5f0 atsame5x: reduce heap allocation 2022-12-01 22:27:12 +01:00
Ayke van Laethem 7aca814954 windows: update mingw-w64 version
This gets rid of the following messages:

    ld.lld: warning: duplicate /export option: hypot
    ld.lld: warning: duplicate /export option: nextafter

I've wanted to wait for the next release but that may take a long while,
so I've simply set the submodule to the commit that fixes this message.
2022-11-26 21:42:15 +01:00
deadprogram 1d52e6be29 machine/nrf51: add ADC implementation
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-11-26 20:17:11 +01:00
sago35 acb2391439 atsame5x: fix extendedID handling 2022-11-25 17:57:16 +01:00
Ayke van Laethem 49007891c8 all: re-enable AVR tests
I have some confidence they'll work reliably now.
2022-11-25 10:56:42 +01:00
Ayke van Laethem 54aec042b7 avr: add channel test
It is working now, so add it as a test. Not sure why, maybe the ThinLTO
change fixed something here?
2022-11-25 10:56:42 +01:00
sago35 baca8a643e xiao-rp2040: add pin definitions 2022-11-23 09:01:48 +01:00
Anuraag Agrawal b731919f97 Fix panic when size 0 passed to malloc 2022-11-21 21:00:36 +01:00
Julia Ogris c759e6fc2d reflect: Add Value.IsZero() method
Add Value.IsZero() with tests, largely copied from the Go source code.

The tests were altered to remove the parts calling `Zero()` as that is
still unimplemented in tinygo, and to remove a test that tries to catch
a panic which is not supported on wasi.

A new case for `UnsafePointer` in `Value.IsNil()` was required for
unsafe.Pointer tests to pass.

Link: https://cs.opensource.google/go/go/+/refs/tags/go1.19.3:src/reflect/value.go;l=1568
Link: https://cs.opensource.google/go/go/+/refs/tags/go1.19.3:src/reflect/all_test.go;l=1322
Co-authored-by: Cam Hutchison <camh@xdna.net>
2022-11-21 14:51:22 +01:00
goropikari a329f56ec2 Fix xiao rp2040 pin variable assignment
According to official infomation(https://wiki.seeedstudio.com/XIAO-RP2040/), D9 and D10 are corresponding to GPIO4 and GPIO3, respectively.
2022-11-21 11:49:18 +01:00
deadprogram 6e503f5ab9 build: update docker GH action to use latest docker action versions 2022-11-21 10:59:59 +01:00
deadprogram 217449df07 machine/stm32f1, stm32f4: fix ADC by clearing the correct bit for rank after each read
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-11-21 08:53:21 +01:00
deadprogram a7fc65861d machine/stm32: always set ADC pins to pullups floating
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-11-21 08:53:21 +01:00
Damian Gryski f0a271bd21 transform: remove duplicate if in gc transform 2022-11-18 20:19:47 +01:00
Ayke van Laethem 4d14d3cd54 avr: support ThinLTO
ThinLTO results in a small code size reduction, which is nice
(especially on these very small chips). It also brings us one step
closer to using ThinLTO everywhere.
2022-11-18 18:40:38 +01:00
Ayke van Laethem 5c622cfc43 compiler: refactor some code for the next commit
This is a pure refactor, it doesn't change the behavior of anything.
It's separate from the next commit so that the actual changes are easier
to read.
2022-11-18 18:40:38 +01:00
Ayke van Laethem 783c6a813a wasm: fix scanning of the stack
LLVM wasn't aware that runtime.stackChainStart must be kept live and
can't be optimized away. With this hack, it is forced to consider
stackChainStart live at the time of the stack scan.

This fixes the corruption in https://github.com/tinygo-org/tinygo/issues/3277
2022-11-17 17:19:10 +01:00
Ayke van Laethem 67841207e8 Revert "Enable wasm pointer tracking for gc=none."
This reverts commit 0b3a7280fa and updates
the documentation a little bit to explain the purpose of -gc=none. (I'm
thinking about the attiny10 by the way where defaulting to -gc=none
makes sense).
2022-11-17 15:50:57 +01:00
tachyonicbytes d92e16e6dc Stubbed Setuid and friends. Stubbed Exec (#3290)
Co-authored-by: TachyonicBytes <TB>
2022-11-16 10:14:27 +01:00
Dan Kegel 4daf4fa0a0 corpus: add buger/jsonparser 2022-11-15 11:03:05 +01:00
Anuraag Agrawal 0b3a7280fa Enable wasm pointer tracking for gc=none. 2022-11-15 10:21:11 +01:00
Ayke van Laethem bb5050a50d avr: fix .data initialization for binaries over 64kB
I found that .data is not correctly initialized with firmware images
that use over 64kB of flash. The problem is that the data in .data
(which is stored in flash, and copied to RAM at reset) is beyond the
64kB limit and must therefore be loaded using the elpm instruction
instead of the lpm instruction.

I encountered this issue while getting testdata/math.go to work for AVR.
The following command mostly works with this patch, while it prints
garbage withtout it:

    tinygo run -target=simavr -size=short -scheduler=none ./testdata/math.go

(This also requires a patch to picolibc to work, see
https://github.com/picolibc/picolibc/pull/371)

It still doesn't work entirely with this patch: some of the math
operations have an incorrect result. But at least it's an improvement as
it won't print garbage anymore.
2022-11-14 22:22:26 +01:00
deadprogram 73b368270c compileopts: add 'retries' flag to allow setting the number of times to retry locating the MSD volume when flashing
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-11-13 20:47:11 +01:00
Ayke van Laethem 2001c44ed3 builder: print compiler commands while building a library
We should have been doing this all along and makes it easier to debug
things that go wrong while compiling a library.
2022-11-12 17:38:02 +01:00
Ayke van Laethem 666ead3996 main: fix -work flag
I broke this flag in f866d5cc38. This
commit fixes it.
2022-11-06 14:06:58 +01:00
Ayke van Laethem df888acd5e avr: drop GNU toolchain dependency
- Use compiler-rt and picolibc instead of avr-libc.
  - Use ld.lld instead of avr-ld (or avr-gcc).

This makes it much easier to get started with TinyGo on AVR because
installing these extra tools (gcc-avr, avr-libc) can be a hassle.
It also opens the door for future improvements such as ThinLTO.

There is a code size increase but I think it's worth it in the long run.
The code size increase can hopefully be reduced with improvements to the
LLVM AVR backend and to compiler-rt.
2022-11-06 09:05:05 +01:00
Ayke van Laethem b9bb605257 all: update picolibc to v1.7.9
This newer version has some support for AVR.
2022-11-06 09:05:05 +01:00
Ayke van Laethem e1281b0128 darwin: fix error with tinygo lldb
Before this patch, `tinygo lldb path/to/package` would result in an
error:

    (lldb) target create --arch=arm64-unknown-macosx10.12.0 "/var/folders/17/btmpymwj0wv6n50cmslwyr900000gn/T/tinygo2731663853/main"
    error: the specified architecture 'arm64-unknown-macosx10.12.0' is not compatible with 'arm64-apple-macosx10.12.0' in '/var/folders/17/btmpymwj0wv6n50cmslwyr900000gn/T/tinygo2731663853/main'

This patch fixes this error.

Unfortunately, it doesn't get debug information to work yet. I still
haven't figured out what's going wrong here. But it's progress, I guess.
2022-11-05 10:20:03 +01:00
Ayke van Laethem 81dbbea1c8 esp: use ThinLTO for Xtensa
This is now possible because we're using the LLVM linker. It results in
some very minor code size reductions. The main benefit however is
consistency: eventually, all targets will support ThinLTO at which point
we can remove support for GNU linkers and simplify the compiler.
2022-11-04 22:49:22 +01:00
Anuraag Agrawal a834359079 Update docs 2022-11-04 19:53:12 +01:00
Anuraag Agrawal 29f8d22a2d sync: implement simple pooling in sync.Pool 2022-11-04 19:53:12 +01:00
Ayke van Laethem 9e34ca9e5f esp: use LLVM Xtensa linker instead of Espressif toolchain
The Espressif fork of LLVM now has Xtensa support in the linker LLD.
(This support was written mosly by me). This means we don't have to use
the Espressif GNU toolchain anymore and makes installing TinyGo simpler.

In the future, this also paves the way for ThinLTO support. Right now it
is mostly just a way to simplify TinyGo installation and speed up CI
slightly.
2022-11-04 09:11:21 +01:00
Ayke van Laethem 268140ae40 wasm: remove -wasm-abi= flag
This flag controls whether to convert external i64 parameters for use in
a browser-like environment.

This flag was needed in the past because back then we only supported
wasm on browsers but no WASI. Now, I can't think of a reason why anybody
would want to change the default. For `-target=wasm` (used for
browser-like environments), the wasm_exec.js file expects this
i64-via-stack ABI. For WASI, there is no limitation on i64 values and
`-wasm-abi=generic` is the default.
2022-11-04 08:28:26 +01:00
deadprogram 8906584fb9 testdata: clearly correct values for timing test with a little more time to spare on CI machines
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-11-03 15:26:20 +01:00
Ayke van Laethem aaa860f154 cgo: support anonymous enums included in multiple Go files
Anonymous enums (often used in typedefs) triggered a problem that was
already solved for structs but wasn't yet solved for enums. So this
patch generalizes the code to work for both structs and enums, and adds
testing for both.
2022-11-02 21:21:40 +01:00
Anuraag Agrawal bce0516394 Allow custom wasm malloc implementation (#3245) 2022-11-02 08:52:48 +01:00
Austin Vazquez 726d74ad1b Upgrade GitHub actions packages from v2 to v3
Signed-off-by: Austin Vazquez <macedonv@amazon.com>
2022-11-01 23:30:39 +01:00
waj334 ad544b5133 Implements calloc. 2022-10-31 17:46:09 +01:00
Ayke van Laethem 580fd490a5 all: remove libffi warning on macos
Running `go install` on MacOS produces the following warning:

    # github.com/tinygo-org/tinygo
    ld: warning: directory not found for option '-L/opt/homebrew/opt/libffi/lib'

It doesn't look like libffi is used anywhere, so I simply removed it.
Not sure why it was included in the first place.

(I updated the Makefile for consistency, but we really should be
removing that Makefile especially because the Go bindings are removed in
upstream LLVM).
2022-10-31 12:19:24 +01:00
Ayke van Laethem c0d505d13a all: use DWARF version 4
This should hopefully fix the following issue:

    DW_FORM_rnglistx index pointing outside of .debug_rnglists offset array [in module /tmp/tinygo4013272868/main]
2022-10-31 09:59:32 +01:00
Matt Johnston 12a41dc791 Add basic GPIO support for rp2040 PIO 2022-10-27 11:47:47 +02:00
soypat dd3ad57efb avoid allocating clock on heap 2022-10-26 23:27:28 +02:00
Damian Gryski 89facf834f fix printing of benchmark output 2022-10-26 20:07:31 +02:00
Anuraag Agrawal 62594004c6 Stub out reflect.Type FieldByIndex 2022-10-26 12:06:08 +02:00
Ayke van Laethem 3dbc4d5210 main: fix outputting .ll files
This command didn't work anymore since the refactor in #3211.
The reason it doesn't work anymore is that before the refactor, the code
in the callback wasn't executed for .ll, .bc and .o files but after the
refactor it is, which causes a spurious error.

This commit fixes this oversight.

Example that didn't work anymore and is fixed with this change:

    tinygo build -o test.ll examples/serial
2022-10-22 11:55:34 +02:00
Anuraag Agrawal 42e4a75319 Look for LLVM 15 in makefile 2022-10-21 09:16:46 +02:00
Ayke van Laethem 2b7f562202 ci: add support for LLVM 15
This commit switches to LLVM 15 everywhere by default, while still
keeping LLVM 14 support.
2022-10-19 22:23:19 +02:00
Ayke van Laethem 08a51535d4 interp: add support for constant icmp instructions
These instructions sometimes pop up in LLVM 15, but they never occured
in LLVM 14. Implementing them is relatively straightforward: simply
generalize the code that already exists for llvm.ICmp interpreting.
2022-10-19 22:23:19 +02:00
Ayke van Laethem 0ddcf4af96 riscv: add "target-abi" metadata flag
This flag is necessary in LLVM 15 because it appears that LLVM 15 has
changed the default target ABI from lp64 to lp64d. This results in a
linker failure. Setting the "target-abi" forces the RISC-V backend to
use the intended target ABI.
2022-10-19 22:23:19 +02:00
Ayke van Laethem d435fc868b transform: fix memory corruption issues
There was a bug in the wasm ABI lowering pass (found using
AddressSanitizer on LLVM 15) that resulted in a rather subtle memory
corruption. This commit fixes this issues.
2022-10-19 22:23:19 +02:00
Ayke van Laethem 62df1d7490 all: remove pointer ElementType calls
This is needed for opaque pointers, which are enabled by default in
LLVM 15.
2022-10-19 22:23:19 +02:00
Ayke van Laethem 229746b71e interp: change object.llvmType to the initializer type
Previously it was a pointer type, which won't work with opaque pointers.
Instead, use the global initializer type instead.
2022-10-19 22:23:19 +02:00
Ayke van Laethem 09ec846c9f all: replace llvm.Const* calls with builder.Create* calls
A number of llvm.Const* functions (in particular extractvalue and
insertvalue) were removed in LLVM 15, so we have to use a builder
instead. This builder will create the same constant values, it simply
uses a different API.
2022-10-19 22:23:19 +02:00
Ayke van Laethem f57cffce2d all: add type parameter to *GEP calls
This is necessary for LLVM 15.
2022-10-19 22:23:19 +02:00
Ayke van Laethem 7b6a9fab42 all: add type parameter to CreateLoad
This is needed for LLVM 15.
2022-10-19 22:23:19 +02:00
Ayke van Laethem 6bc6de8f82 all: add type parameter to CreateCall
This uses LLVMBuildCall2 in the background, which is the replacement for
the deprecated LLVMBuildCall function.
2022-10-19 22:23:19 +02:00
Ayke van Laethem b79bf29c11 compiler: return a FunctionType (not a PointerType) in getRawFuncType
This is necessary for opaque pointer support (in LLVM 15).
2022-10-19 22:23:19 +02:00
Ayke van Laethem 65d65c1313 wasm: fix GC scanning of allocas
Scanning of allocas was entirely broken on WebAssembly. The code
intended to do this was never run. There were also no tests.

Looking into this further, I found that it is actually not really
necessary to do that: the C stack can be scanned conservatively and in
fact this was already done for goroutine stacks (because they live on
the heap and are always referenced). It wasn't done for the system stack
however.

With these fixes, I believe code should be both faster *and* more
correct.

I found this in my work to get opaque pointers supported in LLVM 15,
because the code that was never reached now finally got run and was
actually quite buggy.
2022-10-19 18:36:53 +02:00
Damian Gryski 6b46ae261a runtime: switch some panic() calls in the gc to runtimePanic() for consistency 2022-10-19 12:54:17 +02:00
Fred Goya b734b3c7a1 Print PASS on pass when running standalone test binaries (#3229)
* Add test.batch flag so standalone tests print PASS on pass
* Add comment; use single-dash flag style to match usage elsewhere
* Don't add test.batch for wasmtime
* Skip test.batch unless emulator name is blank
* Remove test.batch flag; buffer test output and show only on verbose or failure
* Remove FAIL when all tests fail to match go test output
2022-10-19 09:46:43 +02:00
Ayke van Laethem 5937f03a07 corpus: remove 'noasm' from some tests
Unfortunately I couldn't fully test these changes, but they don't seem
to be needed on linux/amd64.
2022-10-19 00:03:40 +02:00
Ayke van Laethem bf9282a3a0 corpus: remove golang.org/x/crypto/internal/subtle
This subdirectory appears to be gone now.
2022-10-18 20:44:40 +02:00
Hrishi Hiraskar cad5b79a2d net: implement Pipe 2022-10-18 07:50:31 +02:00
deadprogram d56c9f5533 machine/usb: add back New() with deprecation comment to use Port() instead
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-10-17 14:46:18 +02:00
deadprogram 3d7f24e26c machine/usb: rename 'New()' to 'Port()' to have the API better match the singleton that is actually being returned
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-10-17 14:46:18 +02:00
Ayke van Laethem c32490935b main: fix error message when a serial port can't be accessed
Old message:

    error: failed to reset port /tmp/tinygo1441085170/main.uf2: opening port: Permission denied

new message:

    error: failed to reset port /dev/ttyACM0: opening port: Permission denied
2022-10-16 22:17:27 +02:00
Ayke van Laethem 2b04006b1e main: fix USB vid/pid lookup
I introduced a bug in #3207: looking up a VID/PID pair would result in a
slice out of bounds panic. This is a trivial fix for that bug.
2022-10-16 22:17:27 +02:00
Ayke van Laethem 9de757205f linux: include musl 'getpagesize' function in release
I wonder why nobody else noticed this bug? In any case, this patch fixes it.
2022-10-16 12:03:03 +02:00
Ayke van Laethem f866d5cc38 builder: refactor Build function to not use a callback
The only reason a callback was used, was so that the temporary directory
gets removed once `Build` returns. But that is honestly a really bad
reason: the parent function can simply create a temporary function and
remove it when it returns. It wasn't worth the code complexity that this
callback created.

This change should not cause any observable differences in behavior (it
should be a non-functional change).

I have no reason to do this now, but this unclean code has been bugging
me and I just wanted to get it fixed.
2022-10-16 10:48:34 +02:00
Ayke van Laethem c153239682 targets: remove "acm:"` prefix for USB vid/pid pair
This prefix isn't actually used and only adds noise, so remove it.

It may have been useful on Linux that makes a distinction between
/dev/ttyACM* and /dev/ttyUSB* but it isn't now. Also, it's unlikely that
the same vid/pid pair will be shared between an acm and usb driver
anyway.
2022-10-16 10:02:48 +02:00
deadprogram 8e88f3e76a build/windows: use GH actions parallel execution to cut build time in half.
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-10-16 09:22:01 +02:00
Ayke van Laethem a62044d89b targets: do not set stack size per board
The needed stack size is hard to determine by the compiler. It will try,
but will fail in many common cases. Therefore, the runtime will pick a
fixed stack size.

There is a tradeoff between avoiding stack overflows and wasting RAM.
This tradeoff depends on the application: some don't need large stack
sizes but do need a lot of memory, while others need deep stacks but
aren't so memory constrained. That's why I've added a flag to do this on
the command line: https://github.com/tinygo-org/tinygo/pull/3159

It may be reasonable to use a different stack size per chip, for example
chips with lots of RAM could default to a larger stack size. But I don't
think it's a good idea to do this per board.
2022-10-14 13:36:42 +02:00
Ayke van Laethem 5548b5999b Makefile: add ASAN=1 flag to build with AddressSanitizer enabled
This sanitizer is useful to detect use-after-free, double free, buffer
overflows, and more such errors.

I've found it useful lately to detect some bugs in TinyGo, and having a
single flag to enable it makes it much easier to enable
AddressSanitizer.
2022-10-14 11:17:51 +02:00
Kenneth Bell 8f33721b88 usb: remove allocs in ISR 2022-10-13 23:37:34 +02:00
Ayke van Laethem 7e9d84777e darwin: fix syscall.Open on darwin/arm64
Unfortunately the calling convention for variadic functions is different from
the calling convention of regular functions on darwin/arm64, and open happens
to be such a variadic function. The syscall package treated it like a regular
function, which resulted in buggy behavior.

This fix introduces a wrapper function. This is the cleanest change I could
come up with.
2022-10-13 21:07:38 +02:00
Ayke van Laethem 2072d1bb5c main: print ldflags including ThinLTO flags with -x
The -x flag prints commands as they are executed. Unfortunately, for the link
command, they were printed too early: before the ThinLTO flags were added.
This is somewhat confusing while debugging.
2022-10-13 18:57:49 +02:00
Ayke van Laethem 636a151ffe cgo: add support for C.float and C.double
They are not necessary in TinyGo because they always map to float32 and
float64, but it's a good idea to add them regardless for compatibility
with existing software.

(Now I think about it, perhaps it would have been better to require
explicit casts here just in case we want to support some really weird C
system, but then again we even force 64-bit double on AVR even though
avr-gcc defaults to 32-bit double).
2022-10-13 17:13:12 +02:00
Ayke van Laethem e7d02cd51b all: update musl 2022-10-13 13:38:02 +02:00
Ayke van Laethem f136eb6adf goenv: update to new v0.27.0 development version 2022-10-13 12:06:48 +02:00
Kenneth Bell 2688d9d733 rp2040: remove mem allocation in GPIO ISR 2022-10-07 11:46:12 +01:00
Ayke van Laethem b5ad81c884 all: update to version 0.26.0 2022-09-29 15:05:15 +02:00
deadprogram c2fb1e776a testdata: increase timings used for timers test to try to avoid race condition errors on macOS CI
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-09-28 21:55:37 +02:00
Ayke van Laethem 895c542076 builder: do not ignore debug info on baremetal targets
Since https://github.com/tinygo-org/tinygo/pull/3200, `-no-debug` would
ignore debug info for some linkers. Example:

    $ tinygo build -o test.elf -target=arduino -no-debug examples/blinky1
    $ objdump -h test.elf

    test.elf:       file format elf32-avr

    Sections:
    Idx Name            Size     VMA      LMA      Type
      0                 00000000 00000000 00000000
      1 .text           000004e0 00000000 00000000 TEXT
      2 .trampolines    00000000 000004e0 000004e0 TEXT
      3 .stack          00000200 00800100 00800100 BSS
      4 .data           0000004c 00800300 000004e0 DATA
      5 .bss            000000a9 0080034c 0000052c BSS
      6 .debug_loc      00001bf0 00000000 00000000 DEBUG
      7 .debug_abbrev   000004ed 00000000 00000000 DEBUG
      8 .debug_info     00004176 00000000 00000000 DEBUG
      9 .debug_ranges   00000150 00000000 00000000 DEBUG
     10 .debug_str      0000206e 00000000 00000000 DEBUG
     11 .debug_pubnames 000024bf 00000000 00000000 DEBUG
     12 .debug_pubtypes 000004ca 00000000 00000000 DEBUG
     13 .debug_line     0000193c 00000000 00000000 DEBUG
     14 .debug_aranges  0000002c 00000000 00000000 DEBUG
     15 .debug_rnglists 00000015 00000000 00000000 DEBUG
     16 .debug_line_str 00000082 00000000 00000000 DEBUG
     17 .shstrtab       000000d9 00000000 00000000
     18 .symtab         000006d0 00000000 00000000
     19 .strtab         00000607 00000000 00000000

This shows that even though `-no-debug` is supplied, debug information
is emitted in the ELF file.

With this change, debug information is not stripped when TinyGo doesn't
know how to do it:

    $ tinygo build -o test.elf -target=arduino -no-debug examples/blinky1
    error: cannot remove debug information: unknown linker: avr-gcc

(This issue will eventually be fixed by moving to `ld.lld`).
2022-09-28 19:18:11 +02:00
Adrian Cole e91fae5756 compileopts: silently succeed when there's no debug info to strip
Before, on the baremetal target or MacOS, we errored if the user
provided configuration to strip debug info.

Ex.
```bash
$ $ tinygo build -o main.go  -scheduler=none --no-debug  main.go
error: cannot remove debug information: MacOS doesn't store debug info in the executable by default
```

This is a poor experience which results in having OS-specific CLI
behavior. Silently succeeding is good keeping with the Linux philosophy
and less distracting than logging the same without failing.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-09-27 08:16:35 +02:00
Ayke van Laethem f52ecf3054 machine: use NoPin constant where appropriate
In some cases, regular integers were used. But we have a constant to
explicitly say these pins are undefined: `NoPin`. So use this.

A better solution would be to not require these constants, like with the
proposal in https://github.com/tinygo-org/tinygo/issues/3152. This
change is just a slight improvement over the current state.
2022-09-26 20:44:47 +02:00
Crypt Keeper 725864d8dc cgo: fixes panic when FuncType.Results is nil (#3136)
* cgo: fixes panic when FuncType.Results is nil

FuncType.Results can be nil. This fixes the comparison and backfills
relevant tests.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
Co-authored-by: Ayke <aykevanlaethem@gmail.com>
2022-09-26 19:08:23 +02:00
Damian Gryski fca2de21b1 runtime: make gc and scheduler asserts settable with build tags 2022-09-25 16:47:07 +02:00
Ayke van Laethem 107b1c2906 machine: do not expose RESET_MAGIC_VALUE
This is a constant for internal use only, but was (unintentionally?)
exported. In addition, it doesn't follow the Go naming convention.
This change simply renames the constant so that it is unexported.
2022-09-25 12:38:12 +02:00
deadprogram 2409bbef69 build: set circleci resource class to large for CI build
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-09-25 10:08:10 +02:00
Ayke van Laethem 8b078a9e8f machine: remove level triggered pin interrupts
This removes level-triggered interrupts.

While working on https://github.com/tinygo-org/tinygo/pull/3170, I found
these level triggered interrupt constants. Apart from them being
inconsistent with each other (PinLowLevel vs PinLevelLow) I don't think
they are actually used anywhere. In addition, I removed the
PinNoInterrupt constant on the esp32c3. This makes the esp32c3 pass the
tests in #3170.

I looked into level-triggered interrupts and I really couldn't find a
good justification for them:

  - They were added to the esp32c3 and the rp2040 together with other
    pin interrupt types, meaning they were probably just added because
    the chip supports the feature and not because they were actually
    needed.
  - Level interrupts aren't supported in TinyGo for any other chip, and
    I haven't seen anybody ask for this feature.
  - They aren't supported in the nrf series chips _at all_, and with a
    quick search I found only very little demand for them in general.
  - I tried to see whether there is any good use case for them, but I
    couldn't really find one (where an edge triggered interrupt wouldn't
    work just as well). If there is one where level triggered interrupts
    are a real advantage over edge triggered interrupts, please let me
    know.

Of course, we shouldn't remove a feature lightly. But in this case, I
can't think of an advantage of having this feature. I can think of
downsides: more maintenance and having to specify their behavior in the
machine package documentation.
In general, I would like to keep the machine package clean and only
support things that have a proven use case.
2022-09-24 22:58:22 +02:00
sago35 9e24441978 main: allow setting the baud rate for serial monitors (#3190)
* main: allow setting the baud rate for serial monitors with default baudrate of 115200 bps
2022-09-24 19:09:41 +02:00
Ayke van Laethem 1e6c14b3e4 ci: build TinyGo using Go 1.19
We've supported Go 1.19 for a while now, let's actually use it in CI.
2022-09-24 13:22:38 +02:00
Crypt Keeper 25f6be1488 build: makes CI choose latest Go 1.18.x (#3143)
* build: makes CI choose latest Go 1.18.x
2022-09-24 10:14:18 +02:00
Ayke van Laethem 9a9106a297 esp32c3: remove unused UARTStopBits constants 2022-09-21 18:16:29 +02:00
Ayke van Laethem a68f7e4ce3 nrf: add ReadTemperature method
Similar to the rp2040, the nrf has an on-board temperature sensor.

The main reason why I added this function was to show how this new API
is more general and can be used on multiple chips.
2022-09-21 08:26:56 +02:00
Ayke van Laethem 70b3ece6ec rp2040: add machine.ReadTemperature
Replace ADCChannel.ReadTemperature() with a simple ReadTemperature
function.

Not all chips will have a temperature sensor that is read by sampling an
ADC channel. The replacement ReadTemperature is simpler and more generic
to other chip families.

This breaks chips that were relying on the previous ReadTemperature
method. I hope it won't break a lot of existing code. If it does, a
fallback can be added.
2022-09-21 08:26:56 +02:00
Ayke van Laethem 86ea216e7d machine: move SPI Tx function into separate file
This makes the code a bit cleaner because ErrTxInvalidSliceSize isn't
redefined in every file that uses SPI and Mode0/Mode1/Mode2/Mode3 is
defined for every target that uses SPI.
2022-09-21 06:52:42 +02:00
Ayke van Laethem 5a92c35536 main: restore support for flashing Espressif chips
This reverts commit 303410d3fc and also
removes the unnecessary fallback.
2022-09-20 23:03:07 +02:00
Ayke van Laethem 7513fa2c96 machine: add KHz, MHz, GHz constants, deprecate TWI_FREQ_* constants
There are two main issues with these constants:

  * They don't follow the Go naming convention.
  * They call themselves "TWI", while it makes a lot more sense to refer
    to the actual name which is I2C (or I²C).

I have not removed them but just deprecated them. Perhaps we can remove
them when we move towards version 1.0.
2022-09-20 21:00:17 +02:00
Ayke van Laethem bc946f346d machine: rename PinInputPullUp/PinInputPullDown
Some targets used capital PullUp/PullDown, while the documented standard
is Pullup/Pulldown. This commit fixes this mismatch, while preserving
compatibility with aliases that are marked deprecated.
2022-09-20 05:45:53 +02:00
Ayke van Laethem 6e6666519c go mod tidy 2022-09-19 20:14:09 +02:00
Ayke van Laethem cecae8084c nrf52840: do not export DFU_MAGIC_* constants
These constants are for internal use only, so should not have been
exported. In addition, they didn't follow the Go naming convention
before this change.
2022-09-19 07:41:46 +02:00
Ayke van Laethem 9720ccacbb machine: improve UARTParity slightly
There are only 3 possible values, so a uint8 seems more appropriate.
Also, there is no reason to use specific numbers over a simple
enumeration.
2022-09-18 21:30:30 +02:00
Damian Gryski a5aa777c7b src/runtime: add a few more docs about the garbage collector 2022-09-18 15:19:11 +02:00
sago35 aca1ad187d targets: remove usbpid of bootloader
For more information, see
https://github.com/tinygo-org/tinygo/pull/3168
2022-09-17 11:00:31 +02:00
sago35 5a41ed6329 xiao-ble: fix usbpid 2022-09-17 07:25:41 +02:00
Ayke van Laethem 91e9c84d85 nrf: make GetRNG available to all chips
All nrf chips have a cryptographically secure RNG on board. Therefore,
I've made the code more portable so that it works on all nrf chips.

I did remove a number of exported functions. I am of the opinion that
these should only be made available once we have an agreed upon API for
multiple chips. People who want to have greater control over the RNG
should use the device/nrf package directly instead.

I have also changed the behavior to always enable digital error
correction. Enabling it seems like a more conservative (and secure)
default to me. Again, people who would like to have it disabled can use
the device/nrf package directly.
2022-09-17 06:08:54 +02:00
sago35 4af530f238 wioterminal: remove serial-port setting of bootloader 2022-09-16 20:12:47 +02:00
Ayke van Laethem d3863f337d rp2040: do not use GetRNG in crypto/rand
The crypto/rand package is used for sensitive cryptographic operations.
Do not use the rp2040 RNG for this purpose, because it's not strong
enough for cryptography.

I think it is _possible_ to make use of the RP2040 RNG to create
cryptographically secure pseudo-random numbers, but it needs some
entropy calculation and secure hashing (blake2s or so) to make them
truly unpredictable.
2022-09-16 14:48:41 +02:00
Ayke van Laethem 5551ec7a1e cgo: implement support for static functions 2022-09-16 14:05:17 +02:00
Ayke van Laethem 91104b2f27 runtime: ensure some headroom for the GC to run
The GC was originally designed for systems with a fixed amount of
memory, like baremetal systems. Therefore, it just used what it could
and ran a GC cycle when out of memory.

Other systems (like Linux or WebAssembly) are different. In those
systems, it is possible to grow the amount of memory on demand. But the
GC only actually grew the heap when it was really out of memory, not
when it was getting very close to being out of memory.

This patch fixes this by ensuring there is at least 33% headroom for the
GC. This means that programs can allocate around 50% more than what was
live in the last GC cycle. It should fix a performance cliff when a
program is almost, but not entirely, out of memory and the GC has to run
almost every heap allocation.
2022-09-16 11:11:50 +02:00
sago35 80f38e8449 main: add serial port monitoring functionality
Co-authored-by: Ayke <aykevanlaethem@gmail.com>
2022-09-16 09:28:03 +02:00
Adrian Cole 22893c5180 wasm: documents memory constants
This documents memory constants. Somewhere, we should document what the
default memory size is (seems 2 pages so 128KB), as that determines the
initial heap size (which is a portion of that).

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-09-16 07:32:43 +02:00
Ayke van Laethem 9e4e182615 interp: fix reading from external global
This fixes https://github.com/tinygo-org/tinygo/issues/3020.
2022-09-15 19:07:04 +02:00
Ayke van Laethem 5f96d2b784 all: add flag for setting the goroutine stack size
This is helpful in some cases where the default stack size isn't big
enough.
2022-09-15 12:43:51 +02:00
Ayke van Laethem bd1d93b705 go mod tidy 2022-09-15 12:43:51 +02:00
Anuraag Agrawal 03d1c44265 wasm,wasi: make sure buffers returned by malloc are not freed until f… (#3148)
* wasm,wasi: make sure buffers returned by malloc are not freed until free is called
2022-09-15 09:14:39 +02:00
Adrian Cole dc0346d968 wasi: adds more details about why wasmtime flags are added
Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-09-14 19:52:04 +02:00
Ayke van Laethem dadae95448 ci: use the Go Alpine image for building the release binary
This fixes https://github.com/tinygo-org/tinygo/issues/3146 by using a
prebuilt Docker image. I don't remember why I used `setup-go` but
probably to make it faster (setup-go usually uses cached binaries).
2022-09-14 15:43:14 +02:00
sago35 f5fc2fc072 main: add support for stlink-dap programmer 2022-09-14 14:58:31 +02:00
Matt Schultz 4ba76a5df9 machine/nrf52840: implement RNG peripheral operation 2022-09-12 09:54:51 +02:00
deadprogram ea1e08f53f machine/rp2040: implement semi-random RNG based on ROSC based on pico-sdk
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-09-10 10:47:48 +02:00
Adrian Cole bba0dc9575 build: uses setup-go@v3 to simplify cache config
This updates to setup-go@v3 which is the only updated version (v2 last
updated in feb), and employs its cache to simplify workflow
configuration.

Notably, we can't do this for Alpine until #3146

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-09-09 21:48:51 +02:00
Isaac Rodman 617c7586fe Remove unconnected simple LED pin from qtpy-rp2040 2022-09-09 11:05:12 +02:00
Isaac Rodman 7366d5e185 Set default-stack-size to 4096, and remove NEOPIXELS pluralization for qtpy-rp2040 2022-09-09 11:05:12 +02:00
Adrian Cole 96e3ecd949 build: updates to actions/cache@v3
v2 has bugs and hasn't had a release since last November.

See https://github.com/actions/cache/releases

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-09-08 16:27:40 +02:00
Ayke van Laethem 8bbfb1ee68 wasm: do not allow undefined symbols
--allow-undefined can be a problem: it allows compiling code that will
fail when loaded. This change makes sure that if some symbols are
undefined, they are reported as an error by the linker.

Previously, people could get away with importing a function that was not
defined, like this:

    func add(int a, int b) int

    func test() {
        println(add(3, 5))
    }

This was always unintended but mostly worked. With this change, it isn't
possible anymore. Now every function needs to be marked with //export
explicitly:

    //export add
    func add(int a, int b) int

    func test() {
        println(add(3, 5))
    }

As before, functions will be placed in the `env` module with the name
set from the `//export` tag. This can be overridden with
`//go:import-module`:

    //go:import-module math
    //export add
    func add(int a, int b) int

    func test() {
        println(add(3, 5))
    }

For the syscall/js package, I needed to give a list of symbols that are
undefined. This list is based on the JavaScript functions defined in
targets/wasm_exec.js.
2022-09-08 08:25:27 +02:00
Adrian Cole 07cdcc61f7 examples: adds summary of wasm examples and fixes callback bug
This adds a summary of each wasm example, as before it was a bit unclear
how to do so. This also fixes the callback example which was broken.

Fixes #2568

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-09-07 13:31:21 +02:00
Ayke van Laethem 4ca9b34133 machine: add PWM peripheral comments to pins
These comments will be used in a change to the tinygo.org documentation.
2022-09-05 18:56:34 +02:00
Patricio Whittingslow d5e4b16911 add github.com/soypat/mu8 to corpus.yaml 2022-09-04 09:42:49 +02:00
sago35 fd05254683 Update compileopts/target.go
Co-authored-by: Ayke <aykevanlaethem@gmail.com>
2022-09-03 11:50:41 +02:00
sago35 c579e7e509 Update compileopts/target.go
Co-authored-by: Ayke <aykevanlaethem@gmail.com>
2022-09-03 11:50:41 +02:00
sago35 d463528a72 smoketest: add test to run tinygo targets 2022-09-03 11:50:41 +02:00
sago35 49b0086f8f main: improve error handling when loading target/*.json 2022-09-03 11:50:41 +02:00
Yurii Soldak d7814ff50b targets: fix build tag duplicates
and add missing targets to smoke test
2022-09-03 08:31:27 +02:00
Ayke van Laethem 02160aa8d8 windows: run more tests where supported
I found that some packages do in fact run on Windows, so I've added them
where possible. I've also updated the description of which packages fail
tests and why.
2022-09-02 20:04:28 +02:00
Ayke van Laethem c199dd03c7 windows: save and restore xmm registers when switching goroutines
This is required according to the Windows x64 calling convention:
https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#callercallee-saved-registers
We didn't do this, and this didn't appear to cause any problems. But we
should do it anyway for correctness.
2022-09-02 18:47:00 +02:00
Ayke van Laethem 472aecf07a targets: remove hifive1-qemu target
This target was added purely for running tests, and it is currently
unused. When I try to use it, it causes runtime exceptions.
The replacement riscv-qemu is much better behaved.

This doesn't drop support for any actual hardware, the HiFive 1 B will
remain supported.
2022-09-02 16:35:05 +02:00
Isaac Rodman 09350e5719 Add qtpy-rp2040 to TinyGo v0.25.0 2022-09-02 15:06:37 +02:00
Tim Schaub 623dd6a815 sync: implement map.LoadAndDelete 2022-09-02 11:48:01 +02:00
Joe Shaw e09bd5abb3 runtime/pprof, runtime/trace: stub some additional functions
These are necessary to import some parts of the net/http package.
2022-09-02 10:37:50 +02:00
Ayke van Laethem e955aa1941 reflect: implement CanInterface and fix string Index()
This commit fixes two related issues:

 1. CanInterface was unimplemented. It now uses the same check as is
    used in Interface() itself.
    This issue led to https://github.com/tinygo-org/tinygo/issues/3033
 2. Allow making an interface out of a string char element.

Doing this in one commit (instead of two) because they are shown to be
correct with the same tests.
2022-09-01 21:42:22 +02:00
sago35 edaf13f951 wioterminal: add UART3 for RTL8720DN 2022-09-01 19:22:01 +02:00
Ayke van Laethem 5f6cf665f5 compileopts: fix windows/arm target triple
This is just a papercut, and not really something important. But I
noticed something weird:

    $ GOOS=windows GOARCH=arm tinygo info ""
    LLVM triple:       armv7-unknown-windows-gnueabihf-gnu
    GOOS:              windows
    GOARCH:            arm

That -gnueabihf-gnu ending is weird, it should pick one of the two. I've
fixed it as follows:

    $ GOOS=windows GOARCH=arm tinygo info ""
    LLVM triple:       armv7-unknown-windows-gnu
    GOOS:              windows
    GOARCH:            arm
    [...]

We're probably never going to support windows/arm (this is 32-bit arm,
not arm64) so it doesn't really matter which one we pick. And this patch
shouldn't affect any other system.
2022-09-01 16:23:24 +02:00
Ayke van Laethem c6db89ff05 main: remove GOARM from tinygo info
I think it is more confusing than helpful because it is only relevant
when compiling an actual linux/arm binary (and in that case, it is also
included in the LLVM triple).

See: https://github.com/tinygo-org/tinygo/issues/3034
2022-09-01 13:17:37 +02:00
deadprogram 61d651c947 flash: update serial package to v1.3.5 for latest bugfixes
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-09-01 11:40:52 +02:00
Damian Gryski 227a55d891 loader,crypto: fix link error for crypto/internal/boring/sig.StandardCrypto 2022-09-01 09:48:40 +02:00
Ayke van Laethem b485e8bfbd compiler: fix unsafe.Sizeof for chan and map values
These types are simply pointers. For some reason, they were never
implemented.

Fixes https://github.com/tinygo-org/tinygo/issues/3083.
2022-09-01 03:53:27 +02:00
Ayke van Laethem 9e8739bb47 compiler: replace math aliases with intrinsics
This is really a few more-or-less separate changes:

  * Remove all math aliases that were used in Go 1.16 and below (the
    math.[A-Z] aliases).
  * Replace math aliases with an assembly implementation (the math.arch*
    aliases) with a LLVM intrinsic, where one is available.
  * Include missing math functions in picolibc build.

This leaves just four math aliases:

  * math.archHypot and math.archModf do not have a LLVM builtin
    equivalent. They could be replaced with calls to libm, and I think
    that would be a good idea in the long term.
  * math.archMax and math.archMin do have a LLVM builtin equivalent
    (llvm.maximum.f64, llvm.minimum.f64), but unfortunately they crash
    when used. Apparently these exact operations are not yet widely
    supported in hardware and they don't have a libm equivalent either.

There are more LLVM builtins that we could use for the math package
(such as FMA), but I will leave that to a future change. It could
potentially speed up some math operations.
2022-08-30 17:33:16 +02:00
Ayke van Laethem 20a7a6fd54 compiler: replace some math operation bodies with fast intrinsics
Instead of changing the calls, replace the function bodies themselves.
This is useful for a number of reasons, see
https://github.com/tinygo-org/tinygo/pull/2920 for more information.

I have removed the math intrinsics tests because they are no longer
useful. Instead, I think `tinygo test math` should suffice.
2022-08-30 17:33:16 +02:00
Ayke van Laethem 4695da83b7 all: drop support for Go 1.16 and Go 1.17 2022-08-30 12:38:06 +02:00
Yurii Soldak f094e895c5 p1am-100: remove duplicate build tags 2022-08-29 09:44:03 +02:00
Yurii Soldak 55573c6729 targets: fail fast on duplicate values in target field slices 2022-08-29 09:44:03 +02:00
Ayke van Laethem b8a6a1f62b compiler: use the LLVM builtins everywhere
This gives some more optimization opportunities to LLVM, because it
understands these intrinsics. For example, it might convert
llvm.sqrt.f64 to llvm.sqrt.f32 if possible.
2022-08-28 23:37:56 +02:00
Matt Schultz ef912a132d machine: Add support for Adafruit QT2040 board. 2022-08-28 10:16:52 +02:00
Yurii Soldak fb603a471c boards: Add XIAO ESP32C3 board 2022-08-26 12:44:04 +02:00
Joe Shaw f439514703 runtime: implement resetTimer 2022-08-25 11:30:33 +02:00
sago35 303410d3fc main: ignore ports with VID/PID if not candidates 2022-08-24 19:42:49 +02:00
Daniel Esteban aa13b5d83b Add Pimoroni's Tufty2040 board 2022-08-24 13:50:02 +02:00
Kenneth Bell 12d63d9642 runtime: improve reliability of timers test in CI 2022-08-24 11:05:40 +02:00
Kenneth Bell 24b45555bd runtime: add support for time.NewTimer and time.NewTicker
This commit adds support for time.NewTimer and time.NewTicker. It also
adds support for the Stop() method on time.Timer, but doesn't (yet) add
support for the Reset() method.

The implementation has been carefully written so that programs that
don't use these timers will normally not see an increase in RAM or
binary size. None of the examples in the drivers repo change as a result
of this commit. This comes at the cost of slightly more complex code and
possibly slower execution of the timers when they are used.
2022-08-23 12:37:25 +02:00
Damian Gryski 80c17c0f32 testdata: add russross/blackfriday markdown parser to corpus 2022-08-22 23:06:14 +02:00
Ayke van Laethem f6e6aca8d9 compiler: fix incorrect DWARF type in some generic parameters
For some reason, the type of a function parameter can sometimes be of
interface type, while it should be the underlying type. This might be a
bug in the x/tools/go/ssa package but this is a simple workaround.
2022-08-22 10:31:30 +02:00
Damian Gryski c4d99e5297 src/testing: add support for -benchmem 2022-08-20 11:41:20 +02:00
Damian Gryski 697e8c725b runtime: add MemStats.Mallocs and Frees 2022-08-20 11:41:20 +02:00
Damian Gryski a87e5cdbf0 runtime: add MemStats.TotalAlloc 2022-08-20 11:41:20 +02:00
Damian Gryski b56baa7aad runtime: make MemStats available to leaking collector 2022-08-20 11:41:20 +02:00
deadprogram ee94f92ede build: pin public_suffix Ruby gem to version 4.0.7
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-08-20 08:57:47 +02:00
Damian Gryski 0b77e92c50 make interp timeout configurable from command line 2022-08-20 07:40:39 +02:00
Avi a4ee98e0e1 Add aliases for edwards25519/field.feMul and field.feSquare
ed25519vectors_test.go still fails because:
* It relies on "go mod download" which doesn't work, as well as fork/exec.
* It relies on JSON parsing which has problems with reflection.

But, with the vectors hard coded in the test file the tests *do* succeed, so the encryption is working.
2022-08-18 18:57:16 +02:00
Miguel Angel d0808c93f6 runtime/pprof: add WriteHeapProfile
Fixes: #3071
2022-08-16 09:16:55 +02:00
Ayke van Laethem a0407be7b7 goenv: support GOOS=android
TinyGo doesn't currently support Android directly. However, GOOS=linux
works fine on Android. Therefore, force GOOS=linux on Android.
2022-08-13 12:43:38 +02:00
Elliott Sales de Andrade e70dfa4dd6 Fix skip message for missing emulators 2022-08-09 18:10:35 +02:00
Yeicor f34a0d44ca Fix for builds of tinygo using an Android host 2022-08-09 11:14:39 +02:00
Elliott Sales de Andrade df52b500bf Fix tinygo-test with Go 1.19
One of the internal packages used for tests was moved in that version.
2022-08-09 09:18:49 +02:00
Elliott Sales de Andrade c2f437e0b7 Add ErrProcessDone error
This is used in upstream Go's `os` package now.
2022-08-09 09:18:49 +02:00
Yurii Soldak 2365c7cfec nrf52: cleanup s140v7 uf2 targets 2022-08-07 12:58:36 +02:00
Yurii Soldak a5d28bdcca nrf52: cleanup s140v6 uf2 targets 2022-08-07 11:27:49 +02:00
Damian Gryski f12ddfe164 all: update _test.go files for os.IsFoo changes 2022-08-07 10:32:23 +02:00
Damian Gryski f9ba99344a all: update _test.go files for ioutil changes 2022-08-07 10:32:23 +02:00
Damian Gryski 1784bcd728 compileopts: use backticks for regexp to avoid extra escapes 2022-08-07 10:32:23 +02:00
Damian Gryski a2704f1435 all: move from os.IsFoo to errors.Is(err, ErrFoo) 2022-08-07 10:32:23 +02:00
Damian Gryski edbbca5614 all: remove calls to deprecated ioutil package
Fixes produced via semgrep and https://github.com/dgryski/semgrep-go/blob/master/ioutil.yml
2022-08-07 10:32:23 +02:00
Roman Volosatovs 13f21477b1 syscall/darwin: add ENOTCONN
Signed-off-by: Roman Volosatovs <roman@profian.com>
2022-08-07 09:04:57 +02:00
Roman Volosatovs 9d73e6cfe4 os: add SyscallError.Timeout
Signed-off-by: Roman Volosatovs <roman@profian.com>
2022-08-06 12:40:15 +02:00
Roman Volosatovs 9e7667ffae syscall: add WASI {D,R}SYNC, NONBLOCK FD flags
Signed-off-by: Roman Volosatovs <roman@profian.com>
2022-08-06 09:38:00 +02:00
Roman Volosatovs b86467f9c5 syscall: group WASI consts by purpose
Signed-off-by: Roman Volosatovs <roman@profian.com>
2022-08-06 09:38:00 +02:00
Roman Volosatovs 13a16afc2a net: sync net.go with Go 1.18 stdlib
Signed-off-by: Roman Volosatovs <roman@profian.com>
2022-08-06 08:05:29 +02:00
Roman Volosatovs a107b4d459 syscall: ensure correct C prototype WASI function signature
Signed-off-by: Roman Volosatovs <roman@profian.com>
2022-08-05 21:05:46 +02:00
Ayke van Laethem 5c176f80d5 ci: add check that TinyGo can be built using Homebrew LLVM
This is supposed to work, but there was no CI check. Add it to make sure
it continues to work.
2022-08-05 16:21:34 +02:00
Ayke van Laethem c4392d9472 all: rename assembly files to .S extension
The Go tools only consider lowercase .s files to be assembly files. By
renaming these to uppercase .S files they won't be discovered by the Go
toolchain and listed as the SFiles to be assembled.

There is a difference between .s and .S: only uppercase .S will be
passed through the preprocessor. Doing that is normally safe, and
definitely safe in the case of these files.
2022-08-04 15:43:42 +02:00
Ayke van Laethem b6d6efde07 all: remove support for LLVM 13 2022-08-04 14:31:54 +02:00
sago35 8b67282f91 examples/wasm: improve Makefile 2022-08-04 13:10:41 +02:00
Ayke van Laethem c7a23183e8 all: format code according to Go 1.19 rules
Go 1.19 started reformatting code in a way that makes it more obvious
how it will be rendered on pkg.go.dev. It gets it almost right, but not
entirely. Therefore, I had to modify some of the comments so that they
are formatted correctly.
2022-08-04 12:18:32 +02:00
Ayke van Laethem f936125658 main: use tags parser from buildutil
This should add support for things like quotes around tags, if they are
ever needed.

Only making this change now because I happened to stumble across
buildutil.TagsFlag.
2022-08-04 11:17:43 +02:00
sago35 3cfaceeb16 all: update version for next development iteration 2022-08-04 09:11:18 +02:00
Ayke van Laethem f0391eac25 all: update to version 0.25.0 2022-08-02 18:25:51 +02:00
Phil Kedy 05cdde162c Set internal linkage and keeping default visibility for anonymous functions 2022-08-01 10:53:48 +02:00
sago35 25c8d3ec3a wasm,wasi: stub runtime.buffered, runtime.getchar 2022-07-30 17:41:54 +02:00
Ayke van Laethem 7b1e5f6f99 compiler: implement unsafe.Alignof and unsafe.Sizeof for generic code
For some reason, these aren't lowered when a generic function is
instantiated by the SSA package.

I've left unsafe.Offsetof to be implemented later, it's a bit difficult
to do correctly the way the code is currently structured.
2022-07-28 15:43:51 +02:00
Ayke van Laethem 70c52ef1b4 compiler: fix type names for generic named structs
Without this change, the compiler would probably have worked just fine
but the generated types would look odd.

You can see in the test case that it now doesn't use `main.Point` but
rather the correct `main.Poin[float32]` etc.
2022-07-28 15:43:51 +02:00
Ayke van Laethem 5078ce382d compiler: do not try to build generic functions
There is no reason to: we should only build instantiated generic
functions.
2022-07-28 15:43:51 +02:00
Ayke van Laethem 408855da14 compiler: add generics test case
This test case shows a few bugs, that I will fix in subsequent patches.
2022-07-28 15:43:51 +02:00
Phil Kedy 58072a5167 compiler: fix issue with methods on generic structs 2022-07-28 13:46:07 +02:00
Kenneth Bell 5026047cde rp2040: make picoprobe default openocd interface 2022-07-28 06:48:46 +02:00
deadprogram 67aea275c5 machine/rp2040: turn off pullup/down when not input type not specified
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-07-27 21:45:45 +02:00
Ayke van Laethem 99bd4d2c7c esp32: optimize SPI transmit
For write-only operations (in SPI displays for example), the transmit
speed is doubled with this relatively small change.

In the future, we should try to use DMA instead for larger buffers. But
this is already a significant improvement and will always be an
improvement for small buffer sizes.
2022-07-27 17:22:34 +02:00
sago35 a4b22bd125 usb/midi: add definition of MIDI note number 2022-07-27 16:19:13 +02:00
deadprogram 2ed7523001 build/linux/arm: pin dotenv Ruby gem to version 2.7.6
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-07-27 14:25:23 +02:00
Ayke van Laethem 4aec3d04f9 esp32: fix WDT reset on the MCH2022 badge 2022-07-26 10:47:28 +02:00
Ayke van Laethem 4f729c323d darwin: don't clobber X18 and FP registers
These are reserved registers on MacOS so don't need to be clobbered, and
result in a compiler waring:

    ld.lld-14: warning: inline asm clobber list contains reserved registers: X18, FP
    Reserved registers on the clobber list may not be preserved across the asm statement, and clobbering them may lead to undefined behaviour.
2022-07-26 09:02:06 +02:00
deadprogram 1f43f32aae target: add gopherbot and gopherbot2 aliases to simplify for newer users
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-07-26 08:06:24 +02:00
Kenneth Bell 6d1cbe6fb9 rp2040: usb: reset device address on bus reset 2022-07-26 06:47:16 +02:00
sago35 7cd2890434 rp2040: add resetBlock for USBCTRL 2022-07-25 17:01:14 +02:00
sago35 13311da7e9 main: change to ignore PortReset failures 2022-07-25 14:04:14 +02:00
sago35 3047d8f321 samd51: improve TRNG 2022-07-22 09:27:43 +02:00
deadprogram 13ed58950f machine/usb/midi: add NoteOn, NoteOff, and SendCC methods for more complete API
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-07-21 11:05:53 +02:00
sago35 5271bd8cfa xiao-ble: add support for flash-1200-bps-reset 2022-07-21 08:31:28 +02:00
sago35 72137d663b usb: adjust buffer alignment (samd21, samd51, nrf52840) 2022-07-20 08:05:52 +02:00
sago35 740134197e samd51: add support for DAC1 2022-07-18 12:10:06 +02:00
Ayke van Laethem 610e7fd16a boards: Add MCH2022 badge
I haven't fully tested this badge because I don't have the physical
hardware but I have followed the pinout from the website.
2022-07-16 08:31:22 +02:00
Dan Kegel 69a6718b38 archFamily(): arm64 is aarch64, not arm; fixes #2985 2022-07-15 17:41:39 +02:00
Ayke van Laethem 7d31d98f0f runtime: rename printuint to printuintptr
This is arguably the correct name, and is consistent with other print
functions.
2022-07-15 15:44:40 +02:00
Ayke van Laethem 0a93347e1c machine: reorder pin definitions to improve pin list on tinygo.org 2022-07-15 14:46:33 +02:00
Ayke van Laethem 411333327e esp32c3: provide hardware pin constants 2022-07-15 14:46:33 +02:00
Ayke van Laethem 159f7ebbc3 esp32: provide hardware pin constants 2022-07-15 14:46:33 +02:00
Ayke van Laethem 153ff09cc5 esp8266: provide hardware pin constants like GPIO2 2022-07-15 14:46:33 +02:00
Ayke van Laethem 57cddf5657 clue: remove pins D21..D28
These pins do not appear in the pinout:
https://learn.adafruit.com/adafruit-clue/pinouts
2022-07-15 14:46:33 +02:00
Ayke van Laethem 6a35719594 avr: fix some apparent mistake in atmega1280/atmega2560 pin constants 2022-07-15 14:46:33 +02:00
Ayke van Laethem 20a46e1b28 nrf51: define and use P0_xx constants
This makes nrf51 consistent with nrf52 and other chips, which do provide
constants for hardware pin numbers.
I've also added the microbit to the smoketest because it is used on
play.tinygo.org. And removed PCA10040 and PCA10056 because they aren't
provided on play.tinygo.org anymore.
2022-07-15 14:46:33 +02:00
sago35 926c02b6ff rp2040: reduced allocations 2022-07-15 09:41:32 +02:00
sago35 f370cd18fc rp2040: add support for EnterBootloader() 2022-07-15 09:41:32 +02:00
sago35 a1d7cab080 rp2040: change volatile access to dpsram 2022-07-15 08:49:07 +02:00
deadprogram 15a9e2313a machine/usb/midi: correct reference to handler function
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-07-14 13:25:34 +02:00
sago35 58f2533f15 rp2040: change default for serial to usb 2022-07-14 09:18:21 +02:00
deadprogram 3c2d2a93d3 machine/usb: refactorings to move functionality under machine/usb package
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-07-14 07:20:50 +02:00
Federico G. Schwindt ea36fea5a9 Add support for printing slices via print/println
With help from @aykevl.
2022-07-13 14:44:23 +02:00
deadprogram 5fdb894760 usb: rename callback to handler to keep consistent
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-07-13 12:11:21 +02:00
sago35 8fed063820 usb: add support for midi 2022-07-12 19:13:12 +02:00
deadprogram 2f843af286 build: run tests on drivers and bluetooth repos after successful docker dev build
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-07-12 17:14:49 +02:00
sago35 7afc47d67a usb: add DTR and RTS to serialer interface 2022-07-12 16:22:16 +02:00
sago35 0bc7c2a61f rp2040: add support for usb (#2973)
* rp2040: add support for usb
2022-07-12 15:41:56 +02:00
sago35 d434058aef samd21,samd51,nrf52840: move usbcdc to machine/usb/cdc (#2972)
* samd21,samd51,nrf52840: move usbcdc to machine/usb/cdc
2022-07-10 11:33:52 +02:00
Ayke van Laethem 56780c2691 ci: build Linux binary in Alpine container
This makes it easier to move the TinyGo compiler between Linux versions
because it doesn't depend on any system libraries anymore. For example,
binaries should be able to run on old Linux versions and on
distributions without glibc (such as Alpine Linux).
2022-07-08 15:05:50 +02:00
Kenneth Bell 1d99b1ed84 boards: add Challenger RP2040 LoRa 2022-07-08 13:01:14 +02:00
Kenneth Bell e1405640da all: git ignore smoketest output 2022-07-08 13:01:14 +02:00
Daniel Esteban 5996e113ad update list of boards supported to add Badger2040 2022-07-08 08:52:44 +02:00
sago35 f1e6997018 atsamd21,atsamd51,nrf52840: improve usb-device initialization 2022-07-07 21:04:41 +02:00
sago35 335a7ad0b7 samd21,samd51,nrf52840: refactor handleStandardSetup and initEndpoint (#2968)
* samd21,samd51,nrf52840: refactor handleStandardSetup and initEndpoint
2022-07-07 16:43:57 +02:00
sago35 17deac116f samd21,samd51,nrf52840: change usbSetup and sendZlp to public 2022-07-07 08:25:02 +02:00
Daniel Esteban b112477e95 Initial support for XIAO RP2040 2022-07-06 22:23:47 +02:00
sago35 2fa24ef752 samd21,samd51,nrf52840: refactor usb initialization 2022-07-06 17:55:25 +02:00
sago35 fcefcb191c samd21,samd51,nrf52840: unify bootloader entry process 2022-07-06 09:14:11 +02:00
sago35 ff7c71c99c serial: use common initialization for serial 2022-07-05 20:53:37 +02:00
sago35 7eaad62568 feather-rp2040,macropad-rp2040: fix qspi-flash settings 2022-07-05 16:37:45 +02:00
sago35 401bd89664 samd21, samd51: move USB-CDC code 2022-07-05 14:41:51 +02:00
Damian Gryski 24b1bfcecd tests/runtime: add benchmarks for runtime memhash 2022-07-05 08:54:55 +02:00
Ayke van Laethem 27162ebe32 cgo: add a check that we don't use different LLVM versions 2022-07-04 14:54:39 +02:00
Ayke van Laethem b347aea450 cgo: fix default LLVM version to LLVM 14
Without extra flags, we would try to use LLVM 13 for cgo and LLVM 14 for
other things since 873412b43a. That isn't
great. So fix this by only using LLVM 14 in the cgo package.
2022-07-04 14:54:39 +02:00
sago35 1766746c60 rp2040: add usb settings 2022-07-04 13:17:54 +02:00
Damian Gryski 07049b87b6 targets: make leveldb runtime hash default for wasi 2022-07-03 19:27:54 +02:00
sago35 f38603530d all: update version for next development iteration 2022-07-02 23:35:14 +02:00
deadprogram b65447c7d5 ci: use bash shell for making release artifacts
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-06-30 23:30:48 +02:00
Ayke van Laethem 0abc909739 ci: disable ccache on Windows 2022-06-30 23:30:48 +02:00
Ayke van Laethem d984b55311 all: update to version 0.24.0 2022-06-29 15:18:33 +02:00
sago35 446fe1f5b3 makefile: add badger2040, thingplus-rp2040 to smoketest 2022-06-29 12:06:23 +02:00
Ayke van Laethem 873412b43a all: use LLVM 14 by default
This also adds support for LLVM 14 from Homebrew on MacOS.
2022-06-28 22:07:45 +02:00
Kenneth Bell 8a5ab5ab12 rp2040: fix gpio interrupts 2022-06-26 12:14:52 +02:00
Ayke van Laethem 77cf60ef30 darwin: print full size information for -size=full
The MachO file format is a bit weird and doesn't store the DWARF debug
information directly in the file. Instead, it has to be looked up in the
original object file. This makes reading the DWARF debug information for
code size usage a bit more difficult. However, it works with this
change.
2022-06-24 13:50:30 +02:00
Ayke van Laethem a4e2e09457 compiler: drop support for macos syscalls via inline assembly
This has always been unsupported on MacOS and has in fact been removed
from upstream Go a few releases ago. So do the same for TinyGo.
Linux seems to be the only supported OS with a stable syscall interface.
2022-06-24 12:51:18 +02:00
Ayke van Laethem 4262f0ff1f compiler: really define runtime.mem* as LLVM intrinsic wrappers
This makes it possible to //go:linkname them from other places, like in
the reflect package. And is in my opinion a much cleaner solution.
2022-06-24 11:10:24 +02:00
Ayke van Laethem 1ceb63d14c compiler: really define runtime/volatile.* functions
This makes them available to deferred calls, among others.
2022-06-24 11:10:24 +02:00
Ayke van Laethem e1052f921c compiler: define atomic intrinsic functions directly
This changes the compiler from treating calls to sync/atomic.* functions
as special calls (emitted directly at the call site) to actually
defining their declarations when there is no Go SSA implementation. And
rely on the inliner to inline these very small functions.
This works a bit better in practice. For example, this makes it possible
to use these functions in deferred function calls.

This commit is a bit large because it also needs to refactor a few
things to make it possible to define such intrinsic functions.
2022-06-24 11:10:24 +02:00
Ayke van Laethem 6dff85c756 ci: fix CI failure due to missing apt-get update 2022-06-23 23:16:09 +02:00
ardnew afae6b3795 board/teensy40: Add I2C support (#1471)
* teensy40: add I2C support
2022-06-22 11:28:50 +02:00
Ayke van Laethem 2825b4fe74 compiler: update tests after adding new wasm features
I don't understand why this wasn't caught in CI. It should have. In any
case, because the llvm-features string was updated, these IR outputs
were updated.
2022-06-22 07:50:40 +02:00
Ayke van Laethem b5c5d95b68 wasm: use newer WebAssembly features
This commit will start to use a few more WebAssembly features, such as
bulk memory operations. This results in a significant code size saving.
How much it saves varies a lot but it's typically around 1300 bytes.

This change is possible by bumping our minimum Node.js version to 14.
The previous LTS version (12) has been marked end of life, so we can
start to depend on features in the current oldest LTS version, which is
version 14. Browsers have been supporting these features for a long time
now, it's just Node.js that prevented us doing this before.
2022-06-21 08:55:42 +02:00
Ayke van Laethem 633fe95187 wasm: update wasi-libc version
This is necessary for the next commit. It also results in a nice wasm
binary size saving of around 300 bytes.
2022-06-21 08:55:42 +02:00
Ayke van Laethem 64d7f1e436 all: run gofmt on all source code
Some source code wasn't part of `FMT_PATHS` so wasn't checked for
correct formatting. This change includes all this source code and
excludes cgo/testdata because it contains files that can't be parsed.
2022-06-19 13:00:44 +02:00
Ayke van Laethem 9af535bf98 avr: add support for recover()
You can see that it works with the following command:

    tinygo run -target=simavr ./testdata/recover.go

This also gets the following tests to pass again:

    go test -run=Build -target=simavr -v

Adding support for AVR was a bit more compliated because it's also
necessary to save and restore the Y register.
2022-06-19 11:51:12 +02:00
Ayke van Laethem 159f0051bb runtime: move *task.DeferFrame here
This is a refactor that makes the next commit simpler. Perhaps it should
have been like this from the beginning but I didn't like all the casts.
2022-06-19 11:51:12 +02:00
Ayke van Laethem 49e22fe678 runtime: load sp and pc inside tinygo_longjmp
This is a small change to make it easier to support architectures that
need to restore more than just the sp and pc registers. In particular,
it is needed for the AVR architecture that needs to restore the frame
pointer (Y register).
2022-06-19 11:51:12 +02:00
Yurii Soldak c119721e3b atmega2560: support UART1-3
+ example for uart
2022-06-18 09:26:12 +02:00
Ayke van Laethem 9294141d70 avr: fix race condition in stack write
If an interrupt happens between the writes to SPL and SPH, the stack
pointer is inconsistent and terrible things will happen. Therefore,
disable interrupts while updating the stack pointer.

Interrupts are restored _before_ the write to SPH. This is safe, because
interrupts are re-enabled with a one cycle delay. The avr-gcc and Clang
compilers do the same thing when they need to update the stack pointer.

It's almost impossible to test for this bug, but it should make firmware
just a little bit more reliable.
2022-06-17 19:17:21 +02:00
Damian Gryski bcf58c0840 runtime: add comments about the hash functions 2022-06-17 08:46:41 +02:00
Damian Gryski 7a61cb1bc3 src/runtime: add leveldb memhash 2022-06-17 08:46:41 +02:00
Damian Gryski 11e1b2148f src/runtime: switch to stronger hash function
Fixes #2713
2022-06-17 08:46:41 +02:00
Yurii Soldak a4599ba539 build: cancel in-progress builds 2022-06-16 22:26:29 +02:00
Ayke van Laethem 4c64784724 all: Go 1.19 support
This adds early Go 1.19 support. There are a number of things that don't
work yet, but the smoke tests pass so it's at least working for a
significant subset of programs.

This change also switches from CircleCI convenience images to upstream
Go images. This makes it a bit easier to use the latest Go versions.
Also, the convenience images are not updated anymore.
2022-06-16 12:34:56 +02:00
Ayke van Laethem 8d6b210c09 compiler: implement recover() built-in function 2022-06-16 07:59:21 +02:00
Ayke van Laethem 79ba6a50c3 compiler: insert basic blocks at an appropriate location
For example, this commit moves the 'throw' branch of an assertion (nil
check, slice index check, etc) to the end of the function while
inserting the "continue" branch right after the insert location. This
makes the resulting IR easier to follow.

For some reason, this also reduces code size a bit on average. The
TinyGo smoke tests saw a reduction of 0.22%, mainly from WebAssembly.
The drivers repo saw little average change in code size (-0.01%).

This commit also adds a few compiler tests for the defer keyword.
2022-06-16 07:59:21 +02:00
Ayke van Laethem 2fb5174910 compiler: fix basic block context
llvm.AddBasicBlock should never be used. Instead, we should use the
AddBasicBlock method of the current LLVM context.

This didn't lead to any bugs... yet. But probably would, eventually.
2022-06-16 07:59:21 +02:00
Ayke van Laethem b31281a5b6 runtime: scan all writable program segments
Previously we used to scan between _edata and _end. This is not correct:
the .data section starts *before* _edata.

Fixing this would mean changing _edata to _etext, but that didn't quite
work either. It appears that there are inaccessible pages between _etext
and _end on ARM. Therefore, a different solution was needed.

What I've implemented is similar to Windows and MacOS: namely, finding
writable segments by parsing the program header of the currently running
program. It's a lot more verbose, but it should be correct on all
architectures. It probably also reduces the globals to scan to those
that _really_ need to be scanned.

This bug didn't result in issues in CI, but did result in a bug in the
recover branch: https://github.com/tinygo-org/tinygo/pull/2331. This
patch fixes this bug.
2022-06-16 07:59:21 +02:00
Dan Kegel 8754f64f3b syscall.Getpagesize(): add test, implement for Linux and Windows 2022-06-12 01:15:42 +02:00
Ayke van Laethem caf405b01d reflect: add Value.UnsafePointer method
This was added in Go 1.18.
2022-06-12 01:08:02 +02:00
Ayke van Laethem bb65c5ce2b compiler: add support for type parameters (aka generics)
...that was surprisingly easy.
2022-06-11 20:41:16 +02:00
Ayke van Laethem 283fed16a5 builder: fix -no-debug linker flags
Show the correct error message when trying to strip debug information.

Also, remove the special case for GOOS=linux that was probably dead
code: it was only reachable on baremetal systems which were already
checked before.
2022-06-11 16:57:25 +02:00
sago35 76bba13963 usbhid: add support for mouse buttons (#2900)
* usbhid: add support for mouse buttons
2022-06-11 16:11:04 +02:00
Dan Kegel ada11090a2 smoketest: add regression test for 'tinygo test ./...', see #2892
tests/testing/recurse has two directories with tests;
"make smoketest" now does "tinygo test ./..." in that directory
and fails if it does not run both directories' tests.
2022-06-11 12:11:08 +02:00
José Carlos Chávez a07287d3c6 fix: fixes tinygo test ./... syntax. 2022-06-11 12:11:08 +02:00
sago35 1b2e764835 samd21,samd51,nrf52840: add support for USBHID (keyboard / mouse) 2022-06-11 09:44:09 +02:00
Nia Waldvogel 2c93a4085c transform (MakeGCStackSlots): do not move the stack chain pop earlier
Previously, the MakeGCStackSlots pass would attempt to pop the stack chain before a tail call.
This resulted in use-after-free bugs when the tail call allocated memory and used a value allocated by its caller.
Instead of trying to move the stack chain pop, remove the tail flag from the call.
2022-06-10 17:25:02 +02:00
sago35 906757603d wioterminal: fix I2C definition 2022-06-08 18:32:08 +02:00
Krzysztof Jagiello 5d16811199 Attach USB DP to the correct pin on Matrix Portal M4 2022-06-03 07:42:19 +02:00
Nia Waldvogel f2e576decf interp: do not unroll loops
This change triggers a revert whenever a basic block runs instructions at runtime twice.
As a result, a loop body with runtime-only instructions will no longer be unrolled.
This should help some extreme cases where loops can be expanded into hundreds or thousands of instructions.
2022-06-02 18:13:56 +02:00
Ayke van Laethem 2d61972475 gc: drop support for 'precise' globals
Precise globals require a whole program optimization pass that is hard
to support when building packages separately. This patch removes support
for these globals by converting the last use (Linux) to use
linker-defined symbols instead.

For details, see: https://github.com/tinygo-org/tinygo/issues/2870
2022-06-01 21:21:30 +02:00
Damian Gryski 5c488e3145 src/runtime: handle nil map write panics 2022-06-01 13:28:22 +02:00
Damian Gryski e45ff9c0e8 src/runtime: add per-map hash seeds 2022-06-01 13:28:22 +02:00
sago35 39805bca45 os, runtime: enable os.Stdin for baremetal target 2022-06-01 07:56:25 +02:00
Ayke van Laethem 97842b367c transform: run OptimizeMaps during package optimizations
This shrinks transform.Optimize() a little bit, working towards the goal
of https://github.com/tinygo-org/tinygo/issues/2870. I ran the smoke
tests and there is no practical downside: one test got smaller (??) and
one had a different .hex hash, but other than that there was no
difference.

This should also make TinyGo a liiitle bit faster but it's probably not
even measurable.
2022-05-30 20:39:42 +02:00
Ayke van Laethem 9246899b30 builder: move some code to transform package
The transform package is the more appropriate location for package-level
optimizations, to match `transform.Optimize` for whole-program
optimizations.
This is just a refactor, to make later changes easier to read.
2022-05-30 20:39:42 +02:00
Ayke van Laethem 04ace4de5f corpus: make non-working packages easy to uncomment
This makes it easier to test for changes, just remove the hash sign in
front of some packages to test them.
2022-05-30 14:21:35 +02:00
Ayke van Laethem 87a4676137 all: add support for the embed package 2022-05-30 10:41:17 +02:00
Ayke van Laethem fd20f63ee3 compiler: move createConst to compilerContext
Move it from *builder to *compilerContext, so that it can be called in
more places. This is necessary to create a string value (for the file
name) in createEmbedGlobal.
2022-05-30 10:41:17 +02:00
Ayke van Laethem 9dd249a431 builder: refactor package compile job
This commit moves the calculation of the package action ID (cache key)
into a separate job. At the moment, this won't have a big effect but
this change is necessary for some future changes I want to make.
2022-05-30 10:41:17 +02:00
Ayke van Laethem 777d3f3ea5 builder: free LLVM objects after use
This reduces the TinyGo memory consumption when running

  make tinygo-test

from 5.8GB to around 2GB on my laptop.
2022-05-30 07:53:28 +02:00
Ayke van Laethem ea3b5dc689 nintendoswitch: scan globals conservatively
This is a step towards #2870, similar to #2867 and #2869.
2022-05-29 21:00:09 +02:00
Olaf Flebbe 3dd502a928 align api for PortMaskSet, PortMaskClear 2022-05-26 21:37:03 +02:00
Ayke van Laethem 48242ba8d6 darwin: scan globals by reading MachO header
This replaces "precise" global scanning in LLVM with conservative
scanning of writable MachO segments. Eventually I'd like to get rid of
the AddGlobalsBitmap pass, and this is one step towards that goal.
2022-05-25 12:51:31 +02:00
Ayke van Laethem 7ea9eff406 interp: implement binary operators in markExternal* functions
This is necessary for the next commit. The next commit would otherwise
cause an issue with the following constant operation:

    i64 add (i64 ptrtoint (%runtime.machHeader* @_mh_execute_header to i64), i64 32)
2022-05-25 12:51:31 +02:00
Ayke van Laethem 80d94115dc interp: improve error handling of markExternal* functions 2022-05-25 12:51:31 +02:00
Ayke van Laethem 9de76fb42e avr: simplify timer-based time
Simplify the interrupt-based timer code in a few ways:

  - Do not recalibrate the timer every 100ms. Instead, rely on the fact
    that the machine package will calbrate the timer if necessary if it
    makes changes to Timer0.
  - Do not configure Timer0 and then set nanosecondsInTick based on that
    value. Instead, use a fixed value.

These two changes together mean that in code that doesn't use PWM,
nanosecondsInTick will be constant which makes the TIMER0_OVF interrupt
handler a lot smaller.

Together this reduces the code size of AVR binaries by about 1200 bytes,
making it pretty close to the pre-timer code size (only about 250 bytes
larger).

It also somehow fixes a problem with
tinygo.org/x/drivers/examples/ws2812 on the Arduino Uno. I'm not quite
sure what was going wrong, but bisecting pointed towards the timer code
(https://github.com/tinygo-org/tinygo/pull/2428) and with this
simplification the bug appears to be gone.
2022-05-25 11:53:30 +02:00
Steven Kabbes 52c61de19f compiler: alignof(func) is 1 pointer, not 2
This ensures that an embedded [0]func() never ends up being larger
than 1 pointer, which is requried by protobuf processing code.
2022-05-25 11:01:00 +02:00
deadprogram f308d7d28c machine/badger2040: support for Badger 2040
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-05-24 15:02:23 +02:00
Ayke van Laethem 7729a36782 windows: use ThinLTO
Switch Windows builds to use ThinLTO. This gets us closer to using
ThinLTO everywhere.
2022-05-23 21:24:14 +02:00
Ayke van Laethem 5404c81ffd windows: scan globals conservatively
Scan globals conservatively by reading writable sections from the PE
header.

I'd like to get rid of needing to precisely scan globals eventually, and
this brings us one step closer. It also avoids a bug with ThinLTO on
Windows.
2022-05-23 21:24:14 +02:00
Dylan Arbour b52310fed2 ci: Add arm64 build 2022-05-23 08:50:38 +02:00
Ayke van Laethem 046070074d darwin: add support for ThinLTO 2022-05-22 23:29:30 +02:00
Ayke van Laethem c23a5b65ef darwin: support -size= flag
This is just basic support. It doesn't add support for reading DWARF,
because that's a bit complicated on MacOS (it isn't stored in the file
itself but separately in the object files). But at least this change
makes it possible to easily print executable sizes by section type like
for other operating systems.
2022-05-22 18:07:57 +02:00
Ayke van Laethem b8e433821a interp: fix some buggy localValue handling
Bug:

 1. fn.locals[v.value] returns 0 (the default value) if v.value is not
    part of the fn.locals map.
 2. locals[fn.locals[v.value]] then returns the first local value, which
    is usually non-nil
 3. This incorrect value is then used as the operand value.

The manifestation of this convoluted bug was
https://github.com/tinygo-org/tinygo/issues/2842. It didn't occur more
often probably because it only seems to happen in practice with inline
assembly.

Fixes https://github.com/tinygo-org/tinygo/issues/2842
2022-05-22 15:08:17 +02:00
Ayke van Laethem dd1a836903 interp: do not try to interpret past task.Pause()
For context, see:
https://github.com/tinygo-org/tinygo/pull/2863#issuecomment-1133875237

Basically, testdata/goroutine.go was doing `time.Sleep()` inside an init
function which broke because doing that from a non-goroutine is not
allowed. However, we never hit this bug because of
https://github.com/tinygo-org/tinygo/issues/2842 (I didn't investigate
exactly why).
2022-05-22 15:08:17 +02:00
Dan Kegel 4ed0936c0e darwin: adjust syscall suffix for arm64 2022-05-20 18:47:30 +02:00
Ayke van Laethem 7a5d4c9537 darwin: add support for arm64 GOARCH (aka Apple Silicon)
This patch adds support for generating GOOS=darwin GOARCH=arm64
binaries. This means that it will become possible to run `go test` on
recent Macs, for example.
2022-05-20 08:35:18 +02:00
Dylan Arbour af6bbaf532 Use release built tinygo in Makefile
Closes #2795
2022-05-19 23:10:48 +02:00
Steven Kabbes 4c7449efe5 compiler: alignof [0]func() = 1
In the go protobuf code, a pattern is used to statically prevent
comparable structs by embedding:

```
type DoNotCompare [0]func()

type message struct {
  DoNotCompare
  data *uint32
}
```

Previously, sizezof(message{}) is 2 words large, but it only needs to be
1 byte.  Making it be 1 byte allows protobufs to compile slightly more
(though not all the way).
2022-05-19 08:02:32 +02:00
Ayke van Laethem 995e815b63 avr: enable testdata/map.go
The test needs a few changes to support low-memory devices but other
than that, it works fine.
2022-05-18 15:20:09 +02:00
Ayke van Laethem 109b5298c4 avr: use compiler-rt
This change adds support for compiler-rt, which supports float64 (unlike
libgcc for AVR). This gets a number of tests to pass that require
float64 support.

We're still using libgcc with this change, but libgcc will probably be
removed eventually once AVR support in compiler-rt is a bit more mature.

I've also pushed a fix for a small regression in our
xtensa_release_14.0.0-patched LLVM branch that has also been merged
upstream. Without it, a floating point comparison against zero always
returns true which is certainly a bug. It is necessary to correctly
print floating point values.
2022-05-18 15:20:09 +02:00
Ayke van Laethem a94e03eff2 avr: get go test -target=simavr to work
This patch changes two things:

 1. It changes the default stack size. Without this change, the
    goroutine.go test doesn't pass (apparently there's some memory
    corruption).
 2. It moves the excluded tests so that they are skipped with a regular
    `-target=simavr`, not just when running all tests (without
    `-target`).
2022-05-18 15:20:09 +02:00
Damian Gryski eb3d6261b4 builder: remove extra formatting verb from error message 2022-05-18 09:06:03 +02:00
deadprogram 15724848f9 build: install scoop without update to avoid bug ScoopInstaller/Scoop #4917
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-05-18 07:42:56 +02:00
Kenneth Bell 8f40b107d9 rp2040: replace sleep 'busy loop' with timer alarm 2022-05-17 12:41:24 +02:00
Ayke van Laethem fa673f0827 Makefile: fix forced rebuild of LLVM
This is a small change that makes sure not to force a rebuild of LLVM
every time.

For example, I might run:

    make llvm-source
    make llvm-build ASSERT=1

And then I might make some temporary changes to LLVM to test out a patch
for example. So I run:

    make llvm-build

...and my whole build cache gets destroyed.

This commit addresses this issue by not forcing a re-run of CMake with
every `make llvm-build` invocation.
2022-05-10 16:40:39 +02:00
Elliott Sales de Andrade e3fe6d8f37 Skip slice-copy test for LLVM < 14
Fixes #2836
2022-05-08 03:32:04 +02:00
Ayke van Laethem 5c23f6fb6c all: remove support for LLVM 11 and LLVM 12
This removes a lot of backwards compatibility cruft and makes it
possible to start using features that need LLVM 13 or newer.
For example:

  * https://github.com/tinygo-org/tinygo/pull/2637
  * https://github.com/tinygo-org/tinygo/pull/2830
2022-05-07 17:15:35 +02:00
Ayke van Laethem 5afb63df60 cgo: refactor
This is a large refactor of the cgo package. It should fix a number of
smaller problems and be a bit more strict (like upstream CGo): it for
example requires every Go file in a package to include the header files
it needs instead of piggybacking on imports in earlier files.

The main benefit is that it should be a bit more maintainable and easier
to add new features in the future (like static functions).

This breaks the tinygo.org/x/bluetooth package, which should be updated
before this change lands.
2022-05-06 17:22:22 +02:00
Dan Kegel 1d2c39c3b9 os: skip TestDirFSPathsValid on WASI to work around #2828 on windows 2022-05-03 05:36:55 +02:00
Dan Kegel 270a2f51fd os: skip TestDirFS on wasi until #2827 is fixed 2022-05-03 05:36:55 +02:00
Dan Kegel e87cd23e87 os: Drop support for go 1.15
1.15 specific files deleted.
1.16 specific files folded carefully into generic files, with goal of reducing diff with upstream.
Follows upstream 1.16 in making PathError etc. be aliases for the same errors in io/fs.

This fixes #2817 and lets us add io/ioutil to "make test-tinygo" on linux and mac.
2022-05-03 05:36:55 +02:00
deadprogram db389ba443 all: update version for next development iteration
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-05-03 04:57:08 +02:00
Ayke van Laethem d1dfa1155c ci: fix Go version in ARM build 2022-05-02 08:27:13 +02:00
Ayke van Laethem cf0b7edc78 all: release v0.23.0 2022-04-28 17:51:09 +02:00
Damian Gryski a32cda7a4c testdata: move map growth test to map.go 2022-04-28 09:14:45 +02:00
Damian Gryski b251ce7b33 src/runtime: return a nil pointer for compiler bugs in hashmap code
We'll still panic if there's a compiler bug, but at least we'll have smaller
code in all the cases where we don't.
2022-04-28 09:14:45 +02:00
Damian Gryski 1abe1203a3 src/runtime: make hashmap calculations more uintptr-size independent 2022-04-28 09:14:45 +02:00
Damian Gryski 8b360ec911 src/runtime: remove extra if check in hashmap set logic 2022-04-28 09:14:45 +02:00
Damian Gryski 93654544b3 src/runtime: prevent overflow when calculating hashmap growth limits 2022-04-28 09:14:45 +02:00
Damian Gryski 050d516264 testdata: add test for mapgrowth logic 2022-04-28 09:14:45 +02:00
Damian Gryski 9a8328fcb7 src/runtime/hashmap: comments for iterator structure 2022-04-28 09:14:45 +02:00
Damian Gryski 6812a4dc04 src/runtime: first darft of map growth code
Fixes #1553
2022-04-28 09:14:45 +02:00
Ayke van Laethem 8568d4f625 esp32: add support for running and debuggin using qemu-esp32 2022-04-28 07:50:03 +02:00
Ayke van Laethem bd56636d58 all: make emulator command a string instead of a []string
This matches the flash-command and is generally a bit easier to work
with.
This commit also prepares for allowing multiple formats to be used in
the emulator command, which is necessary for the esp32.
2022-04-28 07:50:03 +02:00
Ayke van Laethem 4fe3a379a5 ci: add ARM build, cross compiled on an amd64 host
I'm making this so I don't have to build all the releases on my
Raspberry Pi at home, and to make the process more reproducible.
2022-04-27 22:47:53 +02:00
deadprogram fce42fc7fa machine/thingplus: rename to the singular thing as that it the correct name
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-04-26 21:13:17 +02:00
Ayke van Laethem 5d177d1328 runtime: be able to deal with a very small heap
See the comment in the source for details.

Also see the discussion in
https://github.com/tinygo-org/tinygo/pull/2755, which originally
triggered this bug.

Somewhat surprising, this results in a slight code size decrease for ARM
targets of a few bytes.
2022-04-26 17:47:21 +02:00
lincolngill 9eb4a6268a Pico adc input ch support (#2737)
machine/rp2040: ADC changes, including
* Add rp2040 ADC mux channel support. Internal temp sensor reading and fix for incorrect setting of CS.AINSEL reg bits
* Reset ADC ref voltage in InitADC
2022-04-26 11:49:38 +02:00
deadprogram 11a402de95 docs: update list of currently supported boards
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-04-26 07:47:34 +02:00
Dan Kegel cdd9198888 github: also do tinygo-test-wasi-fast on windows 2022-04-25 17:59:39 +02:00
Dan Kegel 6055e6eb23 Makefile: compress/lzw fails on windows wasi, see #2800, not plain windows. 2022-04-25 17:59:39 +02:00
Dan Kegel 9239c61edb TestChdir: avoid cd .., as wasi does not really support it yet. Tiptoes around #2799. 2022-04-25 17:59:39 +02:00
deadprogram 008b373df4 build: use latest Windows hosted runner version
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-04-25 17:15:59 +02:00
deadprogram c387a09f54 build: use Go 1.18.1 for all builds
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-04-25 17:15:59 +02:00
deadprogram 5bb3ca2618 machine/circuitplay-bluefruit: move pin mappings so board can be compiled for WASM use in Playground
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-04-25 11:17:42 +02:00
Yurii Soldak a4ea85b303 xiao-ble: initial support 2022-04-24 14:50:02 +02:00
Olaf Flebbe 27d38a9663 machine/board_thingsplus_rp2040 targets/thingsplus-rp2040: support sparkfun thingsplus rp2040 board 2022-04-24 10:56:52 +02:00
deadprogram ee497a296b docker: update Dockerfile to use Go 1.18
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-04-23 18:42:00 +02:00
Ayke van Laethem 6b31ee1e93 all: update to LLVM 14
Switch over to LLVM 14 for static builds. Keep using LLVM 13 for regular
builds for now.

This uses a branch of the upstream Espressif branch to fix an issue,
see: https://github.com/espressif/llvm-project/pull/59
2022-04-23 08:45:46 +02:00
Ayke van Laethem cad6a57077 compiler: remove support for memory references in AsmFull
Memory references (`*m` in LLVM IR inline assembly) need a pointer type
starting in LLVM 14. This is a bit inconvenient and requires a new API
in the go-llvm package.

Instead of doing that, I'd like to remove support for memory references
from AsmFull (and possibly AsmFull entirely if possible: it's hard to
use correctly).

This breaks tinygo.org/x/drivers/ws2812 for AVR, ARM, and RISC-V which
need to be updated. Probably using CGo.
2022-04-21 15:18:18 +02:00
Ayke van Laethem 52233790cc mimxrt1062: simplify arm.AsmFull to arm.Asm
This means fewer instances of arm.AsmFull, which I'd like to remove
eventually if possible.
2022-04-21 15:18:18 +02:00
Ayke van Laethem 9160f3f16d main: use shared code for both run and test subcommands
This means that we don't need duplicate code to pass parameters to
wasmtime and that the following actually produces verbose output (it
didn't before this commit):

    tinygo test -v -target=cortex-m-qemu math
2022-04-20 08:22:46 +02:00
Dan Kegel 69d7ed5cda os: define ErrDeadlineExceeded; fixes go 1.18 compile error in net/http, #2782 2022-04-19 09:22:27 +02:00
Dan Kegel 111661658b .github: use proper name for Mac OS 11 (10.16 was unofficial; we could also use 10.15) 2022-04-18 22:52:14 +02:00
Dan Kegel 3000b2d15e gofmt src/machine/machine_mimxrt1062_spi.go to please 1.18 2022-04-18 22:52:14 +02:00
Dan Kegel c89f026532 Makefile: tinygo-test: skip compress/flate test on windows for now
Lets us move forward until
https://github.com/tinygo-org/tinygo/issues/2762
is fixed.
2022-04-18 22:52:14 +02:00
Dan Kegel e09b1d06f5 Smoke test 1.15 still until we drop support for it 2022-04-18 22:52:14 +02:00
Dan Kegel 0590ccb260 gofmt exec_posix.go 2022-04-18 22:52:14 +02:00
Dan Kegel fe0acb1670 ci: updated supported go versions from 1.15-1.17 to 1.16-1.18 2022-04-18 22:52:14 +02:00
Ayke van Laethem d58c7d2521 main: add support for command-line parameters to tinygo run
This is made easy by the refactor in the previous commit.
2022-04-16 18:37:03 +02:00
Ayke van Laethem 85f5411d60 main: unify how a given program runs
Refactor the code that runs a binary. With this change, the slightly
duplicated code between `tinygo run` and `TestBuild` is merged into one.
Apart from deduplication (which doesn't even gain much in terms of lines
removed), it makes it much easier to maintain this code. In particular,
passing command line arguments to programs to run now becomes trivial.

A future change might also merge `buildAndRun` and `runPackageTest`,
which currently have some overlap. In particular, flags like `-test.v`
don't need to be special-cased for wasmtime.
2022-04-16 18:37:03 +02:00
ardnew c5de68622e board/teensy40: Add SPI support (#1455)
machine/teensy40: add SPI support
2022-04-16 15:43:52 +02:00
Ayke van Laethem 8fb93fbac4 esp: support CGo
Without this patch, the include directory isn't found and picolibc.h
(used indirectly by stdint.h for example) can't be found.

I would like to add tests for this but we currently don't run Xtensa
tests. This should be possible however using https://github.com/espressif/qemu/wiki
(see also: https://github.com/tinygo-org/tinygo/pull/2780).
2022-04-15 23:28:26 +02:00
Ayke van Laethem ef3b3c0d6a transform: fix poison value in heap-to-stack transform
In https://github.com/tinygo-org/tinygo/issues/2777, a poison value
ended up in `runtime.alloc`. This shouldn't happen, especially not for
well written code. So I'm not sure why it happens. But here is a fix
anyway.
2022-04-15 22:54:25 +02:00
ardnew 2dc46a851b board/teensy40: Add ADC support (#1458)
machine/teensy40: add ADC support
2022-04-13 17:12:31 +02:00
Ron Evans f3afc7bbf3 Revert "fix: flash-command for maixbit board"
This reverts commit b02cea0321.
2022-04-12 17:13:32 +02:00
Elliott Sales de Andrade 4858b27120 Also disable asynchronous unwind tables
These seem to be enabled in LLVM 14, and cause undefined symbol errors.
2022-04-11 14:58:55 +02:00
Elliott Sales de Andrade 7f507a7026 Fix incorrect formatting arguments 2022-04-10 22:58:16 +02:00
Ayke van Laethem 83227e68df all: use compiler-rt from LLVM 2022-04-10 21:03:59 +02:00
sago35 09a3c6a16b flash: add openocd-verify 2022-04-09 17:49:54 +02:00
soypat f613cb41a3 rp2040: fix spurious i2c STOP during write+read transaction 2022-04-09 11:10:36 +02:00
Elias Naur e060e588ab goenv: look for Go version in $GOROOT/src/internal/buildcfg/zbootstrap.go
The old path, $GOROOT/runtime/internal/sys/zversion.go, no longer contains
the Go version.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-04-09 10:11:07 +02:00
Dan Kegel 8dfb317d28 Allow building with go 1.18 2022-04-09 09:16:37 +02:00
Elliott Sales de Andrade 9cedd78d9c Add a shim for internal/fuzz
This simply shadows the real code temporarily to see what else is
broken. It only defines a single type to fix testing/internal/testdeps.
2022-04-09 09:16:37 +02:00
Dan Kegel 20a27746b2 compiler: make RawSyscall an alias for Syscall per suggestion from Ayke. For #2474. 2022-04-08 08:29:30 +02:00
Dan Kegel c78df85015 os: Implement Pipe for darwin, add smoke test.
Evidently when you read from pipes in Go, you have to adjust your slice length to reflect the number of bytes read.
Verified upstream behaves the same way.
2022-04-08 08:29:30 +02:00
Ayke van Laethem c0d257d682 compiler: fix difference in aliases in interface methods
There used to be a difference between `byte` and `uint8` in interface
methods. These are aliases, so they should be treated the same.
This patch introduces a custom serialization format for types,
circumventing the `Type.String()` method that is slightly wrong for our
purposes.

This also fixes an issue with the `any` keyword in Go 1.18, which
suffers from the same problem (but this time actually leads to a crash).
2022-04-07 12:54:17 +02:00
Dan Kegel 7af24c7864 compiler: allow slices of empty structs.
Fixes https://github.com/tinygo-org/tinygo/issues/2749
2022-04-07 12:00:27 +02:00
Dan Kegel 3dc1e403ea runtime: stub {Lock,Unlock}OSThread. Makes 1.18 happier on windows. 2022-04-07 10:27:34 +02:00
sago35 1deee3ec5a m5stamp-c3: add pin setting of UART 2022-04-07 07:16:27 +02:00
Dan Kegel 0f9f316db2 main_test.go: fork testdata/testing.go for go 1.18 2022-04-06 20:03:04 +02:00
Dmitriy 0dd521e1d1 add support for esp32c3 to receive UART data 2022-04-06 19:25:24 +02:00
Ron Evans 1dcdd5f2d2 Revert "src/runtime: first darft of map growth code"
This reverts commit 7e05efa274.
2022-04-05 03:34:01 +02:00
Ron Evans dcd8ee63a8 Revert "src/runtime/hashmap: comments for iterator structure"
This reverts commit 8872229a0b.
2022-04-05 03:34:01 +02:00
Ron Evans b8bf0ac3f1 Revert "testdata: add test for mapgrowth logic"
This reverts commit 73571dd423.
2022-04-05 03:34:01 +02:00
Damian Gryski 73571dd423 testdata: add test for mapgrowth logic 2022-04-04 13:22:19 +02:00
Damian Gryski 8872229a0b src/runtime/hashmap: comments for iterator structure 2022-04-04 13:22:19 +02:00
Damian Gryski 7e05efa274 src/runtime: first darft of map growth code
Fixes #1553
2022-04-04 13:22:19 +02:00
Sai Sasidhar Maddali b02cea0321 fix: flash-command for maixbit board
Latest version of kflash tool requires a --Board/-B argument to
        be able to run the tool
2022-04-04 09:15:39 +02:00
Dan Kegel 8823a934a3 syscall: stub WaitStatus 2022-04-04 07:33:31 +02:00
Dan Kegel 6ac02cc34c syscall: wasi: more complete list of signals
Grepped straight out of the appropriate signal.h, with order preserved.

Makes 1.18 tests happier.

See comment on discrepancy for SIGCHLD.  Since wasi doesn't really support signals, this may not matter.
2022-04-03 19:22:43 +02:00
Dan Kegel e259598b68 syscall: darwin: more complete list of signals
Grepped straight out of the appropriate signal.h, with order and comments preserved verbatim.

Makes 1.18 tests happier.
2022-04-03 19:22:43 +02:00
Elliott Sales de Andrade f159573975 Add reflect.Value.FieldByIndexErr stub 2022-03-24 06:31:02 +01:00
sago35 234234af15 build: add JSON output to build command 2022-03-24 05:51:38 +01:00
Dmitriy 3d68804702 Add board support for ESP32-C3-12f Kit 2022-03-20 07:39:27 +01:00
Dan Kegel 38efca1e2d syscall: stub mmap(), munmap(), MAP_SHARED, PROT_READ, SIGBUS, etc. on nonhosted targets
Makes 1.18 tests a little happier.

Works around this error:

$ make test GOTESTFLAGS="-run TestTest/EmulatedCortexM3/Pass"
...
main_test.go:520: test error: could not compile: /usr/local/go/src/internal/fuzz/sys_posix.go:19:18: PROT_READ not declared by package syscall
2022-03-19 21:06:45 +01:00
Aayush Attri 0a75dd82b9 updating the comments for stub funcs 2022-03-19 19:09:20 +01:00
Aayush Attri fbc748f152 removing Version stub 2022-03-19 19:09:20 +01:00
Aayush Attri 881aba1785 add stub for runtime numcgocall, numgoroutine and version 2022-03-19 19:09:20 +01:00
Dan Kegel aa421bf655 compiler.go: createBuiltin: accept alias for slice. Helps 1.18 tests pass.
With proper fix by Ayke.
2022-03-19 19:05:57 +01:00
Dan Kegel 1fb1f08233 syscall: define MAP_SHARED and PROT_READ on wasi
Makes 1.18 tests a little happier.

Not sure mmap works on wasi, so these may be somewhat stubby.
2022-03-19 16:05:23 +01:00
ZauberNerd 0b5d300d94 targets/wasi: remove --export-dynamic linker flag
Exporting symbols seems to embed them in the WASM exports section which
causes wasmtime to fail: https://github.com/bytecodealliance/wasmtime/issues/2587
As a workaround, it is possible to specify the `--allow-unknown-exports`
flag on wasmtime.
But as discussed in the above linked issue, this seems to only be a
workaround. For the Rust compiler the fix was to remove the
`--export-dynamic` linker flag when targeting `wasm32-wasi`:
https://github.com/rust-lang/rust/pull/81255
Which is waht this commit does for Tinygo too.
2022-03-19 15:36:44 +01:00
ZauberNerd 2fdcabdcce src/runtime: add runtime.Version()
This adds the `Version()` function of the `runtime` package which embeds
the go version that was used to build tinygo.

For programs that are compiled with tinygo the version can be overriden
via the:
`tinygo build -ldflags="-X 'runtime.buildVersion=abc'"` flag.
Otherwise it will continue to use the go version with which tinygo was
compiled.
2022-03-19 15:36:44 +01:00
ZauberNerd d066b5c232 Move gitSha1 build time variable from main to goenv package
Moving and exporting this variable from the main to the goenv package
allows us to use it from both the main and the builder package.
This is done in preparation to include the value in `tinygo build`
linker flags, so that we can embed the version and git sha into binaries
built with tinygo.
2022-03-19 15:36:44 +01:00
Elliott Sales de Andrade 836ab95192 Rename reflect.Ptr to reflect.Pointer
This was done in plain Go for 1.18:
https://github.com/golang/go/commit/17910ed4ff5a3cb3dcf4367d4af23ad5a7fe5809
2022-03-18 15:27:28 +01:00
Dan Kegel cf8f4d65f2 Implement getpagesize and munmap. For go 1.18. 2022-03-18 13:44:30 +01:00
Damian Gryski 06b19cde2d interp: prevent an off-by-one during interp debug 2022-03-17 20:06:59 +01:00
Elliott Sales de Andrade 42ae9a665f os: Add some exec.ProcessState stubs 2022-03-17 12:33:59 +01:00
Dan Kegel c55c996c5d gc_leaking.go: don't inline alloc. Fixes #2674. 2022-03-17 11:26:01 +01:00
ZauberNerd 6fb90b6fc4 src/os: Add UserHomeDir() function to os package
This commit adds the `UserHomeDir()` function to the `os` package.
2022-03-16 22:19:05 +01:00
ZauberNerd 6f31712b7d test: write into a temp file and read from its fd
This test creates a new temp file and writes some bytes into it.
It then opens a new file for the file descriptor of the temp file and
tries to read some bytes out of it.
2022-03-16 15:40:04 +01:00
ZauberNerd e295770363 test: simple test to verify os.File.Fd() is working 2022-03-16 15:40:04 +01:00
ZauberNerd 486b99961d src/os: implement os.File.Fd() method
This commits adds a OS-specific `Fd()` function for `file_anyos.go` and
`file_other.go`, which returns a uintptr to the underlying file
descriptor.
2022-03-16 15:40:04 +01:00
Dan Kegel 4a98db4c86 Add regression test for #2666.
I didn't see how to run it easily from main_test.go, though I didn't try too hard.
And it doesn't really have a good place to go in Makefile.
So I added a new target tinygo-baremetal, and invoke it from CI at the end of assert-test-linux.
It only adds 7 seconds to the run, should be ok.
2022-03-15 05:59:00 +01:00
Dan Kegel c534fa1b6f On baremetal platforms, use simpler test matcher. Fixes #2666.
Uses same matcher in testdata (because now we can't replace it in testdata).
2022-03-15 05:59:00 +01:00
deadprogram eed78338e6 build: trigger builds of dev branches of repos in TinyGo ecosystem, e.g. Bluetooth, TinyFS, TinyFont, TinyDraw
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-03-14 20:44:43 +01:00
Elliott Sales de Andrade 5141638cbf Fix type of Signal constants on WASI 2022-03-13 12:53:23 +01:00
Elliott Sales de Andrade 5d4f795aec Add an empty os.Process.Signal implementation
This fixes compile of tests in Go 1.18, due to its use in
`src/internal/testenv/testenv.go`.
2022-03-13 12:53:23 +01:00
Elliott Sales de Andrade db8603e378 Add os Signal aliases
These are used in Go 1.18's `testing/internal/testdeps`. Though the
comment says they should exist _everywhere_, there is still a build
constraint, but that seems to be fine.
2022-03-13 12:53:23 +01:00
Elliott Sales de Andrade bc098da93f Implement all of os.Signal in arch-specific syscall
This is basically copied from `syscall_js.go` from the Go standard
library, since the existing parts were from there as well.
2022-03-13 12:53:23 +01:00
Ayke van Laethem e49e93f22c main: calculate default output path if -o is not specified
This matches the Go command and is generally convenient to have.
2022-03-13 01:08:20 +01:00
Ayke van Laethem 7d4bf09b1a builder: use correct permission bits when creating a library
Previously, the wrong permission bits were emitted by
`tinygo build-library`. This commit fixes that, by `chmod`'ing to
reasonable default permission bits.
2022-03-12 23:20:38 +01:00
Ayke van Laethem 320f21524e cgo: slightly improve error messages
Updating them to libclang-13-dev was a good change, but we can go even
further:

  * The suggestion didn't apply to MacOS.
  * The suggestion would need to be updated with every LLVM release,
    which is a maintenance burden.
  * The suggestion is wrong when compiling with `-tags=llvm12` for
    example to choose a different LLVM version.

Therefore, link to the build documentation instead.
2022-03-12 21:17:29 +01:00
Dan Kegel 4117055611 Makefile: chmod before fpm. For #2685 2022-03-12 17:24:16 +01:00
Ayke van Laethem 603fff78d4 all: add support for ThinLTO
ThinLTO optimizes across LLVM modules at link time. This means that
optimizations (such as inlining and const-propagation) are possible
between C and Go. This makes this change especially useful for CGo, but
not just for CGo. By doing some optimizations at link time, the linker
can discard some unused functions and this leads to a size reduction on
average. It does increase code size in some cases, but that's true for
most optimizations.

I've excluded a number of targets for now (wasm, avr, xtensa, windows,
macos). They can probably be supported with some more work, but that
should be done in separate PRs.

Overall, this change results in an average 3.24% size reduction over all
the tinygo.org/x/drivers smoke tests.

TODO: this commit runs part of the pass pipeline twice. We should set
the PrepareForThinLTO flag in the PassManagerBuilder for even further
reduced code size (0.7%) and improved compilation speed.
2022-03-12 12:55:38 +01:00
Ayke van Laethem d4b1467e4c build: support machine outlining pass in stacksize calculation
The machine outliner introduces a few new opcodes that weren't
previously emitted by LLVM. We need to support these.

This doesn't trigger very often, but it sometimes does. It triggers a
lot more often with ThinLTO enabled.
2022-03-12 12:55:38 +01:00
ZauberNerd 4cf8ad2bee Update libclang installation comment to libclang-13-dev
Tinygo bumped the default llvm version to v13 in:
tinygo-org/tinygo@3a4e0c9
2022-03-12 09:31:18 +01:00
sago35 96c60f9692 atsamd51: allow faster frequency setting when using SPI 2022-03-12 08:45:38 +01:00
Elliott Sales de Andrade 99ce46669b Fix LLVM build constraints 2022-03-11 07:51:44 +01:00
sago35 a1b4eafa07 samd21,samd51: fix usbcdc initialization when -serial=uart (#2631)
machine/samd21,samd51: fix usbcdc initialization when -serial=uart by using machine.USB.Configured()
2022-03-10 12:32:19 +01:00
deadprogram ccbe03795a build/windows: use fork with updated permissions for new scoop 2022-03-10 09:13:33 +01:00
ZauberNerd 3f69c32a55 src/os: export correct values for os.DevNull for each OS
This commit introduces `os.DevNull` exports for all supported OS
targets.
2022-03-08 14:49:14 +01:00
Dmitriy b176494e44 add support for GPIO interrupts on esp32c3
Update interrupt_esp32c3.go:
make callHandler inline
save and restore MSTATUS along with MEPC
save and restore actual threshold value and call fence
print additional data during exception
2022-03-08 09:13:15 +01:00
ZauberNerd 0243a5b8be src/os: add stubs for exec.ExitError and ProcessState.ExitCode
This commit adds stubs for the `ExitError` struct of the `exec` package
and `ProcessState.ExitCode()` of the `os` package.

Since the `os/exec` is listed as unsupported, stubbing these methods
and structs should be enough to get programs that use these to compile.
2022-03-08 06:45:53 +01:00
ZauberNerd 1fac41d535 src/runtime: add stub for runtime.NumCPU()
This adds a stub for the `NumCPU()` function from the `runtime`
package.
This change allows code to compile that tries to access this function.

I guess for most hardware boards and WASM setting this value to `1` is
fine. And as far as I can see it shouldn't break or change existing
applications, because the function previously did not exist at all.
2022-03-07 21:03:38 +01:00
ZauberNerd 1472fb6032 src/runtime: add stub for debug.ReadBuildInfo()
This adds the necessary structs and the `ReadBuildInfo()` function to
the runtime/debug module to allow to compile code that tries to access
it.
The stub itself returns ok=false, so that calling code should not try
to read from the nil pointer that is returned instead of the actual
BuildInfo struct.
2022-03-07 20:03:51 +01:00
Samuel Stauffer 0fd3d785a3 syscall/js: allow copyBytesTo(Go|JS) to use Uint8ClampedArray
From https://github.com/golang/go/commit/f0e8b81aa34120e21642c569912bde00ccd33393

Fixes https://github.com/tinygo-org/tinygo/issues/1941
2022-03-07 19:01:55 +01:00
Ayke van Laethem b9c0aa77bf runtime: implement memhash
This function is used by the hash/maphash package.

Unfortunately, I couldn't get the hash/maphash package to pass tests
because it's too slow. I think it hits the quadratic complexity of the
current map implementation.
2022-03-06 10:13:04 +01:00
Ayke van Laethem 4c28f1b875 runtime: add fastrand
This is needed for hash/maphash support.
2022-03-06 10:13:04 +01:00
Dan Kegel 0791603c86 Makefile: add report-stdlib-tests-pass 2022-03-05 22:22:22 +01:00
Damian Gryski 095312fa3f src/syscall: document Environ() single-allocation tradeoff 2022-03-04 15:26:47 +01:00
Damian Gryski 7e647a5e81 src/runtime: use memzero for leaking collector 2022-03-04 01:35:22 +01:00
Ayke van Laethem 29c1d7c68d compiler: fix incorrect unsafe.Alignof on some 32-bit architectures
This should fix https://github.com/tinygo-org/tinygo/issues/2643
2022-03-04 00:04:17 +01:00
Dan Kegel ecb7eebcff Makefile: add compress/lzw, debug/dwarf, debug/plan9obj, and net to list of tests 2022-03-02 18:25:16 +01:00
Elliott Sales de Andrade a680bfbb7a os: Use a uintptr for NewFile
This appears to have been how it is upstream for about 10 years. Using
an interface breaks if a file descriptor number is passed directly to
`NewFile`, e.g., `NewFile(3, "fuzz_in")` as used in Go 1.18 fuzzing
code.
2022-03-01 14:01:40 +01:00
Damian Gryski bf23839931 src/os,src/syscall: move env copy code to syscall.Environ() 2022-03-01 11:44:39 +01:00
Damian Gryski 6b15a72895 src/os: add back TestClearenv
Removed as flaky in #2603
2022-03-01 11:44:39 +01:00
Damian Gryski 08fd49fe60 src/os: make Environ() return a copy of the environment
Fixes #2646
2022-03-01 11:44:39 +01:00
sago35 d65e3deccf Revert "all: move stm32 files to separate repository"
This reverts commit 644356c220.
2022-02-28 10:19:26 +01:00
Damian Gryski cbfa85be6a testdata/corpus: add google/go-patchutils 2022-02-24 12:36:10 -05:00
Dan Kegel 6c23f27f73 Makefile: add testing/fstest to tinygo-test where supported 2022-02-24 12:35:40 -05:00
Dan Kegel 31a3a7c84b os: testTempDir: now that we have os.ReadDir, bring back one use of it in a test 2022-02-24 12:35:40 -05:00
Dan Kegel a9a225ba26 testing: nudge type TB closer to upstream; should be a no-op change. 2022-02-24 12:35:40 -05:00
Dan Kegel 58d0499e55 Makefile: add io/fs to tinygo-test where supported
Depends on t.TempDir(), which is why this wasn't enabled earlier.
2022-02-24 12:35:40 -05:00
Dan Kegel b24af78327 testing: implement testing.TempDir
TODO: enable test on windows and wasi once os.Readdir and os.RemoveAll are implemented there
2022-02-24 12:35:40 -05:00
Kyle Conroy b406422277 test: Add text/template smoke test 2022-02-24 12:32:40 -05:00
Kyle Conroy cfed3f0213 fix: Add stubs for more missing reflect methods
With these methods stubbed out, the text/template package can be
imported. These changes also allow code generated by protoc to compile.
2022-02-24 12:32:40 -05:00
Ayke van Laethem d75e14245b test: fix assertion for multiple packages
I see no reason why it isn't possible to run `tinygo test -c` with
multiple packages. It'll just create multiple test outputs. I think the
intended flag was the `-o` flag, which indeed doesn't make much sense
with multiple packages.
2022-02-21 05:53:03 +01:00
Dan Kegel af8244e868 Update macos-minimal-sdk to pick up updated dirent.h 2022-02-21 05:18:27 +01:00
Dan Kegel f962e2fd15 github: also run 'make tinygo-test' on mac 2022-02-21 05:18:27 +01:00
Ayke van Laethem 5746154cc0 all: add -work flag
This flag has the same behavior as in upstream Go. It can be useful
while debugging certain issues.
2022-02-20 16:35:20 +01:00
Dan Kegel e9d9ae8781 os: disable TestClearenv for now, it is very flaky. Also reduce verbosity. 2022-02-20 13:46:48 +01:00
BCG 52ffd6aa98 board: Adafruit MacroPad RP2040 2022-02-19 11:52:24 +01:00
Ayke van Laethem 644356c220 all: move stm32 files to separate repository 2022-02-18 23:39:26 +01:00
Dan Kegel 47a622a903 Implement os.RemoveAll()
TODO: enable test on windows once Readdir is implemented there
2022-02-18 04:47:19 +01:00
BCG 4417374b53 board: add definition for Teensy 4.1 (#2618)
* board: add definition for Teensy 4.1
2022-02-13 08:21:03 +01:00
Ayke van Laethem 262291a80a rp2040: fix incorrect inline assembly
The register r0 was used unconditionally. This is a bug: the compiler
doesn't know it is clobbered and might consider it alive across the
inline assembly expression.

The fix is simple. It could probably be optimized, but this should at
least fix the bug.
2022-02-13 07:34:40 +01:00
Ayke van Laethem cdd267fa10 builder: add support for cross compiling to Darwin
This means that it will be possible to generate a Darwin binary on any
platform (Windows, Linux, and MacOS of course), including CGo. Of
course, the resulting binaries can only run on MacOS itself.

The binary links against libSystem.dylib, which is a shared library. The
macos-minimal-sdk repository contains open source header files and
generated symbol stubs so we can generate a stub libSystem.dylib without
copying any closed source code.
2022-02-12 15:33:06 +01:00
Ayke van Laethem 850a5fdbfb loader: only add Clang header path for CGo
It should only be added at the point that it is needed, for example when
using libclang or using the built-in Clang. It isn't needed when running
an external tool.
2022-02-12 15:33:06 +01:00
Damian Gryski 4b2edc9a26 compiler: move allocations > 256 bytes to the heap 2022-02-11 19:46:37 +01:00
sago35 f2fef290c9 machine: add DefaultUART to wioterminal 2022-02-11 07:17:43 +01:00
Elliott Sales de Andrade 010cc13e9e Fix cross-Linux setup on non-amd64 arches
In that case, an emulator is needed for amd64, and tests should be run
for amd64 as a _cross_ test.
2022-02-07 11:05:47 +01:00
Yurii Soldak ac7e370c72 rp2040: i2c minor fixes 2022-02-05 18:18:20 +01:00
Ayke van Laethem 77ec9b6369 all: update build constraints to Go 1.17
Do it all at once in preparation for Go 1.18 support.

To make this commit, I've simply modified the `fmt-check` Makefile
target to rewrite files instead of listing the differences. So this is a
fully mechanical change, it should not have introduced any errors.
2022-02-04 07:49:46 +01:00
Dan Kegel aa8e0bb509 os: isWine: be compatible with older versions of wine, too
Turns out wine 5.x doesn't export WINEUSERNAME.
2022-02-03 19:12:19 +01:00
Ayke van Laethem 372d9e0f5e wasm: remove heap allocator from wasi-libc
This would conflict with our own heap. We previously defined all those
functions to make sure it's not used, but with a more recent wasi-libc
version (https://github.com/WebAssembly/wasi-libc/pull/250) we can
simply not compile the wasi-libc heap, which is the proper fix.
2022-02-03 18:28:02 +01:00
sago35 d139fa5e0f esp32c3: add support for input pin 2022-02-02 18:13:09 +01:00
soypat 367fb9d40e machine/rp2040: whole now correctly set at minimum 1 value for high frequency PWM 2022-02-02 09:52:13 +01:00
Dan Kegel 98a6ed8059 os: add DirFS, which is used by many programs to access readdir.
It's wafer-thin :-)

Includes smoke test from upstream.

TODO: once t.TempDir is implemented, add io/fs to the list of standard library tests to run; that's a better test.
2022-02-02 08:57:49 +01:00
Dan Kegel 641a7e5cb9 os: implement readdir for darwin and linux
readdir is disabled on linux for 386 and arm until syscall.seek is implemented there.

windows is hard, so leaving that for later.

File src/os/dir_other_go115.go can be deleted when we drop support for go 1.15.

Also adds TestReadNonDir, which was helpful while debugging.
2022-02-02 08:57:49 +01:00
Damian Gryski 3fa7d6cc40 src/runtime: assert that a gc block addr isn't inside the metadata 2022-02-01 20:26:35 +01:00
Damian Gryski e497b5c5ba src/runtime: prevent out-of-bounds memory access during b.state() 2022-02-01 20:26:35 +01:00
Damian Gryski 23dc861ddb src/runtime: use garbage collector constants when we have them 2022-02-01 20:26:35 +01:00
Damian Gryski b2ccf12e98 src/runtime: fix location of metadata in comment 2022-02-01 20:26:35 +01:00
Damian Gryski 23479c92d3 src/runtime: improve metadatasize calculation to avoid rounding issues 2022-02-01 20:26:35 +01:00
Yurii Soldak 3458726234 nano-33-ble: typo in LPS22HB peripheral definition and documentation (#2579) 2022-01-29 11:19:15 -05:00
Ayke van Laethem a7a69d38a4 builder: prefer GNU build ID over Go build ID
The GNU build ID covers the Go build ID, and probably some more.
2022-01-27 18:38:40 +01:00
sago35 4210200070 goenv: update version for start of 0.23.0 development cycle 2022-01-27 15:53:53 +01:00
Ayke van Laethem 3883550c44 build: fix build-library subcommand
This subcommand has been broken for a while, since libraries also use
the CPU flag. This commit fixes this.

Previously, libraries were usable for most Cortex-M cores. But with the
addition of the CPU field, I've limited it to three popular cores: the
Cortex-M0 (microbit), Cortex-M0+ (atsamd21), and Cortex-M4 (atsamd21,
nrf52, and many others).

In the future we might consider also building libraries for the current
OS/arch so that libraries like musl are already precompiled.
2022-01-26 00:27:33 +01:00
Ayke van Laethem 5ce072b827 all: release v0.22.0 2022-01-25 23:12:07 +01:00
deadprogram 4029b838ce all: update license year to 2022
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-25 17:13:34 +01:00
Dan Kegel 3fbab2ede3 builder/buildid.go: accept alternate name for buildid section on Linux
On Ubuntu, using standard go, both go and gnu buildid sections are present.
On Alpine, the gnu buildid section is absent, which caused tinygo to abort early.

It is possible that we could hit a situation where only the gnu
buildid section is present, so accept either one just in case.

Fixes https://github.com/tinygo-org/tinygo/issues/2580
2022-01-25 07:26:06 +01:00
Dan Kegel a29e1d43f1 Kludge: provide stub for syscall.seek on 386 and arm, #1906
This replaces an earlier kludge which was at the wrong level
and caused "GOARCH=386 tinygo test os" to fail to compile on linux.

Stubbing just the one missing function, syscall.seek, lets
os tests compile on linux 386, and skipping tests of seek and Fstat
(which has a cryptic dependency on syscall.Seek via time)
lets os tests pass on linux 386.

The stub can be removed once tinygo implements go assembly and picks up the real definition.
2022-01-24 18:23:40 +01:00
Dan Kegel ee663ccb96 Revert "Kludge: work around lack of syscall.seek on 386 and arm, #1906"
This reverts commit 60b483bd3b.
2022-01-24 18:23:40 +01:00
Ayke van Laethem cd867b72b9 interp: don't log from the interp package
We shouldn't be logging anything when not explicitly requested via a
flag or some other way.
2022-01-24 15:01:35 +01:00
Nia Waldvogel 8aa223aed9 main (test): integrate test corpus runner
This allows us to test a large corpus of external packages against the compiler.
2022-01-23 10:22:28 -05:00
Federico G. Schwindt 3a4e0c94e1 Switch default to llvm13 2022-01-23 02:03:27 +01:00
Dmitriy 0a0981a475 Provide Set/Get for each register field described in SVD files
- rename Bitfield to Constant
- add methods to the exiting types to set/get bitfields
- integrate clustered registers
- add cluster size to properly add filler at the end of the structure
- fix structures with leading filler (i.e. for FICR_Type.INFO in nfr9160)
- shorten the function name when prefix and suffix are identical. i.e. GetSTATE_STATE vs GetSTATE
2022-01-21 15:09:08 +01:00
Nia Waldvogel 2f57e4ff6d interp: handle type assertions on nil interfaces
Previously, a type assertion on a nil interface would result in an out-of-bounds operand access, as we assumed it was a ptrtoint.
This would usually result in an undefined value which happens not to have the same name as the asserted type (and therefore the assertion fails as expected).
However, with an LLVM build with asserts, LLVM throws an assertion error:
```
interp.test: /home/niaow/go/src/github.com/tinygo-org/tinygo/llvm-project/llvm/include/llvm/IR/User.h:170: llvm::Value* llvm::User::getOperand(unsigned int) const: Assertion `i < NumUserOperands && "getOperand() out of range!"' failed.
```

This change handles a type code of 0 specially.
2022-01-21 14:49:36 +01:00
deadprogram 5e33dccf1f build: trigger drivers repo build after successful docker dev build
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-21 10:05:29 +01:00
Dan Kegel f4fdf8dce9 Makefile: detected TINYGO now works even if a rule changes directory 2022-01-21 07:39:47 +01:00
Dan Kegel 9c3f9537be os: add stubs for Readlink and File.Seek for baremetal targets, with smoke test.
Test currently enabled on pybadge (chosen at random)

TODO:
- enable test on arduino; currently fails with "interp: ptrtoint integer size..." (#2389)
- enable test on nintendoswitch; currently fails with many missing definitions (#2530)
2022-01-21 07:39:47 +01:00
deadprogram f5b7925047 docs: correct link for building development version of TinyGo
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-20 17:02:33 +01:00
Dmitriy Zakharkin 50401c05e8 move AVR interrupt related code to runtime
move AVR interrupt related code to runtime
address formatting
add volatile to access counters
2022-01-20 15:07:16 +01:00
Dan Kegel 7914a729a5 Makefile: exclude archive/zip from TEST_PACKAGES on windows until ReadAt supported 2022-01-20 11:14:41 +01:00
Dan Kegel 8eedd2b04b Makefile: add archive/zip to TEST_PACKAGES
Except on windows, where it fails because it needs ReadAt, which we don't implement on windows yet.
2022-01-20 11:14:41 +01:00
Dan Kegel 60b483bd3b Kludge: work around lack of syscall.seek on 386 and arm, #1906
Revert this once syscall.seek is implemented
cf. https://github.com/tinygo-org/tinygo/issues/1906
2022-01-20 11:14:41 +01:00
Damian Gryski 322abf6d22 src/{syscall, os}: add File.Stat, with smoke test
This is File.Stat from https://github.com/tinygo-org/tinygo/pull/2371,
plus the windows bits,
plus a smoke test more or less from upstream,
all pulled together and rebased by dkegel-fastly.
2022-01-20 11:14:41 +01:00
Dan Kegel b85cb55aab interpreter.go: double timeout to let a real world project build. Waiting is a bit less frustrating with breadcrumbs. 2022-01-20 10:07:48 +01:00
Federico G. Schwindt 03d83181ca Bump go-llvm to support llvm12 and 13 under macos 2022-01-20 09:29:04 +01:00
Yurii Soldak 31ee1637df nrf: fix stop condition race in i2c 2022-01-20 07:37:47 +01:00
deadprogram b7bcb256d7 docs: add GH Actions badge for Docker build
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-19 22:18:26 +01:00
deadprogram 7516c5d69e build: rename file and cleanup names displayed for Docker dev build
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-19 22:18:26 +01:00
Nia Waldvogel c6ae1c58fc compiler: remove parentHandle from calling convention
This removes the parentHandle argument from the internal calling convention.
It was formerly used to implment coroutines.
Now that coroutines have been removed, it is no longer necessary.
2022-01-19 14:42:02 -05:00
Nia Waldvogel 0c2fefa09b transform: remove switched func lowering
The switched func lowering was mainly necessary for coroutines.
With coroutines removed, this is no longer necessary.
2022-01-19 14:42:02 -05:00
Nia Waldvogel ea2a6b70b2 internal/task: remove coroutines 2022-01-19 14:42:02 -05:00
Ayke van Laethem d054d4d512 loader: respect $GOROOT when running go list
This makes it possible to select the Go version using GOROOT, and works
even if the `go` binary is not in $PATH.
2022-01-19 12:44:07 -05:00
Ayke van Laethem e7e1b755c9 Makefile: use absolute path for llvm-build/bin/* binaries
This un-breaks `make wasi-libc` on my system.
2022-01-19 09:44:30 -05:00
Nia Waldvogel 38cd5b80ec Makefile: fix tool autodetect conversion to absolute path
After the last change, $(abspath x) no longer returned the actual absolute path.
This uses which instead.
2022-01-19 07:40:16 +01:00
Nia Waldvogel 57ff3a5ca0 compiler: predeclare runtime.trackPointer
When a package only uses runtime.trackPointer to create interface packs, the compiler fails to find runtime.trackPointer.
This change predeclares it alongside runtime.alloc and updates the tests to use runtime.trackPointer when the test's target uses it.
2022-01-18 16:27:12 -05:00
Nia Waldvogel ecf7014f7e Makefile: reorganize tool detection
There are now a large number of paths that need to be searched, and this started to get a little bit unwieldy.
Additionally, brew paths were searched unconditionally, resulting in warnings every time the Makefile was run.
This reorganizes the detection paths into a parameterized list of search paths by version, which is appended to on Mac.
This list is then expanded across all versions.
The loop and filtering has been moved into the detect function.

Additionally, a helpful error message is displayed upon use of a missing tool:
Makefile:204: *** failed to locate llvm-blah at any of: llvm-build/bin/llvm-blah llvm-blah-13 llvm-blah-12 llvm-blah-11 llvm-blah.  Stop.
2022-01-18 20:37:29 +01:00
Nia Waldvogel 7c3a22d289 wasmtest: fix resource cleanup and add logging
The chromedp context was not cancelled, so resources may have been leaking.
Additionally this waits for the browser to start before the timer starts, and extends the timeout to 20 seconds.
Logging from chromedp has also been enabled, which may help identify possible issues?
2022-01-18 19:29:29 +01:00
Dan Kegel 2c7ea98ccf runtime: add stubs for Func.FileLine and Frame.PC
With this, 'tinygo test' in github.com/pkg/errors at least compiles and passes a few tests:

    $ git clone github.com/pkg/errors
    $ cd errors
    $ tinygo test -c
    $ for a in $(go test -list Test | grep Test); do ./errors.test -test.run $a -test.v  > $a.log 2>&1; done
    $ grep -l PASS *.log | wc -l
      19
    $ grep -l FAIL *.log | wc -l
      11

For https://github.com/tinygo-org/tinygo/issues/2445
2022-01-18 14:38:13 +01:00
Dan Kegel 57b8f7e667 os: implement os.Symlink and os.Readlink 2022-01-18 12:36:33 +01:00
Dan Kegel db0efc52c7 os: implement os.ExpandEnv 2022-01-18 10:12:40 +01:00
Dan Kegel 94b075e423 .github: test-linux-build: install wasmtime, make tinygo-test-wasi-fast 2022-01-18 08:18:13 +01:00
Dan Kegel ce5d52870f Makefile: tinygo-test: move slow tests to end, add -fast target to skip them 2022-01-18 08:18:13 +01:00
Dan Kegel dd6adcacb6 testing: --run now allows filtering of subtests
Also fix typo in error message in sub_test.go from upstream,
and move a few members from B to common where they belonged.

Note that testdata/testing.go seems to be pushing the edge of what
the emulated cortex-m3 target can handle; using regexp in that test
causes it to fail on that target with an out of memory error.

TODO: once tinygo supports runtime.Goexit, consider just using upstream's testing directory...
2022-01-17 21:54:20 +01:00
Dan Kegel 610a20c4d5 testing.go: hoist runTests() out of Run() to match upstream a bit better
Only trivial functional changes:
- gets rid of mistaken extra "no tests" warning (whoops)
- matches upstream's exit code better

In preparation for switching to fancy test filtering.
2022-01-17 21:54:20 +01:00
Pure White daf5d0b63a fix: makefile on macOS (#2535)
* fix: makefile on macOS
2022-01-17 19:32:36 +01:00
Damian Gryski 233f5c6af2 main: replace {root} for compiler tests too 2022-01-17 18:15:09 +01:00
Damian Gryski ca2f25ed48 compileopts: move {root} replacement to compileopts.Emulator() 2022-01-17 18:15:09 +01:00
Yurii Soldak cc1a95a489 nrf: fix race in i2c 2022-01-17 16:19:16 +01:00
Nia Waldvogel 431e223803 main (test): skip AVR tests
The AVR tests fail inconsistently now due to non-deterministic backend bugs.
This disables them until this can be understood and fixed.
2022-01-16 22:02:30 +01:00
deadprogram 1b46324456 testL update chromedp to v0.7.6 for stability
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-16 15:23:37 -05:00
Nia Waldvogel 751ac85488 ci (Windows/Mac): use binaryen from scoop/brew
The scoop and brew package managers now bundle up-to-date copies of binaryen.
As a result, there is no longer a strong need for us to build and package our own copy.
2022-01-15 22:46:20 +01:00
deadprogram 512fb1dae6 docs: update CI badges for GH actions, and correct count of supported boards
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-15 19:03:15 +01:00
Damian Gryski 0d20afa85f Makefile: add compress/flate and compress/zlib to wasi test packages 2022-01-15 17:29:33 +01:00
Damian Gryski c87bb0e9cc pass more --dirs to wasmtime so it can read the entire module tree
This allows compress/flate to pass on -target=wasi out of the box

Fixes #2367
2022-01-15 17:29:33 +01:00
Nia Waldvogel 6afceb5621 os (wasi): fix opening files in read-only mode
On wasi, O_RDWR is a bitwise or of read and write mode.
As a result, the bit test result was incorrect, and rewrote it to read-write mode.
However, the bit tests are not necessary (and upstream Go does not use them).
This passes the flags through directly.
2022-01-15 10:26:19 -05:00
Nia Waldvogel aa053b5fb0 interp: always run atomic and volatile loads/stores at runtime 2022-01-15 14:40:14 +01:00
Dan Kegel 0ed34e3cb0 testing: print duration
TODO: account for time taken in Cleanup().
2022-01-15 10:38:22 +01:00
Dan Kegel 78a36f7724 testing: nudge functions closer to upstream order, to make diffing easier. No functional change. 2022-01-15 10:38:22 +01:00
Nia Waldvogel a743580734 main (test): reorganize runTestWithConfig
This change updates the test runner to use exec.CommandContext for timeout handling.
The timeout has been raised to 1 minute to handle slow machines and (hopefully) Windows.
The test run also now acquires the semaphore to reserve CPU time for the test and (hopefully?????) reduce the number of timeouts in Windows CI.
2022-01-14 14:09:37 -05:00
Nia Waldvogel e2178ce682 compiler: work around AVR atomics bugs
The AVR backend has several critical atomics bugs.
This change invokes libcalls for all atomic operations on AVR.
Now `testdata/atomic.go` compiles and runs correctly.
2022-01-14 13:49:20 +01:00
Elliott Sales de Andrade b2ef7299b7 arm: Explicitly disable unwind tables
Some clang builds (e.g., Fedora's) enable unwind tables by default. As
tinygo does not need nor support them, that leads to undefined symbols
when linking.
2022-01-14 07:34:36 +01:00
Kenneth Bell 14ce531498 stm32: add blues wireless swan 2022-01-13 07:56:08 +01:00
Dan Kegel 21c76c0cb0 testing: benchmarks: implement -benchtime flag 2022-01-12 21:49:27 +01:00
Dan Kegel fbd72a4b2c testing: benchmarks: -bench: allow filtering subbenchmarks
Pull in testing/match.go verbatim from upstream and use it to filter benchmarks.

TODO: also update testing.go to filter tests similarly.
2022-01-12 21:49:27 +01:00
Pure White 93e0636c03 feat: support build on darwin arm64 (#2439)
main: support build on darwin arm64
2022-01-12 12:10:08 +01:00
Dan Kegel ef77b645b9 testing: implement testing.Cleanup
Also reorder and regroup common's fields slightly to match upstream.

TODO: pull in more upstream tests once this package is goroutine-safe
2022-01-12 08:59:09 +01:00
Dan Kegel 0b939f93bc testing: gather duplicate code into tRunner
No change in behavior, just preparing for next commit, and gently nudging code closer to upstream.
2022-01-12 08:59:09 +01:00
Dan Kegel 798085e866 testdata/testing.go: update so it can be run with go 1.16 for comparison 2022-01-12 08:59:09 +01:00
Dan Kegel 69bf6e3c89 interp: show breadcrumbs to help developer find slow init functions; raise timeout. 2022-01-11 22:09:15 +01:00
Elliott Sales de Andrade 8f8d83bffe Run go mod tidy 2022-01-11 16:09:45 +01:00
Dan Kegel 998f01608c os: implement file.Seek, add smoke test 2022-01-11 14:23:14 +01:00
Cameron Eagans 84279ab2ec Add JSON output to info command (#2501)
main: Add json output flag to tinygo info
2022-01-11 13:02:58 +01:00
Dan Kegel a888d6245d testing: replace spaces with underscores in test/benchmark names, as upstream does 2022-01-11 11:53:24 +01:00
Dan Kegel f80efa5b8b testing: support b.SetBytes(); implement sub-benchmarks. 2022-01-11 11:53:24 +01:00
Dan Kegel 29f7ebc63e os: pull in os.Rename and some of its tests from upstream
Skip part of the test on Windows because of https://github.com/tinygo-org/tinygo/issues/2480

TODO: fix 2480 and unskip test
TODO: pull in rest of upstream tests, fix problems they find

Requested in https://github.com/tinygo-org/tinygo/issues/2109
2022-01-11 09:58:38 +01:00
deadprogram 72e15af1fa ci: use GH action to perform build for macos
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-01-10 22:50:52 +01:00
sago35 6cb604c752 board: add M5Stamp C3 2022-01-10 11:10:06 +01:00
Nia Waldvogel cb01d4d63e builder (env): update clang header search path to look in /usr/lib
Arch Linux stores the clang executable seperately from its data, so the search based on the executable does not work.
This change searches /usr/lib as a backup.
2022-01-09 18:46:15 +01:00
Nia Waldvogel fe21650010 builder (musl): add -fno-stack-protector
Arch Linux has turned on the stack protector by default.
This causes a crash in libc init because the stack protector uses TLS before it is initialized.
2022-01-09 18:46:15 +01:00
Ayke van Laethem ebd4969cde all: switch to LLVM 13
This adds support for building with `-tags=llvm13` and switches to LLVM
13 for tinygo binaries that are statically linked against LLVM.

Some notes on this commit:

  * Added `-mfloat-abi=soft` to all Cortex-M targets because otherwise
    nrfx would complain that floating point was enabled on Cortex-M0.
    That's not the case, but with `-mfloat-abi=soft` the `__SOFTFP__`
    macro is defined which silences this warning.
    See: https://reviews.llvm.org/D100372
  * Changed from `--sysroot=<root>` to `-nostdlib -isystem <root>` for
    musl because with Clang 13, even with `--sysroot` some system
    libraries are used which we don't want.
  * Changed all `-Xclang -internal-isystem -Xclang` to simply
    `-isystem`, for consistency with the above change. It appears to
    have the same effect.
  * Moved WebAssembly function declarations to the top of the file in
    task_asyncify_wasm.S because (apparently) the assembler has become
    more strict.
2022-01-09 11:04:10 +01:00
Ayke van Laethem 32a7b8cc4e avr: use a stack size of 512 bytes for testing
The goroutine tests are failing with the default 256 byte stack size.
2022-01-09 11:04:10 +01:00
Dan Kegel b4fa658705 .github: asset-test-linux: show cpuinfo for troubleshooting. 2022-01-07 10:39:30 +01:00
Dan Kegel ee4e42ba1f src/testing: support -bench option to run benchmarks matching the given pattern. 2022-01-07 10:39:30 +01:00
Dan Kegel c6678525a9 src/testing/benchmark.go: reorder functions to make diffing against go easier
On the theory that tinygo is tending towards smaller diffs with go...

Also adds placeholder for ReportAllocs(), otherwise zero semantic changes.
2022-01-07 10:39:30 +01:00
Dan Kegel 8d75b58bdf .github: update apt before installing, in case it is stale
Symptom: assert-test-linux failed in https://github.com/tinygo-org/tinygo/runs/4721983373
with following errors:

E: Failed to fetch http://azure.archive.ubuntu.com/ubuntu/pool/main/c/ceph/librados2_15.2.14-0ubuntu0.20.04.1_amd64.deb  404  Not Found [IP: 52.154.174.208 80]
E: Failed to fetch http://azure.archive.ubuntu.com/ubuntu/pool/main/c/ceph/librbd1_15.2.14-0ubuntu0.20.04.1_amd64.deb  404  Not Found [IP: 52.154.174.208 80]
E: Failed to fetch http://azure.archive.ubuntu.com/ubuntu/pool/main/q/qemu/qemu-block-extra_4.2-3ubuntu6.18_amd64.deb  404  Not Found [IP: 52.154.174.208 80]
E: Failed to fetch http://azure.archive.ubuntu.com/ubuntu/pool/main/q/qemu/qemu-system-common_4.2-3ubuntu6.18_amd64.deb  404  Not Found [IP: 52.154.174.208 80]
E: Failed to fetch http://azure.archive.ubuntu.com/ubuntu/pool/main/q/qemu/qemu-system-data_4.2-3ubuntu6.18_all.deb  404  Not Found [IP: 52.154.174.208 80]
E: Failed to fetch http://azure.archive.ubuntu.com/ubuntu/pool/main/q/qemu/qemu-system-arm_4.2-3ubuntu6.18_amd64.deb  404  Not Found [IP: 52.154.174.208 80]
E: Failed to fetch http://azure.archive.ubuntu.com/ubuntu/pool/main/q/qemu/qemu-system-misc_4.2-3ubuntu6.18_amd64.deb  404  Not Found [IP: 52.154.174.208 80]
E: Failed to fetch http://azure.archive.ubuntu.com/ubuntu/pool/universe/q/qemu/qemu-user_4.2-3ubuntu6.18_amd64.deb  404  Not Found [IP: 52.154.174.208 80]
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?

This usually means those packages have been updated and you have to run apt-get update first, as recommended at
https://github.com/actions/virtual-environments/issues/1757
2022-01-06 16:29:53 +01:00
Dan Kegel ec97313239 When running tests under wasmtime, provide a fresh TMPDIR.
Also fix a couple os tests that wrote to current directory to write to os.TempDir() instead.

After this, os tests pass in wasi, so add them to the list run by "make tinygo-test-wasi".
2022-01-04 21:43:38 +01:00
Kenneth Bell e046b23773 stm32l552ze: use supported stlink interface 2022-01-04 20:27:41 +01:00
Kenneth Bell 0099d47002 all: show error if platform has no rng 2022-01-04 20:27:41 +01:00
Kenneth Bell 5c3ad004ab stm32: add more MCUs with h/w RNG 2022-01-04 20:27:41 +01:00
Dan Kegel 61be9189f1 os: add a few upstream tests for Read and ReadAt, fix problems they exposed.
There are more upstream tests to pull in, but this is plenty for today.
2022-01-04 15:45:49 +01:00
Damian Gryski 1e2791b216 src/os: loop in File.ReadAt to handle short reads
This matches what upstream Go does.  This also means len(b) == 0 successfully
reads 0 bytes without any extra logic.  The tests in archive/zip test for this
behaviour.
2022-01-04 15:45:49 +01:00
Nia Waldvogel d86dd642b3 main (test): add tests to tinygo test 2022-01-03 18:59:19 -05:00
Ayke van Laethem 21b89ef327 compiler: fix emission of large object layouts
Large object layouts don't fit in a pointer-sized integer and therefore
need to be stored in a global instead. However, the way the data was
stored in these globals was not correct for buffers that don't have
pointers near the end. This commit fixes this issue by using math/big
FillBytes() instead of Bytes().

This gets the unicode package to compile on AVR.
2022-01-03 21:22:49 +01:00
Ayke van Laethem 39c8711332 compiler: add correct debug location to init instructions
This adds proper debug locations to interp errors. For example, when
trying to use the unicode package on AVR (which currently doesn't work),
the following error is shown with this commit:

    /usr/local/go1.17/src/unicode/casetables.go:13:31: interp: ptrtoint integer size does not equal pointer size

Before this commit, that error was a lot less helpful:

    unicode/<init>:13:31: interp: ptrtoint integer size does not equal pointer size
2022-01-03 17:58:02 +01:00
Nia Waldvogel edc9319e0d main (tinygo test): fail tests on build error
This fixes a bug where build errors (e.g. linker errors) would be ignored by tinygo test.
2022-01-03 10:12:14 -05:00
Ayke van Laethem fcd88356db avr: fix time.Sleep() in init code
In the early days of TinyGo, the idea of `postinit` was to enable
interrupts only after initializers have run. Which kind of makes
sense... except that `time.Sleep` is allowed in init code and
`time.Sleep` requires interrupts to be enabled. Therefore, interrupts
must be enabled while initializers are being run.

This commit simply moves the enabling of interrupts to a point right
before running package initializers. It also removes `runtime.postinit`,
which is not necessary anymore (and was only used on AVR).
2022-01-02 19:41:44 +01:00
Nia e536676a67 main (test): run tests on AVR 2022-01-01 15:58:03 +01:00
Tobias Theel 342c438586 remove multi core support non-goal 2022-01-01 00:17:51 -05:00
sago35 6b7ecf1f52 readme: unify the notation of micros with tinygo.org 2021-12-31 16:44:45 +01:00
Elias Naur bd7ab8ddd5 targets,runtime,machine: add support for the stm32f469-disco board
The LEDs and button work; I haven't tested the SPI and I2C
configuration.
2021-12-31 10:30:48 +00:00
Elias Naur 302e72e84f machine: add PG* and PK* pins
They're used for LEDs on the STM32F469-Discovery board.
2021-12-31 10:30:48 +00:00
Elias Naur 55ca5287fe runtime: separate runtime initialization for STM32F4 boards
The STM32F469 can use the same initialization as the existing STM32F407
with a few frequency tweaks. This change splits the generic
initialization code into a separate runtime_stm32f4.go file, leaving
only the 407 board specific constants in the existing
runtime_stm32f407.go file.

Note that runtime_stm32f405.go initialization seems semantically similar
to the 407, but I don't have enough confidence in merging 405 with 407
in this change.
2021-12-31 10:30:48 +00:00
Elias Naur 11ee0969b6 machine: merge stm32f405/407
They're no longer functionally different.
2021-12-31 10:30:48 +00:00
Elias Naur 81dbbc89d3 machine: make machine_stm32f407.go equivalent to machine_stm32f405.go
The only differences are a more general SPI.getBaudRate and a different
frequency limit in I2C.getFreqRange.

This is a first step towards adding stm32f469 support: a follow-up
merges machine_stm32f407.go and machine_stm32f405.go, another adds
frequency tweaks for stm32f469.
2021-12-31 10:30:48 +00:00
Nia Waldvogel a4f9e5e552 targets (wasi/wasm): raise default stack size to 16 KiB
In some cases, 8 KiB is not enough for both the C stack and the asyncify stack.
This gets the compress/zlib tests to fail without crashing.
2021-12-30 12:20:04 -05:00
Nia Waldvogel f9f2349850 tinygo test: simplify output buffering 2021-12-30 12:03:12 -05:00
Nia Waldvogel f1b15db258 main (tinygo test): reduce memory use when compiling a large number of packages
This change adds an additional semaphore to tinygo test that limits the number of tests being processed simultaneously (in addition to the existing limit on build jobs and runs).
When running a large number of tests, this limits the number of copies of per-test data stored in memory (avoiding an OOM in CI).
2021-12-30 12:03:12 -05:00
Nia Waldvogel 12e314ccc9 main (tinygo test): build and run tests in concurrently 2021-12-30 12:03:12 -05:00
Nia Waldvogel e594dbc133 builder: refactor job runner and use a shared semaphore across build jobs
Switching to a shared semaphore allows multi-build operations (compiler tests, package tests, etc.) to use the expected degree of parallelism efficiently.

While refactoring the job runner, the time complexity was also reduced from O(n^2) to O(n+m) (where n is the number of jobs, and m is the number of dependencies).
2021-12-30 12:03:12 -05:00
Nia Waldvogel bb08a25edc main (test): remove global build lock 2021-12-30 12:03:12 -05:00
sago35 b7b7713526 docker: update Dockerfile for xtensa-esp32-elf-ld 2021-12-30 15:50:43 +01:00
Dmitriy 92150bd1c5 Interrupt based time. Adjust tick cost when timer-0 is reconfigured (the time precision affected when timer-0 reconfigured). Keep all time in nanoseconds.
Interrupt based time. Adjust tick cost every 1 minute and when timer-0 is reconfigured (the time precision affected when timer-0 reconfigured). Keep all time in nanoseconds.
2021-12-30 11:39:28 +01:00
Kenneth Bell d0633f6228 all: go-llvm that defaults to llvm-12 2021-12-29 16:53:25 +01:00
Arsen Musayelyan d46933abf2 Use os.Stat instead of os.ReadDir as that was added in 1.16 2021-12-29 12:05:51 +01:00
Arsen Musayelyan 26625f5a22 Check for /run/media on Linux for non-debian-based distros 2021-12-29 12:05:51 +01:00
Ayke van Laethem 3e109fca5f builder: use build ID as cache key
Instead of storing an increasing version number in relevant packages
(compiler.Version, interp.Version, cgo.Version, ...), read the build ID
from the currently running executable. This has several benefits:

  * All changes relevant to the compiled packages are caught.
  * No need to bump the version for each change to these packages.
    This avoids merge conflicts.
  * During development, `go install` is enough. No need to run
    `tinygo clean` all the time.

Of course, the drawback is that it might be updated a bit more often
than necessary but I think the overall benefit is big.

Regular release users shouldn't see any difference. Because the tinygo
binary stays the same, the cache works well.
2021-12-28 18:29:05 -05:00
Nia Waldvogel 763a86cd8e loader: elminate goroot cache inconsistency
This change breaks the merged goroot creation process into 2 steps:
1. List all overrides
2. Construct a goroot with the specified overrides

Now step 2 is cached using a hash of the results from step 1.
This eliminates cache inconsistency, but means that step 1 needs to be run on every build.
This is relatively acceptable, as step 1 only takes about 3 ms (assuming the directory tree is in the OS filesystem cache).
2021-12-28 18:01:15 -05:00
Nia Waldvogel 13a3c4b155 Makefile: update tool search for LLVM 12 2021-12-28 17:33:22 -05:00
Nia Waldvogel 9fa667ce63 rumtime: implement __sync libcalls as critical sections
This change implements __sync atomic polyfill libcalls by disabling interrupts.
This was previously done in a limited capacity on some targets, but this change uses a go:generate to emit all of the calls on all microcontroller targets.
2021-12-28 22:12:03 +01:00
kenbell 8bd39d2fc2 Merge pull request #2427 from eliasnaur/remove-arrtype
Remove unused arrtype from package runtime
2021-12-28 19:18:35 +00:00
Nia Waldvogel c685e0696a os: add Perm stub on Go 1.15
This adds a stub for Perm on Go 1.15, which allows the OS package to compile again.
2021-12-26 16:04:19 -05:00
Nia Waldvogel 9db8826b3b interp: run goroutine starts and checks at runtime
This change prevents interp from trying to execute goroutine starts or checks.
This fixes a bug where a goroutine started by an init function would run before the init function.
2021-12-24 09:10:21 +01:00
Dan Kegel 0aed62efe4 Makefile: add tinygo-test-wasi; like tinygo-test but with -target wasi 2021-12-24 01:20:59 +01:00
Olivier Fauchon 2b1a72d112 stm32wlx: I2C implementation for gnse,lora-e5,nucleo-wl55jc boards 2021-12-23 23:45:28 +01:00
Elias Naur a6837f05a4 runtime: remove unused arrtype type aliases
The arrtype aliases are used in the machine package.
2021-12-23 22:07:49 +01:00
Dmitriy c35ce761aa Merge duplicate registers into a single record and merge they bitfields. 2021-12-23 15:14:06 +01:00
Dmitriy d2963b153e Add *_Msk for each bit field and avoid duplicate fields in the output file 2021-12-23 15:14:06 +01:00
Nia Waldvogel f9293645af builder: use flock to avoid double-compiles
This change uses flock (when available) to acquire locks for build operations.
This allows multiple tinygo processes to run concurrently without building the same thing twice.
2021-12-23 08:28:08 +01:00
Nia Waldvogel 38305399a3 sync: add tests 2021-12-22 11:02:45 +01:00
deadprogram 8f2082df69 docker: remove only subdirectories (which are updated as submodules) from lib to keep picolibc file in its correct place
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-22 08:06:28 +01:00
deadprogram da8eb521e1 build: update XCode version for CircleCI builds to 11.4.1 due to deprecations
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-21 19:01:19 +01:00
deadprogram dc53a59c49 docker: have to copy build results to GOPATH at the very end of docker build
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-20 13:36:08 -05:00
Nia Waldvogel f21fdd1f76 sync: add a package doc 2021-12-20 13:35:57 -05:00
Nia Waldvogel 5e719b0d3d sync: fix concurrent read-lock on write-locked RWMutex
This bug can be triggered by the following series of events:
A acquires a write lock
B starts waiting for a read lock
C starts waiting for a read lock
A releases the write lock

After this, both B and C are supposed to be resumed as a read-lock is available.
However, with the previous implementation, only C would be resumed immediately.
Other goroutines could immediately acquire the read lock, but B would not be resumed until C released the read lock.
2021-12-20 13:35:57 -05:00
Damian Gryski 9eb13884de compileopts,targets: replace '{root}' in target files 2021-12-20 13:13:32 -05:00
Damian Gryski 85031d6df7 tinygo: set cmd.Dir even when running emulators
This allows compress/bzip2 to pass with -target=wasi

Fixes #2367
2021-12-20 13:13:32 -05:00
Alan Wang 58b44f9f17 Update board_microbit-v2.go 2021-12-18 14:03:19 +01:00
Damian Gryski c0ea21ece7 src/reflect: add test for indirect array indexing 2021-12-18 10:02:36 +01:00
Damian Gryski 81edf577a3 src/reflect: add test for indirect pointer fix 2021-12-18 10:02:36 +01:00
Damian Gryski 484bb8f13d src/reflect: fix stripPrefix comment 2021-12-18 10:02:36 +01:00
Damian Gryski ae1e7731a4 src/reflect: comment out a now-failing test
Keys() is unimplemented, which is required to compare
these two maps.
2021-12-18 10:02:36 +01:00
Damian Gryski 518745ea79 src/reflect: make sure indirect pointers are handled correctly
Fixes #2370
Fixes #2323
2021-12-18 10:02:36 +01:00
Damian Gryski 38b14706e2 internal/task: fix two missed instances of extalloc 2021-12-17 17:36:49 -05:00
Nia Waldvogel 747336f0a9 runtime: remove extalloc
The extalloc collector has been broken for a while, and it doesn't seem reasonable to fix right now.
In addition, after a recent change it no longer compiles.
In the future similar functionality can hopefully be reintroduced, but for now this seems to be the most reasonable option.
2021-12-17 18:15:18 +01:00
Nia Waldvogel e4de7b4957 internal/task: swap stack chain when switching goroutines
This change swaps the stack chain when switching goroutines, ensuring that the chain is maintained consistently.
This is only really currently necessary with asyncify on wasm.
2021-12-17 10:01:11 +01:00
Nia Waldvogel d5c0083085 builder: handle concurrent library header rename
When a library is built concurrently by multiple TinyGo processes, they may sometimes both build the headers.
In that case a directory rename may fail due to conflict.
This change detects and handles the conflict similar to how GOROOT construction does.
2021-12-17 09:33:28 +01:00
Nia Waldvogel e6fbad13c6 runtime (gc): correct scan bounds
This fixes 2 bugs in the GC scan bounds:
1. On AVR, the GC could sometimes read one byte past the end of a block due to the difference between pointer size and alignment.
2. On WASM, the linker does not properly align the marker for the end of the globals section. A manual alignment operation has been added to markGlobals to work around this.
2021-12-17 09:26:44 +01:00
Dan Kegel 62bda8e129 os: os_chmod_test.go: fix copyright 2021-12-16 16:36:53 -05:00
Dan Kegel 51d6ffb3be os: Chmod: don't test on wasi yet, wasi-libc does not yet support it
Lets "tinygo test -target wasi os" compile, if not pass.

For https://github.com/tinygo-org/tinygo/issues/2369
2021-12-16 16:36:53 -05:00
deadprogram 964aa7058a build: use GHA cache and dockerx for docker dev build
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-15 19:26:32 +01:00
deadprogram 0f9d2ac0e4 docker: update Dockerfile for dev build for LLVM 12 changes
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-15 19:26:32 +01:00
deadprogram 5264469cbd machine/stm32wl: unify implementation for RNG for stm32wl with other STM32 processors
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-15 18:33:41 +01:00
Nia Waldvogel c096f35224 runtime: handle negative sleep times
This change fixes the edge case where a negative sleep time is provided.
When this happens, the call now returns immediately (as specified by the docs for time.Sleep).
2021-12-15 17:52:48 +01:00
Dan Kegel 929cd767c1 os/path_windows_test.go: don't fail on Wine, which allows dots for cur dir even in extended length paths 2021-12-15 12:23:28 +01:00
deadprogram e1df2510d4 machine/stm32f4, stm32f7, stm32l4: implement TRNG for randomness
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-15 11:38:40 +01:00
deadprogram 2ebaa9f520 machine/samd51: implement TRNG for randomness
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-14 14:55:19 +01:00
deadprogram 5159eab694 examples: add example to exercise random number generation
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-14 14:55:19 +01:00
Dan Kegel 75dfb26452 os: skip TestMkdirTempBadDir on windows until TestStatBadDir passes 2021-12-14 09:25:27 +01:00
Dan Kegel 971da0bc09 os: implement and test os.MkdirTemp 2021-12-14 09:25:27 +01:00
Dan Kegel 0420842f4d os: skip TestStatBadPath on windows for now
I'm not up enough on how syscall errors work on windows to figure this out yet.
2021-12-14 09:25:27 +01:00
Dan Kegel d30f8b6ed6 os.Stat: returned error on nonexistent path did not satisfy IsNotExist
Add direct test for the problem to make the fix commit clearer.

Noticed while implementing MkdirTemp on mac; the upstream tests for MkdirTemp fail without this.
2021-12-14 09:25:27 +01:00
Dan Kegel 1f6b4a5e7b os_test.go: use CreateTemp now that it is implemented 2021-12-14 09:25:27 +01:00
Dan Kegel 51fc78c100 os: implement and smoketest os.Clearenv 2021-12-13 23:05:17 +01:00
Dan Kegel e4f2b9c003 os: implement and smoketest os.Unsetenv 2021-12-13 23:05:17 +01:00
Dan Kegel cff4493ca0 os: implement and smoketest os.Setenv 2021-12-13 23:05:17 +01:00
Olivier Fauchon 93ac7cec0d stm32/stm32wlx: Add support for stm32wl55_cm4
board/stm32: Add support for GNSE (Generic Node Sensor Edition)

 Thanks to @jamestait for his help on GNSE port
2021-12-13 16:02:00 +01:00
Olivier Fauchon b4503c1e37 stm32wl: STM32WL TRNG implementation in crypto/rand 2021-12-11 12:25:08 +01:00
Ayke van Laethem 3e6410f323 interp: work around AVR function pointers in globals
Not sure how to test this, since we don't really have any AVR tests
configured.
2021-12-11 11:24:19 +01:00
Rouven Broszeit 0f69d016a0 Added realloc implementation to GCs
When using the latest wasi-libc I experienced a
panic on an attempt to call realloc. My first attempt to
add it to arch_tinygowasm.go was obviously not good (PR #2194). So here
is another suggestion.
2021-12-10 17:51:08 +01:00
Ayke van Laethem ef8c1a187d transform: allocate the correct amount of bytes in an alloca
When I wrote the code originally, I didn't know about SetAlignment so I
hacked a way around it by allocating [...]uintptr types. However, this
allocates a few too many bytes in some cases.
This commit changes this to only allocate the space that we actually
need.

The code size effect is mixed, but generally positive. The combined
average is reduced by 0.27% with more programs being reduced in size
than are increasing in size.
2021-12-10 10:48:24 +01:00
Federico G. Schwindt 08d0dc0d25 Enable Getwd() in wasi and add tests 2021-12-10 09:50:38 +01:00
Dan Kegel 039186a2a3 src/os/stat.go: get build tags right, maybe
Should fix https://github.com/tinygo-org/tinygo/issues/2354

Untested with wasi
2021-12-09 22:14:29 +01:00
Damian Gryski d6c892fe7b src/runtime: fix nil map dereference
Operations on nil maps are accepted and shouldn't
panic. The base hashmapGet/hashmapDelete handled
nil-maps correctly, but the hashmapBinary versions
could segfault accessing the nil map while trying
to hash the key.

Fixes #2341
2021-12-09 18:23:49 +01:00
Federico G. Schwindt cfe6b9765f Test net.Buffers{} 2021-12-09 14:35:52 +01:00
Federico G. Schwindt 539495ef45 Add net.Buffers
Should fix https://github.com/mailru/easyjson/issues/335, for the
most part.
2021-12-09 14:35:52 +01:00
Ayke van Laethem b13c993565 compiler: fix ranging over maps with particular map types
Some map keys are hard to compare, such as floats. They are stored as if
the map keys are of interface type instead of the key type itself. This
makes working with them in the runtime package easier: they are compared
as regular interfaces.

Iterating over maps didn't care about this special case though. It just
returns the key, value pair as it is stored in the map. This is buggy,
and this commit fixes this bug.
2021-12-09 00:14:20 +01:00
Ayke van Laethem 449bfe04f3 compiler: move *ssa.Next lowering for maps to compiler/map.go
This moves it to the most logical place, as a preparation to fixing a
bug in the next commit.
2021-12-09 00:14:20 +01:00
Damian Gryski 1903cf23c9 src/runtime: improve float/complex hashing
This allows positive and negative zero to hash to the same value,
as required by Go.

This is not perfect, but the best I could do without
revamping all the hash funtions to take a seed.

Fixes #2356
2021-12-08 22:38:22 +01:00
deadprogram 9734f349a3 net/interface: use internal implementation for itoa.Uitoa
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-08 14:43:45 +01:00
soypat d87ff838eb net: add bare Interface implementation 2021-12-08 12:34:08 +01:00
Damian Gryski a360c82b40 src/runtime: strengthen hash function for structs and arrays
Using `|` to combine hash values will slowly turn every bit on.
Hashes combined with `^` with keep more entropy.
2021-12-08 10:33:35 +01:00
deadprogram 4a2faeb2c5 machine/stm32f103: initial implementation on ADC interface
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-07 20:12:23 +01:00
deadprogram 99f00d396d machine/bluepill: add definitions for ADC pins
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-07 20:12:23 +01:00
deadprogram 049c5ed3b1 machine/stm32f4: initial implementation for ADC interface
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-07 20:12:23 +01:00
deadprogram cce02cd046 machine/stm32f4disco: add definitions for ADC pins
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-12-07 20:12:23 +01:00
Dan Kegel be7bbba4ca os: implement and smoketest os.Chmod 2021-12-07 10:54:02 +01:00
Dan Kegel e668c8c1a7 os: implement and smoketest os.Chdir 2021-12-07 10:54:02 +01:00
Dan Kegel d62c9696fb os_unix_test.go: rename to os_anyos_test.go, add windows build tag
Also remove now-unsupported freebsd build tag.
2021-12-06 21:56:41 +01:00
Damian Gryski 343146f35c src/testing: stub b.RunParallel() and PB.Next() 2021-12-06 20:09:36 +01:00
sago35 0285171484 main: improve help 2021-12-03 16:14:41 +01:00
Dan Kegel 1a22d92217 os: remove as-yet unused function splitPath 2021-12-03 09:38:40 +01:00
Dan Kegel 8416bb61d8 os: implement MkdirAll 2021-12-03 09:38:40 +01:00
Damian Gryski 85ad157f3f src/os: fix build tags for non-windows PathSeparator 2021-12-01 18:39:37 +01:00
Dan Kegel b123ffcea4 os: implement CreateTemp
Until tinygo implements fastrand(), use a placeholder RNG here.
2021-12-01 12:53:04 +01:00
Dan Kegel ec9fd3fb38 os, syscall: implement Stat and Lstat
File.Stat is left as a stub for now.

Tests are a bit stubbed down because os.ReadDir, os.Symlink, and t.TempDir are not yet (fully) implemented.
TODO: reimport tests from upstream as those materialize.
2021-12-01 00:23:23 +01:00
Ayke van Laethem 5127b9d65b all: add LLVM 12 support
Originally based on a PR by @QuLogic, but extended a lot to get all
tests to pass.
2021-11-30 21:53:16 +01:00
Ayke van Laethem 74b20ca234 runtime: use LLVM intrinsic to read the stack pointer
This should result in smaller code.
2021-11-30 10:01:44 +01:00
Ayke van Laethem 3d73ee77d3 machine: add Device constant
This field contains the microcontroller name that we're compiling for,
or "generic" if we're not running on a microcontroller.
2021-11-30 00:47:11 +01:00
Dan Kegel 6b0f2cd697 os: TempDir(): obey TMPDIR on unix, TMP on win, etc
Uses upstream go code, lightly adjusted.

Adds smoke test.
2021-11-30 00:10:09 +01:00
Dan Kegel e354a3523b os.Remove: avoid double-wrapping err; fixes TODO in test 2021-11-29 20:49:28 +01:00
Dan Kegel f79f6b0e62 os, syscall: implement ReadAt for unix
Windows will take more work, so test is skipped there.
2021-11-29 20:13:29 +01:00
Damian Gryski 47db50b273 os: add a stub for File.Truncate 2021-11-26 18:53:27 +01:00
Olivier Fauchon b0fce80b50 Improvements for stm32wle targets :
- board/stm32: Add STM32 Nucleo WL55JC board
- stm32/stm32wl: Set 48Mhz HSE32/PLL as default Clock, SPI implementation
2021-11-26 14:15:11 +01:00
Ayke van Laethem 718746dd21 os: stub out support for some more features
This is necessary for the following:

  - to make sure os/exec can be imported
  - to make sure internal/testenv can be imported

The internal/testenv package (which imports os/exec) is used by a lot of
tests. By adding support for it, more tests can be run.

This commit adds a bunch of new packages that now pass all tests.
2021-11-26 08:05:35 +01:00
Kenneth Bell 6cbaed75c8 stm32: fix timeout for i2c comms
ticks changed to 16ns causing timeouts to be very, very short.  This change updates timeouts for 16ns ticks.
2021-11-26 00:38:00 +01:00
Kenneth Bell a6200920f7 stm32: pull-up on I2C lines
fixes #2310
2021-11-24 23:57:46 +01:00
Ayke van Laethem 79467baf12 all: remove FreeBSD support
FreeBSD support has been broken for a long time, probably since
https://github.com/tinygo-org/tinygo/pull/1860 (merged in May). Nobody
has complained yet, so I am going to assume nobody uses it.

This doesn't remove support for FreeBSD entirely: the code necessary to
build TinyGo on FreeBSD is still there. It just removes the code
necessary to build binaries targetting FreeBSD. But again, it could very
well be broken as we don't test it.

If anybody wants to re-enable support for FreeBSD, they would be welcome
to do that. But I think it would at the very least need a smoke test of
some sort.
2021-11-24 22:21:22 +01:00
Ayke van Laethem c31aef06ba cgo: add support for C.CString and related functions 2021-11-24 21:09:29 +01:00
Ayke van Laethem 6bd18af5ef cgo: simplify construction of in-memory AST
Instead of writing the entire AST by hand, write it in Go code and parse
it to create the base AST to build upon.
2021-11-24 21:09:29 +01:00
Ayke van Laethem 1789570f52 cgo: add //go: pragmas to generated functions and globals
This patch adds //go: pragmas directly to declared functions and
globals found during CGo processing. This simplifies the logic in the
compiler: it no longer has to consider special "C." prefixed function
names. It also makes the cgo pass more flexible in the pragmas it emits
for functions and global variables.
2021-11-24 21:09:29 +01:00
Damian Gryski a536ddcda8 tinygo: support -run for tests
Fixes #2294
2021-11-24 17:27:11 +01:00
Damian Gryski 18242bc26a runtime: allow comparing interfaces in reflectValueEqual() 2021-11-24 14:17:47 +01:00
Ayke van Laethem 18f4ffd656 ci: move Linux release builds to GitHub Actions 2021-11-24 13:00:15 +01:00
Ayke van Laethem 7238c0a16f ci: cache Go cache for faster build times 2021-11-22 19:43:03 +01:00
Ayke van Laethem c177e4dbc0 ci: move assert-test-linux to GitHub Actions 2021-11-21 12:17:34 +01:00
Ayke van Laethem 1d2c17753a tests: improve wasm tests slightly
These wasm tests weren't passing in GitHub Actions and also weren't
passing on my laptop. I'm not sure why, I think there are a few race
conditions that are going on.

This commit attempts to fix this at least to a degree:

  - The context deadline is increased from 5 seconds to 10 seconds.
  - The tests are not running in parallel anymore.
  - Some `Sleep` calls were removed, they do not appear to be necessary
    (and if they were, sleeping is the wrong solution to solve race
    conditions).

Overall the tests are taking a few seconds more, but on the other hand
they seem to be passing more reliable. At least for me, on my laptop
(and hopefully also in CI).
2021-11-21 12:17:34 +01:00
Kenneth Bell 470cbd5f53 housekeeping: wasm optional in smoketest and fix make clean 2021-11-20 13:30:50 -05:00
Kenneth Bell 62d4a6a77f stm32: add minimal stm32wlex5 / lorae5 target
credit to ofauchon
2021-11-20 12:07:11 +01:00
Dan Kegel 339301b709 os: Implement and smoke test Mkdir() and Remove() 2021-11-20 10:39:27 +01:00
Dan Kegel aea4f57a2b syscall: hoist cstring() out of two functions to reduce repetition and allocations 2021-11-20 10:39:27 +01:00
sago35 2a17a3e56c board: add M5Stack 2021-11-20 09:37:24 +01:00
Ayke van Laethem 34011c4800 targets: change LLVM features to match vanilla Clang
I mistakenly believed the difference was in LLVM version 11.0.0 vs LLVM
11.1.0. However, the difference is in whether we use the Debian version
of Clang.

The Debian version has had lots of patches. I'm not sure which is to
blame, but it could be this one:
https://salsa.debian.org/pkg-llvm-team/llvm-toolchain/-/blob/snapshot/debian/patches/clang-arm-default-vfp3-on-armv7a.patch
2021-11-20 02:48:23 +01:00
Damian Gryski f8206b9bcc syscall: fix array size for mmap slice creation 2021-11-20 00:43:24 +01:00
Ayke van Laethem b01ce95cb5 ci: run stdlib tests on macos 2021-11-20 00:43:24 +01:00
Ayke van Laethem 0658e4896f syscall: add support for Mmap and Mprotect
This is necessary to run crypto/sha1 tests.
2021-11-20 00:43:24 +01:00
Damian Gryski 9d87d658ba testing: add a stub for CoverMode
This allows the strings package test to compile.
2021-11-20 00:36:42 +01:00
Ayke van Laethem ec95d3560f ci: fix Binaryen cache on Windows
The wrong path was used to cache binaryen, so it wasn't actually getting
cached. Therefore, wasm-opt was rebuilt on every new PR (slowing down
the "Build TinyGo release tarball" a lot).
2021-11-19 14:46:20 -05:00
Ayke van Laethem bf076aed61 ci: only build wasm-opt, don't build other Binaryen tools 2021-11-19 14:46:20 -05:00
Ayke van Laethem dee5602e56 builder: fix off-by-one in size calculation
> There are two hard things in computer science: cache invalidation,
> naming things, and off-by-one errors.

Because of this bug, sometimes the last object in a section might not be
attributed correctly to a source location.
2021-11-19 12:14:32 +01:00
Ayke van Laethem 4ef340f228 windows: add support for the -size= flag
Like WebAssembly, it misses information on strings and other anonymous
symbols. However, most code (.text) is covered.
2021-11-19 00:21:21 +01:00
Damian Gryski 843a7ac445 add asyncify to scheduler flag help 2021-11-18 18:09:48 -05:00
deadprogram 8ed7d197a7 docs: update CONTRIBUTING links to point to web site. Also replace Azure build badge with Windows build on GH Actions.
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-11-18 17:49:13 -05:00
Nia Waldvogel 39ce7111bd goenv: update version for start of 0.22.0 development cycle 2021-11-18 23:19:48 +01:00
Ayke van Laethem 06df31944c all: release v0.21.0 2021-11-18 14:20:59 +01:00
Damian Gryski 3ba8bc92cd testdata: update binop.go for string comparison tests 2021-11-18 11:07:45 +01:00
Damian Gryski 0e7a129de7 compiler: update testdata/string.ll
$ go test ./compiler -update
2021-11-18 11:07:45 +01:00
Damian Gryski aeddcd9c5f compiler: fix string compare functions
Before:
	x < x false
	x <= x true
	x == x true
	x >= x false
	x > x true

After:
	x < x false
	x <= x true
	x == x true
	x >= x true
	x > x false
2021-11-18 11:07:45 +01:00
Patricio Whittingslow bf0b05e32c machine/rp2040: refactor PWM code. fix Period calculation 2021-11-18 10:22:26 +01:00
Damian Gryski 348a02d697 src/runtime/debug: stub debug.Stack() 2021-11-17 19:25:52 +01:00
Damian Gryski 7273a2b5fd src/testing stub AllocsPerRun 2021-11-17 19:25:52 +01:00
Damian Gryski 44bb381220 src/runtime/debug: add SetMaxStack to allow compress/flate tests to build 2021-11-17 19:25:52 +01:00
Damian Gryski 2e6b92fc56 src/testing: add testing.Verbose() 2021-11-17 19:25:52 +01:00
Ayke van Laethem 51290e5842 wasm: support -scheduler=none
Previously, -scheduler=none wasn't possible for WASM targets:

    $ tinygo run -target=wasm -scheduler=none ./testdata/stdlib.go
    src/runtime/runtime_wasm_js.go:34:2: attempted to start a goroutine without a scheduler

With this commit, it works just fine:

    $ tinygo run -target=wasm -scheduler=none ./testdata/stdlib.go
    stdin:  /dev/stdin
    stdout: /dev/stdout
    stderr: /dev/stderr
    pseudorandom number: 1298498081
    strings.IndexByte: 2
    strings.Replace: An-example-string

Supporting `-scheduler=none` has some benefits:

  * it reduces file size a lot compared to having a scheduler
  * it allows JavaScript to call exported functions
2021-11-17 19:03:20 +01:00
Ayke van Laethem 22c35c8e31 ci: move all cross compilation tests to Linux
The idea here is as follows:
  - Run all Linux and cross compilation tests in the asser-test-linux
    job.
  - Only run native tests on MacOS and Windows.

This reduces testing time on MacOS and Windows, which are generally more
expensive in CI. Also, by not duplicating tests in Windows and MacOS we
can reduce overall CI usage a bit.

I've also changed the assert-test-linux job a bit to so that the tests
that are more likely to break and the tests that are only run in
assert-test-linux are run first.
2021-11-17 14:52:32 +01:00
Ayke van Laethem 2081380b5c ci: simplify build-linux job
Split building the release and smoke-testing the release in two, and
don't redo some tests that are already done by assert-test-linux.

Some benefits:
  - Lower overall CI time because tests aren't done multiple times.
  - TinyHCI can run earlier because the build-linux job is finished as
    soon as the build artifact is ready.

It does however have the downside of an extra job, which costs a few
seconds to spin up and a few seconds to push and pull the workspace. But
even with this, overall CI time is down by a few minutes per workflow
run.
2021-11-16 18:43:32 +01:00
Ayke van Laethem 3d0c6dd02d ci: simplify test-linux jobs
Instead of doing lots of repetitive tests in test-llvm11-go115 and
test-llvm11-go116, do those tests only once in assert-test-linux and
only run smoke tests for older Go versions.

Benefits:
  - This should reduce total CI time, because these jobs don't do tests
    that are done elsewere anyway. They only do the minimal work
    necessary to prove that the given Go/LLVM version works.
  - Doing all tests in assert-test-linux hopefully catches bugs that
    might not be found in regular LLVM builds.
2021-11-16 16:23:59 +01:00
Ayke van Laethem 869e917dc6 all: add support for windows/amd64
This uses Mingw-w64, which seems to be the de facto standard for porting
Unixy programs to Windows.
2021-11-16 11:08:30 +01:00
Ayke van Laethem 41bcad9c19 runtime: only use CRLF on baremetal systems
We should only do this on baremetal systems, not on Linux, macOS, and
Windows. In fact, Windows will convert LF into CRLF in its putchar
function.
2021-11-16 11:08:30 +01:00
Ayke van Laethem 73ab44c178 builder: support -size= flag on the esp32
This fixes a small mistake when calculating binary size for an Xtensa
file. Previously it would exit with the following error:

    $ tinygo build -o test.elf -size=short -target=esp32-mini32 examples/serial
    panic: runtime error: index out of range [65521] with length 18

Now it runs as expected:

    $ tinygo build -o test.elf -size=short -target=esp32-mini32 examples/serial
       code    data     bss |   flash     ram
       2897       0    4136 |    2897    4136
2021-11-16 07:42:58 +01:00
Dan Kegel b70b6076e3 net/ip, syscall/errno: Reduce code duplication by switching to internal/itoa.
internal/itoa wasn't around back in go 1.12 days when tinygo's syscall/errno.go was written.
It was only added as of go 1.17 ( https://github.com/golang/go/commit/061a6903a232cb868780b )
so we have to have an internal copy for now.
The internal copy should be deleted when tinygo drops support for go 1.16.

FWIW, the new version seems nicer.
It uses no allocations when converting 0,
and although the optimizer might make this moot, uses
a multiplication x 10 instead of a mod operation.
2021-11-16 02:13:52 +01:00
sago35 7b41d92198 device: add build tag for go1.17 2021-11-16 02:10:03 +01:00
Ayke van Laethem 2f4f3bd1ba wasi: restore support for -scheduler=none
The assembly symbols were not marked as hidden and so were exported,
leading to unreferenced symbols.

Example error message:

    Error: failed to run main module `/tmp/tinygo3961039405/main`

    Caused by:
        0: failed to instantiate "/tmp/tinygo3961039405/main"
        1: unknown import: `asyncify::stop_rewind` has not been defined

This commit fixes this issue.
2021-11-15 22:17:40 +01:00
Ayke van Laethem 7cb44fb373 all: add support for GOARM
This environment variable can be set to 5, 6, or 7 and controls which
ARM version (ARMv5, ARMv6, ARMv7) is used when compiling for GOARCH=arm.

I have picked the default value ARMv6, which I believe is supported on
most common single board computers including all Raspberry Pis. The
difference in code size is pretty big.

We could even go further and support ARMv4 if anybody is interested. It
should be pretty simple to add this if needed.
2021-11-15 11:53:44 +01:00
Ayke van Laethem 73ad825b67 ci: update Windows runner to windows-2019
The windows-2016 runner will soon be removed:
https://github.blog/changelog/2021-10-19-github-actions-the-windows-2016-runner-image-will-be-removed-from-github-hosted-runners-on-march-15-2022/
Therefore, switch to the next version.
2021-11-14 13:18:54 +01:00
Nia Waldvogel 539e1324c8 fix binaryen build in docker
Oops I forgot to install cmake and ninja.
2021-11-14 10:49:28 +01:00
Nia Waldvogel 641dcd7c16 internal/task: use asyncify on webassembly
This change implements a new "scheduler" for WebAssembly using binaryen's asyncify transform.
This is more reliable than the current "coroutines" transform, and works with non-Go code in the call stack.

runtime (js/wasm): handle scheduler nesting

If WASM calls into JS which calls back into WASM, it is possible for the scheduler to nest.
The event from the callback must be handled immediately, so the task cannot simply be deferred to the outer scheduler.
This creates a minimal scheduler loop which is used to handle such nesting.
2021-11-14 10:49:28 +01:00
Yurii Soldak 523d1f28cf nano-33-ble: internal i2c config, power led and sensors switch 2021-11-13 12:46:54 +01:00
Damian Gryski 782c57cc11 pass testing arguments to wasmtime 2021-11-13 12:01:20 +01:00
Ayke van Laethem c1d697f868 compiler: fix indices into strings and arrays
This PR fixes two bugs at once:

 1. Indices were incorrectly extended to a bigger type. Specifically,
    unsigned integers were sign extended and signed integers were zero
    extended. This commit swaps them around.
 2. The getelementptr instruction was given the raw index, even if it
    was a uint8 for example. However, getelementptr assumes the indices
    are signed, and therefore an index of uint8(200) was interpreted as
    an index of int8(-56).
2021-11-13 11:04:24 +01:00
Ayke van Laethem 335fb71d2f reflect: add support for DeepEqual
The implementation has been mostly copied from the Go reference
implementation with some small changes to fit TinyGo.

Source: https://github.com/golang/go/blob/77a11c05d6a6f766c75f804ea9b8796f9a9f85a3/src/reflect/deepequal.go

In addition, this commit also contains the following:

  - A set of tests copied from the Go reflect package.
  - An increased stack size for the riscv-qemu and hifive1-qemu targets
    (because they otherwise fail to run the tests). Because these
    targets are only used for testing, this seems fine to me.
2021-11-12 21:27:27 +01:00
Ayke van Laethem 5866a47e77 reflect: fix Value.Index() in a specific case
In the case where:

 - Value.Index() was called on an array
 - that array was bigger than a pointer
 - the element type fits in a pointer
 - the 'indirect' flag isn't set

the Value.Index() method would still (incorrectly) load the value.
This commit fixes that.

The next commit adds a test which would have triggered this bug so works
as a regression test.
2021-11-12 21:27:27 +01:00
Ayke van Laethem 823c9c25cf reflect: implement Value.Elem() for interface values 2021-11-12 21:27:27 +01:00
Ayke van Laethem d15e32fb89 reflect: don't construct an interface-in-interface value
v.Interaface() could construct an interface in interface value if v was
of type interface. This is not correct, and doesn't follow upstream Go
behavior. Instead, it should return the interface value itself.
2021-11-12 21:27:27 +01:00
soypat b534dd67e0 machine/rp2040: add interrupt API 2021-11-12 10:38:02 +01:00
Ayke van Laethem 6c02b4956c interp: fix reverting of extractvalue/insertvalue with multiple indices 2021-11-11 10:36:22 +01:00
Ayke van Laethem 1681ed02d3 interp: take care of constant globals
Constant globals can't have been modified, even if a pointer is passed
externally. Therefore, don't treat it as such in hasExternalStore.

In addition, it doesn't make sense to update values of constant globals
after the interp pass is finished. So don't do this.

TODO: track whether objects are actually modified and only update the
globals if this is the case.
2021-11-11 08:59:32 +01:00
Ayke van Laethem 7e68980c39 ci: improve caching for GitHub Actions
Previously the cache would be stale for every new branch.
With this change, PRs use the cache from the base branch and therefore
don't need to rebuild LLVM from scratch.
2021-11-10 18:55:17 +01:00
Ayke van Laethem cf640290a3 compiler: add "target-cpu" and "target-features" attributes
This matches Clang, and with that, it adds support for inlining between
Go and C because LLVM only allows inlining if the "target-cpu" and
"target-features" string attributes match.

For example, take a look at the following code:

    // int add(int a, int b) {
    //   return a + b;
    // }
    import "C"

    func main() {
        println(C.add(3, 5))
    }

The 'add' function is not inlined into the main function before this
commit, but after it, it can be inlined and trivially be optimized to
`println(8)`.
2021-11-10 11:16:13 +01:00
Ayke van Laethem 78fec3719f all: add target-features string to all targets
This makes sure that the LLVM target features match the one generated by
Clang:

  - This fixes a bug introduced when setting the target CPU for all
    targets: Cortex-M4 would now start using floating point operations
    while they were disabled in C.
  - This will make it possible in the future to inline C functions in Go
    and vice versa. This will need some more work though.

There is a code size impact. Cortex-M4 targets are increased slightly in
binary size while Cortex-M0 targets tend to be reduced a little bit.
Other than that, there is little impact.
2021-11-07 09:26:46 +01:00
Ayke van Laethem af4d0fe191 compileopts: fix reversed append in the target file
With this fix, `cflags` in the target JSON files is correctly ordered.
Previously, the cflags of a parent JSON file would come after the ones
in the child JSON file, which makes it hard to override properties in
the child JSON file.

Specifically, this fixes the case where targets/riscv32.json sets
`-march=rv32imac` and targets/esp32c3.json wants to override this using
`-march=rv32imc` but can't do this because its `-march` comes before the
riscv32.json one.
2021-11-07 09:26:46 +01:00
Ayke van Laethem 7caf0732fa transform: add debug info in interface lowering pass
This is fake debug info. It doesn't point to a source location because
there is no source location. However, it helps to correctly attribute
code size usage to particular packages.

I've also updated builder/sizes.go with some debugging helpers.
2021-11-06 10:50:55 +01:00
Ayke van Laethem edcece33ca transform: refactor interrupt lowering
Instead of doing everything in the interrupt lowering pass, generate
some more code in gen-device to declare interrupt handler functions and
do some work in the compiler so that interrupt lowering becomes a lot
simpler.

This has several benefits:

  - Overall code is smaller, in particular the interrupt lowering pass.
  - The code should be a bit less "magical" and instead a bit easier to
    read. In particular, instead of having a magic
    runtime.callInterruptHandler (that is fully written by the interrupt
    lowering pass), the runtime calls a generated function like
    device/sifive.InterruptHandler where this switch already exists in
    code.
  - Debug information is improved. This can be helpful during actual
    debugging but is also useful for other uses of DWARF debug
    information.

For an example on debug information improvement, this is what a
backtrace might look like before this commit:

    Breakpoint 1, 0x00000b46 in UART0_IRQHandler ()
    (gdb) bt
    #0  0x00000b46 in UART0_IRQHandler ()
    #1  <signal handler called>
    [..etc]

Notice that the debugger doesn't see the source code location where it
has stopped.

After this commit, breaking at the same line might look like this:

    Breakpoint 1, (*machine.UART).handleInterrupt (arg1=..., uart=<optimized out>) at /home/ayke/src/github.com/tinygo-org/tinygo/src/machine/machine_nrf.go:200
    200			uart.Receive(byte(nrf.UART0.RXD.Get()))
    (gdb) bt
    #0  (*machine.UART).handleInterrupt (arg1=..., uart=<optimized out>) at /home/ayke/src/github.com/tinygo-org/tinygo/src/machine/machine_nrf.go:200
    #1  UART0_IRQHandler () at /home/ayke/src/github.com/tinygo-org/tinygo/src/device/nrf/nrf51.go:176
    #2  <signal handler called>
    [..etc]

By now, the debugger sees an actual source location for UART0_IRQHandler
(in the generated file) and an inlined function.
2021-11-06 09:40:15 +01:00
jaap aarts 30bbdd5aeb Make the frequency selection more flexible on stm32f103 2021-11-05 18:11:43 +01:00
jaap aarts 03383760d6 Fix SPI on stm32f103 2021-11-05 18:11:43 +01:00
Ayke van Laethem fce403b7a0 targets: match LLVM triple to the one Clang uses
The target triples have to match mostly to be able to link LLVM modules.
Linking LLVM modules is already possible (the triples already match),
but testing becomes much easier when they match exactly.

For macOS, I picked "macosx10.12.0". That's an old and unsupported
version, but I had to pick _something_. Clang by default uses
"macos10.4.0", which is much older.
2021-11-05 09:42:00 +01:00
Ayke van Laethem fb33f3813d runtime: only initialize os.runtime_args when needed
This generally means that code size is reduced, especially when the os
package is not imported.

Specifically:

  - On Linux (which currently statically links musl), it avoids calling
    malloc, which avoids including the musl C heap for small programs
    saving around 1.6kB.
  - On WASI, it avoids initializing the args slice when the os package
    is not used. This reduces binary size by around 1kB.
2021-11-05 08:50:36 +01:00
Ayke van Laethem 670fcf59d8 linux: reduce binary size in the common case
This commit changes the runtime.putchar implementation to directly call
the `write` system call. This reduces the binary size by around 2.7kB.
2021-11-05 08:50:36 +01:00
Ayke van Laethem cceb655874 cgo: run CGo parser for all CGo fragments in a file
Previously, libclang was run on each fragment (import "C") separately.
However, in regular Go it's possible for later fragments to refer to
types in earlier fragments so they must have been parsed as one.

This commit changes the behavior to run only one C parser invocation for
each Go file.
2021-11-04 22:26:33 +01:00
Damian Gryski 13891d428f os: add File.WriteString and File.WriteAt
WriteString just does the simple and and converts the passed string
to a byte-slice.  This can be made zero-copy later with unsafe, if needed.

WriteAt returns ErrNotImplemented, to match Seek() and ReadAt().

Fixes #2157
2021-11-04 21:47:57 +01:00
Ayke van Laethem 6c9bb96bca wasm: update wasi-libc dependency
The latest version allows overriding the default CFLAGS. By default,
they're `-O2 -DNDEBUG`, thus not including DWARF debug information. This
commit changes this to include the `-g` flag.

Apart from an improved debug experience, this lets -size=full attribute
code to wasi-libc.

Before:

    $ tinygo build -o test.wasm -size=full ./testdata/alias.go
       code  rodata    data     bss |   flash     ram | package
    ------------------------------- | --------------- | -------
       1780       0     188  130733 |    1968  130921 | (unknown)
         84       0       0       0 |      84       0 | internal/task
        281       0       0       0 |     281       0 | main
       2374       0       4     147 |    2378     151 | runtime
    ------------------------------- | --------------- | -------
       4519       0     192  130880 |    4711  131072 | total

After:

    $ tinygo build -o test.wasm -size=full ./testdata/alias.go
       code  rodata    data     bss |   flash     ram | package
    ------------------------------- | --------------- | -------
         40       0     188  130733 |     228  130921 | (unknown)
       1740       0       0       0 |    1740       0 | C wasi-libc
         84       0       0       0 |      84       0 | internal/task
        281       0       0       0 |     281       0 | main
       2374       0       4     147 |    2378     151 | runtime
    ------------------------------- | --------------- | -------
       4519       0     192  130880 |    4711  131072 | total

The main difference here is the `(unknown)` code, which turns out to be
mostly wasi-libc in this trivial example.
2021-11-04 21:10:42 +01:00
Ayke van Laethem 403d93560b builder: build static binaries using musl on Linux
This commit adds support for musl-libc and uses it by default on Linux.
The main benefit of it is that binaries are always statically linked
instead of depending on the host libc, even when using CGo.

Advantages:
  - The resulting binaries are always statically linked.
  - No need for any tools on the host OS, like a compiler, linker, or
    libc in a release build of TinyGo.
  - This also simplifies cross compilation as no cross compiler is
    needed (it's all built into the TinyGo release build).

Disadvantages:
  - Binary size increases by 5-6 kilobytes if -no-debug is used. Binary
    size increases by a much larger margin when debugging symbols are
    included (the default behavior) because musl is built with debugging
    symbols enabled.
  - Musl does things a bit differently than glibc, and some CGo code
    might rely on the glibc behavior.
  - The first build takes a bit longer because musl needs to be built.

As an additional bonus, time is now obtained from the system in a way
that fixes the Y2038 problem because musl has been a bit more agressive
in switching to 64-bit time_t.
2021-11-04 17:15:38 +01:00
Ayke van Laethem b344d65781 builder: reduce number of open files
MacOS X 10.14 has a soft limit of 256 open files by default, at least on
CircleCI. So don't keep object files open while writing the ar file to
reduce the number of open files at once.

Context: the musl libc has more than 256 object files in the .a file.
This resulted in the error "too many open files" on MacOS X 10.14 when
running in CircleCI.
2021-11-04 17:15:38 +01:00
Ayke van Laethem c638f03b3c main: add -p flag to set parallelism
This is very useful for debugging.
2021-11-04 17:15:38 +01:00
Ayke van Laethem 79bdd3f79a picolibc: add include directory to build artefact
This is really just a preparatory commit for musl support. The idea is
to store not just the archive file (.a) but also an include directory.
This is optional for picolibc but required for musl, so the main purpose
of this commit is the refactor needed for this change.
2021-11-04 17:15:38 +01:00
Ayke van Laethem 39ff13fd1a wasm: specify wasi-libc in code, not in the JSON target file
This brings a bit more consistency to libc configuration. It seems
better to me to set the header flags all in the same place, instead of
some in Go code and some in JSON target files (depending on the target).
2021-11-04 17:15:38 +01:00
Ayke van Laethem de6f831983 ci: switch to GitHub Actions for Windows builds
GitHub Actions is faster and much better integrated into GitHub than
Azure Pipelines, and is in general easier to use. Therefore, switch to
GitHub Actions for our Windows builds and tests.
2021-11-04 13:54:21 +01:00
Ayke van Laethem fb6571e405 builder: add support for -size= flag for WebAssembly 2021-11-04 12:34:23 +01:00
Ayke van Laethem 29206cf0a4 targets: add CPU property everywhere
This is for consistency with Clang, which always adds a CPU flag even if
it's not specified in CFLAGS.

This commit also adds some tests to make sure the Clang target-cpu
matches the CPU property in the JSON files.

This does have an effect on the generated binaries. The effect is very
small though: on average just 0.2% increase in binary size, apparently
because Cortex-M3 and Cortex-M4 are compiled a bit differently. However,
when rebased on top of https://github.com/tinygo-org/tinygo/pull/2218
(minsize), the difference drops to -0.1% (a slight decrease on average).
2021-11-03 23:03:44 +01:00
Yurii Soldak c2165f74d8 nano-33-ble: SoftDevice s140v7 support 2021-11-03 20:54:40 +01:00
Ayke van Laethem 02ef64f012 stacksize: hardcode some more frame sizes for __aeabi_* functions
These functions are defined in compiler-rt in assembly and therefore
don't have stack size information. However, they're often called so
these missing functions often inhibit stack size calculation.

Example, before:

    $ tinygo build -o test.elf -target=cortex-m-qemu -print-stacks ./testdata/float.go
    function                         stack usage (in bytes)
    Reset_Handler                    unknown, __aeabi_memclr does not have stack frame information
    runtime.run$1                    unknown, __aeabi_dcmpgt does not have stack frame information

After:

    $ tinygo build -o test.elf -target=cortex-m-qemu -print-stacks ./testdata/float.go
    function                         stack usage (in bytes)
    Reset_Handler                    260
    runtime.run$1                    224
2021-11-03 18:42:16 +01:00
Ayke van Laethem 5792f3a1cf builder: improve accuracy of the -size=full flag
This commit improves accuracy of the -size=full flag in a big way.
Instead of relying on symbol names to figure out by which package
symbols belong, it will instead mostly use DWARF debug information
(specifically, debug line tables and debug information for global
variables) relying on symbols only for some specific things. This is
much more accurate: it also accounts for inlined functions.

For example, here is how it looked previously when compiling a personal
project:

     code  rodata    data     bss |   flash     ram | package
     1902     333       0       0 |    2235       0 | (bootstrap)
       46     256       0       0 |     302       0 | github
        0     454       0       0 |     454       0 | handleHardFault$string
      154      24       4       4 |     182       8 | internal/task
     2498      83       5    2054 |    2586    2059 | machine
        0      16      24     130 |      40     154 | machine$alloc
     1664      32      12       8 |    1708      20 | main
        0       0       0     200 |       0     200 | main$alloc
     2476      79       0      36 |    2555      36 | runtime
      576       0       0       0 |     576       0 | tinygo
     9316    1277      45    2432 |   10638    2477 | (sum)
    11208       -      48    6548 |   11256    6596 | (all)

And here is how it looks now:

     code  rodata    data     bss |   flash     ram | package
  ------------------------------- | --------------- | -------
     1509       0      12      23 |    1521      35 | (unknown)
      660       0       0       0 |     660       0 | C compiler-rt
       58       0       0       0 |      58       0 | C picolibc
        0       0       0    4096 |       0    4096 | C stack
      174       0       0       0 |     174       0 | device/arm
        6       0       0       0 |       6       0 | device/sam
      598     256       0       0 |     854       0 | github.com/aykevl/ledsgo
      320      24       0       4 |     344       4 | internal/task
     1414      99      24    2181 |    1537    2205 | machine
      726     352      12     208 |    1090     220 | main
     3002     542       0      36 |    3544      36 | runtime
      848       0       0       0 |     848       0 | runtime/volatile
       70       0       0       0 |      70       0 | time
      550       0       0       0 |     550       0 | tinygo.org/x/drivers/ws2812
  ------------------------------- | --------------- | -------
     9935    1273      48    6548 |   11256    6596 | total

There are some notable differences:

  * Odd packages like main$alloc and handleHardFault$string are gone,
    instead their code is put in the correct package.
  * C libraries and the stack are now included in the list, they were
    previously part of the (bootstrap) pseudo-package.
  * Unknown bytes are slightly reduced. It should be possible to reduce
    it significantly more in the future: most of it is now caused by
    interface invoke wrappers.
  * Inlined functions are now correctly attributed. For example, the
    runtime/volatile package is normally entirely inlined.
  * There is no difference between (sum) and (all) anymore. A better
    code size algorithm now counts the code/data sizes correctly.
  * And last (but not least) there is a stylistic change: the table now
    looks more like a table. Especially the summary should be clearer
    now.

Future goals:

  * Improve debug information so that the (unknown) pseudo-package is
    reduced in size or even eliminated altogether.
  * Add support for other file formats, most importantly WebAssembly.
  * Perhaps provide a way to expand this report per file, or in a
    machine-readable format like JSON or CSV.
2021-11-03 16:28:04 +01:00
Ayke van Laethem f63c389f1a compiler: change symbol name for string and packed data constants
This new symbol name format (package name + "$string" or "$pack" suffix)
is easier to parse for analysis.
2021-11-03 16:28:04 +01:00
Ayke van Laethem 7c24925aa7 compiler: add minsize attribute for -Oz
This matches the behavior of Clang, which uses optsize for -Os and adds
minsize for -Oz.

The code size change is all over the map, but using a hacked together
size comparison tool I've found that there is a slight reduction in
binary size overall (-1.6% with the tinygo smoke tests and -0.8% for the
drivers smoke test).
2021-11-03 13:40:13 +01:00
Ayke van Laethem d7b7583e83 compiler: refactor when the optsize attribute is set
This commit has a few related changes:

  * It sets the optsize attribute immediately in the compiler instead of
    adding it to each function afterwards in a loop. This seems to me
    like the more appropriate way to do it.
  * It centralizes setting the optsize attribute in the transform
    package, to make later changes easier.
  * It sets the optsize in a few more places: to runtime.initAll and to
    WebAssembly i64 wrappers.

This commit does not affect the binary size of any of the smoke tests,
so should be risk-free.
2021-11-03 13:40:13 +01:00
Ayke van Laethem 1869efe954 interp: use object layout information for LLVM types
This commit will use the memory layout information for heap allocations
added in the previous commit to determine LLVM types, instead of
guessing their types based on the content. This fixes a bug in which
recursive data structures (such as doubly linked lists) would result in
a compiler stack overflow due to infinite recursion.

Not all heap allocations have a memory layout yet, but this can be
incrementally fixed in the future. So far, this commit should fix
(almost?) all cases of this stack overflow issue.
2021-11-02 22:16:15 +01:00
Ayke van Laethem 54dd75f7b3 interp: simplify pointer arithmetic in getLLVMValue
Instead of doing lots of complicated calculations to get the shortest
GEP, I'll just cast it to i8*, do the GEP, and optionally cast to the
requested type.

This currently produces ugly constant expressions, but once LLVM
switches to opaque pointer types all of this shouldn't matter anymore.
2021-11-02 22:16:15 +01:00
Ayke van Laethem 27cbb53538 interp: support const getelementptr with non-zero first offset
This is uncommon, but it does happen if the source pointer is a bitcast
of a global. For example, if a struct is cast to an i8*, it's possible
to index beyond what would appear to be the size of the pointer (i8*).
2021-11-02 22:16:15 +01:00
Ayke van Laethem 0704794def compiler: add object layout information to heap allocations
This commit adds object layout information to new heap allocations. It
is not yet used anywhere: the next commit will make use of it.

Object layout information will eventually be used for a (mostly) precise
garbage collector. This is what the data is made for. However, it is
also useful in the interp package which can work better if it knows the
memory layout and thus the approximate LLVM type of heap-allocated
objects.
2021-11-02 22:16:15 +01:00
Ayke van Laethem f24a93c51d compiler, runtime: add layout parameter to runtime.alloc
This layout parameter is currently always nil and ignored, but will
eventually contain a pointer to a memory layout.

This commit also adds module verification to the transform tests, as I
found out that it didn't (and therefore didn't initially catch all
bugs).
2021-11-02 22:16:15 +01:00
Ayke van Laethem c454568688 loader: fix true path detection on Windows
This is necessary to display error messages on Windows. For example,
this command invocation is not correct (esp32 doesn't define
machine.LED, you need esp32-coreboard-v2 for example):

    tinygo run -target=esp32 examples/blinky1

It results in the following hard-to-read error message:

    # examples/blinky1
    ..\..\..\..\..\AppData\Local\tinygo\goroot-go1.16-24cb853b66a5367bf6d65bc08b2cb665c75bd9971f0be8f8b73f69d1a33e04a1-syscall\src\examples\blinky1\blinky1.go:11:17: LED not declared by package machine

With this commit, this error message becomes much easier to read:

    # examples/blinky1
    C:\Users\Ayke\go\src\github.com\tinygo-org\tinygo\src\examples\blinky1\blinky1.go:11:17: LED not declared by package machine
2021-10-31 19:10:26 +01:00
Nia Waldvogel d46bf2e5e0 transform (interface): fix merge error from #2202 2021-10-31 17:35:58 +01:00
Ayke van Laethem 9e1b4de999 compiler: add support for the go keyword on interface methods
This is a feature that was long missing, but because of the previous
refactor, it is now trivial to implement.
2021-10-31 14:17:25 +01:00
Ayke van Laethem a4afc3b4b0 compiler: simplify interface lowering
This commit simplifies the IR a little bit: instead of calling
pseudo-functions runtime.interfaceImplements and
runtime.interfaceMethod, real declared functions are being called that
are then defined in the interface lowering pass. This should simplify
the interaction between various transformation passes. It also reduces
the number of lines of code, which is generally a good thing.
2021-10-31 14:17:25 +01:00
Ayke van Laethem 90076f9401 all: drop support for LLVM 10 2021-10-31 10:44:17 +01:00
Ayke van Laethem afd49e7cdd compiler: add support for recursive function types
This adds support for a construct like this:

    type foo func(fn foo)

Unfortunately, LLVM cannot create function pointers that look like this.
LLVM only supports named types for structs (not for pointers) and thus
can't add a pointer to a function type of the same type to a parameter
of that function type.

The fix is simple: cast all function pointers to a void function, in
LLVM IR:

    void ()*

Raw function pointers are cast to this type before storing, and cast
back to the regular function type before calling. This means that
function parameters will never refer to its own type because raw
function types are fixed at that one type.

Somehow, this does have an effect on binary size in some cases. The
effect is small and goes both ways. On top of that, there is work
underway in LLVM which would make all pointer types opaque (without a
pointee type). This would make this whole commit useless and therefore
should fix any size increases that might happen.
https://llvm.org/docs/OpaquePointers.html
2021-10-30 15:55:20 +02:00
Ayke van Laethem 4199be9780 ci: increase timeout to 20 minutes 2021-10-28 17:44:51 +02:00
Ayke van Laethem 86f1e6aec4 compiler: properly implement div and rem operations
The division and remainder operations were lowered directly to LLVM IR.
This is wrong however because the Go specification defines exactly what
happens on a divide by zero or signed integer overflow and LLVM IR
itself treats those cases as undefined behavior. Therefore, this commit
implements divide by zero and signed integer overflow according to the
Go specification.

This does have an impact on the generated code, but it is surprisingly
small. I've used the drivers repo to test the code before and after, and
to my surprise most driver smoke tests are not changed at all. Those
that are, have only a small increase in code size. At the same time,
this change makes TinyGo more compliant to the Go specification.
2021-10-28 15:55:02 +02:00
Ayke van Laethem f99c600ad8 transform: work around renamed return type after merging LLVM modules
This fix is very similar to
https://github.com/tinygo-org/tinygo/pull/1768, but now for the return
type. It fixes the issue in
https://github.com/tinygo-org/tinygo/issues/1887.

Like #1768, I'm not sure how to test this as it is very specific to
certain renames that LLVM does and that don't seem very reproducable.
2021-10-28 09:20:08 +02:00
Ayke van Laethem 15d3f5f609 machine: support Pin.Get() function when the pin is configured as output
To my surprise, this is supported on all the devices I could test so
therefore it makes sense to change the API to allow this.
2021-10-28 07:22:19 +02:00
Yurii Soldak c8719f8d14 docker: add picolibc-include directory 2021-10-27 20:49:06 +02:00
Dmitriy Zakharkin e848f47ad4 Fix gen-device-svd to handle 64-bit 2021-10-27 14:52:27 +02:00
Ast-x64 3fe7ab19f6 bump go.bug.st/serial to version 1.1.3
Bump version to 1.1.3 in order to support riscv64 within tinygo.
See https://github.com/bugst/go-serial/pull/100 for more information.
2021-10-27 14:43:38 +02:00
Ayke van Laethem b5d61760f7 transform: remove some dead code
This showed up in the linter and it makes sense to just remove it.
2021-10-26 18:11:58 +02:00
Ayke van Laethem 14bb90c3c0 cgo: add support for stdio in picolibc and wasi-libc
This adds support for stdio in picolibc and fixes wasm_exec.js so that
it can also support C puts. With this, C stdout works on all supported
platforms.
2021-10-26 17:08:30 +02:00
Ayke van Laethem 1645f45c1a esp32c3: use tasks scheduler by default
Now that the tasks scheduler has been implemented for 32-bit RISC-V, it
can be used for the ESP32-C3.
2021-10-26 11:24:41 +02:00
Ayke van Laethem 38b9c55ae6 sam: move I2S0 to machine file
There is no need to put these in the board files as the I2S is the same
on all Microchip SAM D21 chips. This simplifies the code and avoids some
special *_baremetal.go files.

This change does not change the resulting binaries.
2021-10-25 14:49:02 +02:00
Ayke van Laethem 497c74e4a9 sam: simplify SPI peripheral declaration
This has practically no effect on the resulting binaries, the only
difference I could find was for the flash/console/spi driver example.
I'm not sure how to test that one, but I think it's very unlikely that
code will have changed in any meaningful way (apart from reordering some
globals).
2021-10-25 14:49:02 +02:00
Ayke van Laethem ae864bdf0c sam: simplify I2C peripheral declarations
This commit changes the I2C declarations so that the objects are
instantiated in each chip file (e.g. machine_atsamd21e18.go) and used to
define I2C0 (and similar) in the board file (e.g. board_qtpy.go). This
should make it easier to define new board files, and reduces the need
for separate *_baremetal.go files.

I have tested this the following way:

  - With the LIS3DH driver example on the Circuit Playground Express and
    the PyBadge.
  - With the LSM6DS3 driver example on the Arduino Nano 33 IoT.

They both still work fine.
2021-10-25 14:49:02 +02:00
Ayke van Laethem e50885a6f2 sam: simplify definition of SERCOM UART peripherals
Instead of defining them separately for each board, define them once in
the chip definition and later simply use &sercomUART1 etc. to refer to
them. This is simpler and less error-prone.

I found two bugs while working on this:

  - The P1AM-100 board mixed SERCOM 5 and SERCOM 3. It looks like SERCOM
    5 was intended, based on the used pins.
  - The Adafruit Matrix Portal appears to have configured the wrong
    interrupt.

Unfortunately, I can't test these fixes. However, they make it clear
that such a change is important to avoid bugs.

I tested this commit on the PyBadge and the Circuit Playground Express.
2021-10-25 14:49:02 +02:00
Ayke van Laethem 478dd3a28d compiler: add nounwind attribute
This attribute is also set by Clang when it compiles C source files
(unless -fexceptions is set). The advantage is that no unwind tables are
emitted on Linux (and perhaps other systems). It also avoids
__aeabi_unwind_cpp_pr0 on ARM when using the musl libc.
2021-10-25 13:39:54 +02:00
Rouven Broszeit 112b369636 Call __wasm_call_ctors() in wasi init function 2021-10-25 13:12:23 +02:00
Dmitriy 43efe94041 add support for CPU interrupts for ESP32-C3 2021-10-23 03:31:37 +02:00
Ayke van Laethem b5b2600b7b fe310: add support for bit banging drivers
This is necessary to add support for WS2812.
2021-10-21 08:14:34 +02:00
Ayke van Laethem 3f89fa0bee fe310: increase CPU frequency from 16MHz to 320MHz
This chip can run so much faster! Let's update the default frequency.

Also, change the UART implementation to be more fexible regarding the
clock frequency.
2021-10-21 07:13:57 +02:00
Yurii Soldak a5d905f19b rp2040: i2c SetBaudRate spelling 2021-10-21 00:29:16 +02:00
Yurii Soldak d1f1f267a3 rp2040: i2c baud rate handling improvements 2021-10-21 00:29:16 +02:00
sago35 d21ffc63b9 board: add M5Stack Core2 2021-10-20 20:28:47 +02:00
Damian Gryski 90f4b0a266 Makefile: add more TEST_PACKAGES that currently pass 2021-10-16 01:49:25 +02:00
Damian Gryski a88530b785 src/testing: stub B.ReportAllocs()
This allows test packages that use this feature in their benchmarks
to build and run (if not the benchmarks themselves).
2021-10-16 01:49:25 +02:00
Damian Gryski 18aaed63b9 src/runtime: add another set of invalid unicode runes to encodeUTF8() 2021-10-16 01:37:48 +02:00
Damian Gryski a413d5dfe9 rutime/gc_leaking: ensure heapptr is aligned on wasm 2021-10-14 01:56:05 +02:00
Ayke van Laethem 4d5ec6c57b main: use emulator exit code instead of parsing test output
This commit changes `tinygo test` to always look at the exit code of the
running test, instead of looking for a "PASS" string at the end of the
output. This is possible now that the binaries running under
qemu-system-arm or qemu-system-riscv32 will signal the correct exit code
when they exit.

As a side effect, this also makes it possible to avoid the "PASS" line
between successful tests. Before:

    $ tinygo test container/heap container/list
    PASS
    ok  	container/heap	0.001s
    PASS
    ok  	container/list	0.001s

After:

    $ tinygo test container/heap container/list
    ok  	container/heap	0.001s
    ok  	container/list	0.001s

The new behavior is more in line with upstream Go:

    go test container/heap container/list
    ok  	container/heap	0.004s
    ok  	container/list	0.004s
2021-10-06 09:04:06 +02:00
Ayke van Laethem 98f84a497d qemu: signal correct exit code to QEMU
There were a few issues that were causing qemu-system-arm and
qemu-system-riscv to give the wrong exit codes. They are in fact capable
of exiting with 0 or 1 signalled from the running application, but this
functionality wasn't used. This commit changes this in the following
ways:

  * It fixes SemiHosting codes, which were incorrectly written in
    decimal while they should have been written in hexadecimal (oops!).
  * It modifies all the baremetal main functions (aka reset handlers) to
    exit with `exit(0)` instead of `abort()`.
  * It changes `syscall.Exit` to call `exit(code)` instead of `abort()`
    on baremetal targets.
  * It adds these new exit functions where necessary, implemented in a
    way that signals the correct exit status if running under QEMU.

All in all, this means that `tinygo test` doesn't have to look at the
output of a test to determine the outcome. It can simply look at the
exit code.
2021-10-06 09:04:06 +02:00
sago35 00c73d62ad rp2040: add CPUFrequency() 2021-10-05 07:17:36 +02:00
Ayke van Laethem dbfaaf7c13 main: implement tinygo lldb subcommand
LLDB mostly works on most platforms, but it is still lacking in some
features. For example, it doesn't seem to support RISC-V yet (coming in
LLVM 12), it only partially supports AVR (no stacktraces), and it
doesn't seem to support the Ctrl-C keyboard command when running a
binary for another platform (e.g. with GOOS=arm64). However, it does
mostly work, even on baremetal systems.
2021-10-05 06:26:21 +02:00
Ayke van Laethem 878b62bbe8 riscv: switch to tasks-based scheduler
This is only supported for RV32 at the moment. RV64 can be added at a
later time.
2021-10-05 05:52:03 +02:00
Ayke van Laethem 5d8f25a622 hifive1-qemu: increase memory to 64K
Somehow this is accepted by QEMU. I'm doing this so that tests for
-target=hifive1-qemu still work with the RISC-V tasks scheduler (with a
stack size of 2048 bytes).
2021-10-05 05:52:03 +02:00
Ayke van Laethem c7413837aa riscv: align the heap to 16 bytes
This may be expected by the ABI. In particular, it means that stacks
allocated on the heap will be 16-byte aligned.
2021-10-05 05:52:03 +02:00
Federico G. Schwindt b1ec8eb2e0 os: implement Getwd 2021-10-05 00:14:09 +02:00
deadprogram 98fbf7ff25 build: double timeout period without output for make test
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-10-04 23:51:25 +02:00
Ayke van Laethem af00e218a8 riscv: implement 32-bit atomic operations
This is necessary to support the ESP32-C3, which lacks the A (atomic)
extension and thus requires these 32-bit atomic operations.
With this commit, flashing ./testdata/atomic.go to the ESP32-C3 works
correctly and produces the expected output on the serial console.
2021-10-04 21:27:00 +02:00
Ayke van Laethem b31d241388 riscv: use MSTATUS.MIE bit instead of MIE to disable interrupts
This should behave the same but is compatible with the ESP32-C3 which
lacks the MIE CSR (but does have the MSTATUS CSR).
2021-10-04 21:27:00 +02:00
Ayke van Laethem a6246e60f3 main: remove -target flag for LLVM targets
It is better to use environment variables (GOOS and GOARCH) for
consistency instead of providing two slightly incompatible ways. This
-target flag should only be used to specify a .json file (either
directly or in the TinyGo targets directory). Previously it was possible
to specify the LLVM target as well but that was never really fully
supported.

So:

  - To specify a different OS/arch like you would in regular Go, use
    GOOS and GOARCH.
  - To specify a microcontroller chip or board, use the -target flag.

Also remove the old `os.Setenv` which might have had a purpose long ago
but doesn't have a purpose now.
2021-10-04 18:22:55 +02:00
Ayke van Laethem 0a80da46b1 main: test other architectures by specifying a different GOARCH
... instead of setting a special -target= value. This is more robust and
makes sure that the test actually tests different arcitectures as they
would be compiled by TinyGo. As an example, the bug of the bugfix in the
previous commit ("arm: use armv7 instead of thumbv7") would have been
caught if this change was applied earlier.

I've decided to put GOOS/GOARCH in compileopts.Options, as it makes
sense to me to treat them the same way as command line parameters.
2021-10-04 18:22:55 +02:00
Ayke van Laethem 36f1517e8d arm: use armv7 instead of thumbv7
At the moment, thumbv7 is crashing. I'm not exactly sure why, but it
appears that there is an unknown instruction in __aeabi_uldivmod
(probably from libgcc).

I've fixed this by switching to armv7, which is also somewhat modern.
Maybe we can switch back to Thumb2 (aka thumbv7) once we start using
musl and compiler-rt. In the meantime, this does fix a miscompilation
(illegal instruction).
2021-10-04 18:22:55 +02:00
learnforpractice 04040453b4 fix export math functions issue 2021-10-03 16:28:34 +02:00
Ayke van Laethem 2b453db4da esp32c3: add support for GDB debugging
You can now debug the ESP32-C3 from the TinyGo command line, like this:

    tinygo flash -target=esp32c3 examples/serial
    tinygo gdb -target=esp32c3 examples/serial

It's important to flash before running `tinygo gdb`, because loading a
new firmware from GDB has not yet been implemented.

Probably the easiest way to connect to the ESP32-C3 is by using the
built-in JTAG connection. See:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-guides/jtag-debugging/configure-builtin-jtag.html

You will need to make sure that the `openocd` command in your $PATH is
the one from Espressif. Otherwise GDB will hang. You can debug this by
supplying the -ocd-output flag:

    $ tinygo gdb -target=esp32c3 -ocd-output examples/serial
    Open On-Chip Debugger 0.10.0
    openocd: Licensed under GNU GPL v2
    openocd: For bug reports, read
    openocd: 	http://openocd.org/doc/doxygen/bugs.html
    openocd: embedded:startup.tcl:60: Error: Can't find interface/esp_usb_jtag.cfg
    openocd: in procedure 'script'
    openocd: at file "embedded:startup.tcl", line 60

Make sure to configure OpenOCD correctly, until you get the correct
version (that includes the string "esp32"):

    $ openocd --version
    Open On-Chip Debugger  v0.10.0-esp32-20210721 (2021-07-21-13:33)
    Licensed under GNU GPL v2
    For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html

If you are on Linux, you may also get the following error:

    $ tinygo gdb -target=esp32c3 -ocd-output examples/serial
    Open On-Chip Debugger  v0.10.0-esp32-20210721 (2021-07-21-13:33)
    openocd: Licensed under GNU GPL v2
    openocd: For bug reports, read
    openocd: 	http://openocd.org/doc/doxygen/bugs.html
    openocd: Info : only one transport option; autoselect 'jtag'
    openocd: adapter speed: 40000 kHz
    openocd:
    openocd: Warn : Transport "jtag" was already selected
    openocd: Info : Listening on port 6666 for tcl connections
    openocd: Info : Listening on port 4444 for telnet connections
    openocd: Error: libusb_open() failed with LIBUSB_ERROR_ACCESS
    openocd: Error: esp_usb_jtag: could not find or open device!

The error LIBUSB_ERROR_ACCESS means that there is a permission error.
You can fix this by creating the following file:

    $ cat /etc/udev/rules.d/50-esp.rules
    # ESP32-C3
    SUBSYSTEMS=="usb", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="0666"

For more details, see:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-guides/jtag-debugging/index.html
2021-10-02 09:24:13 +02:00
Ayke van Laethem 29d3e10dc9 ci: fix wasmtime.dev expiry issue by upgrading some packages
Hopefully this will fix the CI breakage after curl and wget refuse to
download anything from wasmtime.dev (which is signed by Let's Encrypt).

- wget needs and updated libgnutls30
- curl needs and updated libssl1.0.2
2021-10-01 17:45:54 +02:00
sago35 06c60b4ecf esp32: remove extra configuration 2021-09-29 14:51:04 +02:00
Ayke van Laethem 5c0a337c4f cgo: implement rudimentary C array decaying
This is just a first step. It's not complete, but it gets some real
world C code to parse.

This signature, from the ESP-IDF:

    esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]);

Was previously converted to something like this (pseudocode):

    C.esp_err_t esp_wifi_get_mac(ifx C.wifi_interface_t, mac [6]uint8)

But this is not correct. C array parameters will decay. The array is
passed by reference instead of by value. Instead, this would be the
correct signature:

    C.esp_err_t esp_wifi_get_mac(ifx C.wifi_interface_t, mac *uint8)

So that it can be called like this (using CGo):

    var mac [6]byte
    errCode := C.esp_wifi_get_mac(C.ESP_IF_WIFI_AP, &mac[0])

This stores the result in the 6-element array mac.
2021-09-29 13:38:33 +02:00
Ayke van Laethem 04e8f44370 os: don't try to read executable path on baremetal
Baremetal systems usually pretend to be GOOS=linux, so an extra build
tag is needed here.
2021-09-28 20:28:15 +02:00
Ayke van Laethem e02727679f builder, cgo: support function definitions in CGo headers
For example, the following did not work before but does work with this
change:

    // int add(int a, int b) {
    //   return a + b;
    // }
    import "C"

    func main() {
        println("add:", C.add(3, 5))
    }

Even better, the functions in the header are compiled together with the
rest of the Go code and so they can be optimized together! Currently,
inlining is not yet allowed but const-propagation across functions
works. This should be improved in the future.
2021-09-28 18:44:11 +02:00
Ayke van Laethem 138add2b96 cgo: fix line/column reporting in syntax error messages 2021-09-28 18:44:11 +02:00
Ayke van Laethem bf9dab36f7 build: normalize target triples to match Clang
This commit changes a target triple like "armv6m-none-eabi" to
"armv6m-unknown-unknow-eabi". The reason is that while the former is
correctly parsed in Clang (due to normalization), it wasn't parsed
correctly in LLVM meaning that the environment wasn't set to EABI.

This change normalizes all target triples and uses the EABI environment
(-eabi in the triple) for Cortex-M targets.

This change also drops the `--target=` flag in the target JSON files,
the flag is now added implicitly in `(*compileopts.Config).CFlags()`.
This removes some duplication in target JSON files.

Unfortunately, this change also increases code size for Cortex-M
targets. It looks like LLVM now emits calls like __aeabi_memmove instead
of memmove, which pull in slightly more code (they basically just call
the regular C functions) and the calls themself don't seem to be as
efficient as they could be. Perhaps this is a LLVM bug that will be
fixed in the future, as this is a very common occurrence.
2021-09-28 18:44:11 +02:00
Ayke van Laethem 6234bf9a88 all: use -opt flag for optimization level in CFlags (-Os, etc)
This brings some consistency to the CFlags and fixes the issue that on
some platforms (Linux, MacOS), no optimization level was set and
therefore C files in packages were not optimized at all.
2021-09-28 18:44:11 +02:00
Damian Gryski 32899d1cc3 testing: add a stub for t.Parallel() 2021-09-27 20:02:02 +02:00
Damian Gryski 0dfb336563 add support for -test.short flag 2021-09-27 20:02:02 +02:00
Damian Gryski d9ad500cf7 src/reflect: fix type.Size() to account for struct padding
Fixes #2141
2021-09-27 17:04:16 +02:00
Ayke van Laethem 49dd2ce393 all: fix staticcheck warnings
This is a loose collection of small fixes flagged by staticcheck:

  - dead code
  - regexp expressions not using backticks (`foobar` / "foobar")
  - redundant types of slice and map initializers
  - misc other fixes

Not all of these seem very useful to me, but in particular dead code is
nice to fix. I've fixed them all just so that if there are problems,
they aren't hidden in the noise of less useful issues.
2021-09-27 15:47:12 +02:00
sago35 7df8e8db42 feather-stm32f405, feather-rp2040: add I2C pin names 2021-09-27 12:37:26 +02:00
Damian Gryski 25011c5078 src/internal/bytealg: fix indexing error in Compare()
Fixes #2139
2021-09-26 11:07:19 +02:00
sago35 54867f901a version: update TinyGo version to 0.21.0-dev 2021-09-23 21:08:44 +02:00
Nia Waldvogel 1573826005 transform (coroutines): move any misplaced entry-block allocas to the start of the entry block before lowering 2021-09-21 20:08:30 +02:00
Nia Waldvogel ecd8c2d902 transform (coroutines): fix memory corruption for tail calls that reference stack allocations
This change fixes a bug in which `alloca` memory lifetimes would not extend past the suspend of an asynchronous tail call.
This would typically manifest as memory corruption, and could happen with or without normal suspending calls within the function.
2021-09-21 20:08:30 +02:00
Ayke van Laethem a116fd0dc6 main: release version 0.20.0 2021-09-21 18:05:21 +02:00
Ayke van Laethem a590d791bd builder: simplify running of jobs
Instead of keeping a slice of jobs to run, let the runJobs function
determine which jobs should be run by investigating all dependencies.
This has two benefits:

  - The code is somewhat cleaner, as no 'jobs' slice needs to be
    maintained while constructing the dependency graph.
  - Eventually, some jobs might not be required by any dependency.
    While it's possible to avoid adding them to the slice, the simpler
    solution is to build a new slice from the dependencies which will
    only include required dependencies by design.
2021-09-17 22:22:27 +02:00
Ayke van Laethem cb147b9475 esp32c3: add support for this chip
This change adds support for the ESP32-C3, a new chip from Espressif. It
is a RISC-V core so porting was comparatively easy.

Most peripherals are shared with the (original) ESP32 chip, but with
subtle differences. Also, the SVD file I've used gives some
peripherals/registers a different name which makes sharing code harder.
Eventually, when an official SVD file for the ESP32 is released, I
expect that a lot of code can be shared between the two chips.

More information: https://www.espressif.com/en/products/socs/esp32-c3

TODO:
  - stack scheduler
  - interrupts
  - most peripherals (SPI, I2C, PWM, etc)
2021-09-16 20:13:04 +02:00
Ayke van Laethem c830f878c6 stm32: add support for PortMask* functions for WS2812 support
This also requires support in the tinygo.org/x/drivers/ws2812 package,
which I've already partially written.
2021-09-16 18:29:14 +02:00
Ayke van Laethem c7c874a487 loader: fix panic in CGo files with syntax errors
If all of the Go files presented to the compiler have syntax errors,
cgo.Process gets an empty files slice and will panic:

    panic: runtime error: index out of range [0] with length 0

    goroutine 1 [running]:
    github.com/tinygo-org/tinygo/cgo.Process({0x0, 0x4e8e36, 0x0}, {0xc000024104, 0x18}, 0xc000090fc0, {0xc000899780, 0x7, 0xc00018ce68})
    	/home/ayke/src/github.com/tinygo-org/tinygo/cgo/cgo.go:186 +0x22ee
    github.com/tinygo-org/tinygo/loader.(*Package).parseFiles(0xc0001ccf00)
    	/home/ayke/src/github.com/tinygo-org/tinygo/loader/loader.go:400 +0x51e

This is simple to work around: just don't try to run CGo when there are
no files to process. It just means there are bugs to fix before CGo can
properly run.

(This is perhaps not the nicest solution but certainly the simplest).
2021-09-15 19:04:26 +02:00
Ayke van Laethem c528a168ee os: add SEEK_SET, SEEK_CUR, and SEEK_END
These are deprecated but still used by some code.
2021-09-15 18:58:17 +02:00
Ayke van Laethem 88b9c27dbf unix: check for mmap error and act accordingly
At startup, a large chunk of virtual memory is used up by the heap. This
works fine in emulation (qemu-arm), but doesn't work so well on an
actual Raspberry Pi. Therefore, this commit reduces the requested amount
until a heap size is found that works on the system.

This can certainly be improved, but for now it's an important fix
because it allows TinyGo built binaries to actually run on a Raspberry
Pi with just 1GB RAM.
2021-09-15 17:06:21 +02:00
Ayke van Laethem 37ee4bea40 arm: switch to Thumb instruction set on ARM
This reduces binary size substantially, for two reasons:

  - It switches to a much more architecture ARMv4 vs ARMv7.
  - It switches to Thumb2, which is a lot denser than regular ARM.

Practically all modern and not-so-modern ARM chips support Thumb2, so
this seems like a safe change to me.

The size in numbers:

  - Code size for testdata/stdlib.go is reduced by about 35%.
  - Binary size for testdata/stdlib.go (when compiling with -no-debug to
    strip debug information) is reduced by about 16%.
2021-09-15 15:28:10 +02:00
ardnew ca4f251050 relax restriction on configuration with duplicate settings 2021-09-13 09:29:20 +02:00
ardnew 1e92e5f6c6 teensy40: enable hardware UART reconfiguration, fix receive watermark interrupt 2021-09-13 09:29:20 +02:00
Damian Gryski 3eb9dca695 machine: fix copy-paste error for atsamd21/51 calibTrim block
Fixes #2097
2021-09-10 18:07:17 +02:00
sago35 53794cf339 target: fix pid for mdbt50qrx-uf2 2021-09-09 18:40:03 +02:00
Damian Gryski da6c14481f runtime: fix a suspicious bitwise operation
The `0 << nxp.SIM_CLKDIV1_OUTDIV1_Pos` term was duplicated.
No effect other than triggering a static analysis check.
2021-09-09 17:51:46 +02:00
sago35 fb5516604d targets: add DefaultUART to adafruit boards 2021-09-09 15:58:35 +02:00
Ayke van Laethem e9f1ed701a cgo: don't normalize CGo tests anymore
Normalization was required because previously we supported Go 1.13 and
Go 1.14 at the same time. Now we've dropped support for both so this
normalization is not necessary anymore.

CGo support remains the same. It's just the test outputs that aren't
normalized anymore.
2021-09-09 13:28:50 +02:00
Ayke van Laethem 6315db21f7 compiler: avoid zero-sized alloca in channel operations
This works around a bug in LLVM
(https://bugs.llvm.org/show_bug.cgi?id=49916) but seems like a good
change in general.
2021-09-09 11:24:52 +02:00
Damian Gryski 485a9284e7 builder: add missing error check for ioutil.TempFile() 2021-09-08 15:21:31 +02:00
BCG 602d3d7c78 board: add Raytac MDBT50Q-RX Dongle with TinyUF2 2021-09-08 12:40:49 +02:00
Ayke van Laethem 409688e67a compiler: fix equally named structs in different scopes
For example, in this code:

    type kv struct {
           v float32
    }

    func foo(a *kv) {
           type kv struct {
                   v byte
           }
    }

Both 'kv' types would be given the same LLVM type, even though they are
different types! This is fixed by only creating a LLVM type once per Go
type (types.Type).

As an added bonus, this change gives a performance improvement of about
0.4%. Not that much, but certainly not nothing for such a small change.
2021-09-08 10:02:57 +02:00
Damian Gryski d348db4a0d tinygo: add a flag for creating cpu profiles 2021-09-08 01:09:10 +02:00
Damian Gryski 95ab7cb8d1 Makefile: add smoke test with gc=leaking to test dead asm code 2021-09-07 08:00:11 +02:00
Damian Gryski 32de906f6d internal/task, runtime: add subsections_via_symbols to assembly files on darwin
This allows the assembly routines in these files to be stripped as dead
code if they're not referenced.  This solves the link issues on MacOS
when the `leaking` garbage collector or the `coroutines` scheduler
are selected.

Fixes #2081
2021-09-07 08:00:11 +02:00
Ron Evans eaab05fc43 Revert "Minor changes to support go 1.17"
This reverts commit 2d224ae049.
2021-09-06 12:39:40 +02:00
sago35 4d1945b467 nrf52840: fix ram size 2021-09-05 23:54:26 +02:00
Mike Mogenson fd9422d218 fix GBA ROM header
Populate the GBA ROM header so that emulators and physical Game Boy
Advance consoles recognize the ROM as a valid game.

Note: The reserve space at the end of the header was hand-tuned. Why
this magic value?
2021-09-05 19:59:26 +02:00
sago35 bbbe7d43ce machine/arduino_mkrwifi1010: fix pin definition of NINA_RESETN 2021-09-05 14:10:25 +02:00
Damian Gryski b3f1dacbb9 interp: remove unused gepOperands slice 2021-09-05 12:00:07 +02:00
Damian Gryski 5fa1e7163a src/runtime: reset heapptr to heapStart after preinit()
heapptr is assinged to heapStart (which is 0) when it's declared, but preinit()
may have moved the heap somewhere else.  Set heapptr to the proper value
of heapStart when we initialize the heap properly.

This allows the leaking allocator to work on unix.
2021-09-04 12:13:53 +02:00
deadprogram 4b1f92600f docker: use go 1.17 for docker dev build
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-09-02 11:18:52 +02:00
sago35 ca39bc9f35 machine/feather-rp2040: add pin name definition for feather 2021-09-01 20:55:35 +02:00
sago35 f985f2c376 targets: add openocd configuration for rp2040 2021-09-01 19:37:23 +02:00
Federico G. Schwindt f0936ffccb Implement os.Executable
For now this is a stub for everything but linux, which is a slightly
modified copy of the official implementation.

Should address #1778.
2021-09-01 19:01:35 +02:00
Yurii Soldak 97d48e5c02 board/nano-rp2040: define NINA_SPI and fix wifinina pins 2021-09-01 17:24:19 +02:00
Patricio Whittingslow a7c53cce06 machine/rp2040: add PWM implementation (#2015)
machine/rp2040: add PWM implementation
2021-09-01 16:58:13 +02:00
Federico G. Schwindt 2d224ae049 Minor changes to support go 1.17 2021-08-31 16:04:42 +02:00
Olivier Fauchon 6c6fea5387 BlackMagic (BMP) ARM JTAG/SWD debugger:
- Flashing and debugging with BMP can be done with -programmer=bmp
- New getBMPPorts() function was added to properly detect BMP USB serial ports.
2021-08-31 10:03:40 +02:00
sago35 98bd947817 machine/arduino_mkrwifi1010: add board definition for Arduino MKR WiFi 1010 2021-08-30 15:45:47 +02:00
Ayke van Laethem 255f35671d compiler: add support for new language features of Go 1.17 2021-08-30 09:18:58 +02:00
Ayke van Laethem 8e88e560a1 all: add support for Go 1.17 2021-08-30 09:18:58 +02:00
Ayke van Laethem d45497691f reflect: add StructField.IsExported method
This field was introduced in Go 1.17 and is used by the encoding/json
package (starting with Go 1.17).
2021-08-30 09:18:58 +02:00
Ayke van Laethem ad73986070 goenv: improve Go version detection
First look at the VERSION file, only then look at
src/runtime/internal/sys/zversion.go. This makes it possible to
correctly detect the Go version for release candidates.
2021-08-30 09:18:58 +02:00
deadprogram 931f87f96a docker: golang default images now based on bullseye
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-08-18 20:28:36 +02:00
deadprogram 192a32f8d9 docker: use autoremove to tr to cleanup broken packages
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-08-18 20:19:33 +02:00
deadprogram 972f4254eb docker: add GH actions build on fix-docker-llvm-build branch to sort out build issues
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-08-18 20:18:16 +02:00
deadprogram 7d83e2ee5c docker: apt clean before apt get of llvm to avoid broken packages
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-08-18 20:01:50 +02:00
Ayke van Laethem 0f2f73be53 compiler: fix max possible slice
This commit improves make([]T, len) to be closer to upstream Go. The
difference is unlikely to have much real-world effect, but previously
certain make([]T, len) expressions would not result in a slice out of
bounds error in TinyGo while they would have done such a thing in Go
proper. In practice, available RAM is likely to be a bigger limiting
factor.
2021-08-17 08:16:27 +02:00
Ayke van Laethem a2cc5715ba compiler: add *ssa.MakeSlice bounds tests
There are some bugs in it. This commit adds the tests, so that the next
commit can show what changed.
2021-08-17 08:16:27 +02:00
Ayke van Laethem 59d53182bb all: use new testing features of Go 1.14 and 1.15
This simplifies the tests a bit.
2021-08-16 21:19:26 +02:00
Ayke van Laethem 25c7bfd404 ci: drop support for Go 1.13 and 1.14
They aren't supported anymore in CI, and because untested code is broken
code, let's remove support for these Go versions altogether.
2021-08-16 21:19:26 +02:00
Ayke van Laethem 04f520040e testing: add support for the -test.v flag
This flag is passed automatically with the (new) -v flag for TinyGo. For
example, this prints all the test outputs:

    $ tinygo test -v crypto/md5
    === RUN   TestGolden
    --- PASS: TestGolden
    === RUN   TestGoldenMarshal
    --- PASS: TestGoldenMarshal
    === RUN   TestLarge
    --- PASS: TestLarge
    === RUN   TestBlockGeneric
    --- PASS: TestBlockGeneric
    === RUN   TestLargeHashes
    --- PASS: TestLargeHashes
    PASS
    ok  	crypto/md5	0.002s

This prints just a summary:

    $ tinygo test crypto/md5
    PASS
    ok  	crypto/md5	0.002s

(The superfluous 'PASS' message may be removed in the future).

This is especially useful when testing a large number of packages:

    $ tinygo test crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512
    PASS
    ok  	crypto/md5	0.002s
    PASS
    ok  	crypto/sha1	0.043s
    PASS
    ok  	crypto/sha256	0.002s
    PASS
    ok  	crypto/sha512	0.003s

At the moment, the -test.v flag is not supplied to binaries running in
emulation. I intend to fix this after
https://github.com/tinygo-org/tinygo/pull/2038 lands by refactoring
runPackageTest, Run, and runTestWithConfig in the main package which all
do something similar.
2021-08-13 08:53:40 +02:00
Ayke van Laethem f57e9622fd baremetal,wasm: support command line params and environment variables
This is mainly useful to be able to run `tinygo test`, for example:

    tinygo test -target=cortex-m-qemu -v math

This is not currently supported, but will be in the future.
2021-08-12 21:19:24 +02:00
Ayke van Laethem c25a7cc747 testing: test testing package using tinygo test 2021-08-12 13:23:41 +02:00
Ayke van Laethem 5e5ce98d42 compiler: add aliases for many hashing packages
This commit adds support for the following packages:

  - crypto/md5
  - crypto/sha1
  - crypto/sha256
  - crypto/sha512

They would normally need assembly implementations, but with these
aliases they already work everywhere.
2021-08-10 20:08:27 +02:00
Ayke van Laethem a3c4421f39 compiler: move math aliases from the runtime to the compiler
This makes them more flexible, especially with Go 1.17 making the
situation more complicated (see
https://github.com/golang/go/commit/1d20a362d0ca4898d77865e314ef6f73582daef0).
It also makes it possible to do the same for many other functions, such
as assembly implementations of cryptographich functions which are
similarly dependent on the architecture.
2021-08-10 20:08:27 +02:00
Ayke van Laethem 58565b42cc compiler: move LLVM math builtin support into the compiler
This simplifies src/runtime/math.go, which I eventually want to remove
entirely by moving the given functionality into the compiler.
2021-08-10 20:08:27 +02:00
Ayke van Laethem ca7c849da3 386: bump minimum requirement to the Pentium 4
Previously we used the i386 target, probably with all optional features
disabled. However, the Pentium 4 has been released a _long_ time ago and
it seems reasonable to me to take that as a minimum requirement.

Upstream Go now also seems to move in this direction:
https://github.com/golang/go/issues/40255

The main motivation for this is that there were floating point issues
when running the tests for the math package:

    GOARCH=386 tinygo test math

I haven't investigated what's the issue, but I strongly suspect it's
caused by the weird x87 80-bit floating point format. This could perhaps
be fixed in a different way (by setting the FPU precision to 64 bits)
but I figured that just setting the minimum requirement to the Pentium 4
would probably be fine. If needed, we can respect the GO386 environment
variable to support these very old CPUs.

To support this newer CPU, I had to make sure that the stack is aligned
to 16 bytes everywhere. This was not yet always the case.
2021-08-10 20:08:27 +02:00
Ayke van Laethem 6c1301688b math: fix math.Max and math.Min
The math package failed the package tests on arm64 and wasm:

    GOARCH=arm64 tinygo test math

Apparently the builtins llvm.maximum.f64 and llvm.minimum.f64 have
slightly different behavior on arm64 and wasm compared to what Go
expects.
2021-08-10 20:08:27 +02:00
Ayke van Laethem d05103668f crypto/rand: switch to arc4random_buf
This doesn't have the potential blocking issue of the getentropy call
(which calls WASI random_get when using wasi-libc) and should therefore
be a lot faster.

For context, this is what the random_get documentation says:

> Write high-quality random data into a buffer. This function blocks
> when the implementation is unable to immediately provide sufficient
> high-quality random data. This function may execute slowly, so when
> large mounts of random data are required, it's advisable to use this
> function to seed a pseudo-random number generator, rather than to
> provide the random data directly.
2021-08-09 15:20:39 +02:00
Patricio Whittingslow 4f7b23c2b7 machine/rp2040: add I2C support (#2013)
machine/rp2040: add i2c support
2021-08-06 17:22:50 +02:00
Dan Kegel cfae2d4f9a Makefile: add src/testing to FMT_PATHS 2021-08-06 08:19:15 +02:00
Dan Kegel 55789fd2c2 src/testing/benchmark.go: add subset implementation of Benchmark
Partially fixes #1808

Allows the following to succeed:

curl "https://golang.org/test/fibo.go?m=text" > fibo.go
tinygo build -o fibo fibo.go
./fibo -bench
2021-08-06 08:19:15 +02:00
Ayke van Laethem 478c592b13 wasm: add support for the crypto/rand package
This is done via wasi-libc and the WASI interface, for ease of
maintenance (only one implementation for both WASI and JS/browsers).
2021-08-05 19:01:14 +02:00
Ayke van Laethem ab47cea055 transform: improve GC stack slot pass to work around a bug
Bug 1790 ("musttail call must precede a ret with an optional bitcast")
is caused by the GC stack slot pass inserting a store instruction
between a musttail call and a return instruction. This is not allowed in
LLVM IR.

One solution would be to remove the musttail. That would probably work,
but 1) the go-llvm API doesn't support this and 2) this might have
unforeseen consequences. What I've done in this commit is to move the
store instruction to a position earlier in the basic block, just after
the last access to the GC stack slot alloca.

Thanks to @fgsch for a very small repro, which I've used as a regression
test.
2021-08-04 20:06:59 +02:00
soypat 98e70c9b19 machine/rp2040: add SPI support
spi working with loopback

SPI working

apply @deadprogram's suggestions

consolidate SPI board pin naming

fix up SPI configuration

add feather-rp2040 SPI pins

add arduino connect SPI pins

add SPI handle variables
2021-07-31 22:11:08 +02:00
Ayke van Laethem 7434e5a2c7 main: strip debug information at link time instead of at compile time
Stripping debug information at link time also allows relocation
compression (aka linker relaxations). Keeping debug information at
compile time and optionally stripping it at link time has some
advantages:

  * Automatic stack sizes on Cortex-M rely on the presence of debug
    information.
  * Some parts of the compiler now rely on the presence of debug
    information for proper diagnostics.
  * It works better with the cache: there is no distinction between
    debug and no-debug builds.
  * It makes it easier (or possible at all) to enable debug information
    in the wasi-libc library without big downsides.
2021-07-31 18:33:52 +02:00
Ayke van Laethem 65c1978965 wasm: align heap to 16 bytes
This commit fixes two things:

  * It changes the alignment to 16 bytes (from 4), to match max_align_t
    in C.
  * It manually aligns heapStart on WebAssembly, to work around a bug in
    wasm-ld with --stack-first (see https://reviews.llvm.org/D106499).
2021-07-30 08:38:51 +02:00
Federico G. Schwindt e834d78871 Fix undefined symbols error
Currently TinyGo does not process SFiles (assembly files), which
are needed by math/big. Add math_big_pure_go to the build tags to
unbreak it.
2021-07-27 14:14:39 +02:00
Ayke van Laethem 03481789b0 runtime: fix time base for time.Now()
This function previously returned the atomic time, that isn't affected
by system time changes but also has a time base at some arbitrary time
in the past. This makes sense for baremetal platforms (which typically
don't know the wall time) but it gives surprising results on Linux and
macOS: time.Now() usually returns a time somewhere near the start of
1970.

This commit fixes this by obtaining both time values: the monotonic time
and the wall clock time. This is also how the Go runtime implements the
time.now function.
2021-07-20 22:19:13 +02:00
sago35 73cf187552 machine/feather-nrf52: fix pin definition of uart 2021-07-20 17:45:41 +02:00
Ayke van Laethem b40703e986 wasm: override dlmalloc heap implementation from wasi-libc
These two heaps conflict with each other, so that if any function uses
the dlmalloc heap implementation it will eventually result in memory
corruption.

This commit fixes this by implementing all heap-related functions. This
overrides the functions that are implemented in wasi-libc. That's why
all of them are implemented (even if they just panic): to make sure no
program accidentally uses the wrong one.
2021-07-15 00:13:17 +02:00
Ayke van Laethem 00ea0b1d57 build: list libraries at the end of the linker command
Static libraries should be added at the end of the linker command, after
all object files. If that isn't done, that's _usually_ not a problem,
unless there are duplicate symbols. In that case, weird dependency
issues can arise. To solve that, object files (that may include symbols
to override symbols in the library) should be listed first on the
command line and then the static libraries should be listed.

This fixes an issue with overriding some symbols in wasi-libc.
2021-07-15 00:13:17 +02:00
Ayke van Laethem efa0410075 interp: fix bug in compiler-time/run-time package initializers
Make sure that if a package initializer cannot be run, later package
initializers won't try to access any global variables touched by the
uninterpretable package initializer.
2021-07-14 22:33:32 +02:00
Ayke van Laethem 607d824211 interp: keep reverted package initializers in order
Previously, a package initializer that could not be reverted correctly
would be called at runtime. But the initializer would be called in the
wrong order: after later packages are initialized.

This commit fixes this oversight and adds a test to verify the new
behavior.
2021-07-14 22:33:32 +02:00
Ayke van Laethem 8cc7c6d572 interp: populate Inst field in interp.Error
It is used in the main package but wasn't actually set anywhere.
2021-07-14 22:33:32 +02:00
Ayke van Laethem cdba4fa8cc interp: don't ignore array indices for untyped objects
This fixes https://github.com/tinygo-org/tinygo/issues/1884.
My original plan to fix this was much more complicated, but then I
realized that the output type doesn't matter anyway and I can simply
cast the type to an *i8 and perform a GEP on that pointer.
2021-07-14 07:55:05 +02:00
Ayke van Laethem 0565b7c0e0 cortexm: fix stack overflow because of unaligned stacks
On ARM, the stack has to be aligned to 8 bytes on function calls, but
not necessarily within a function. Leaf functions can take advantage of
this by not keeping the stack aligned so they can avoid pushing one
register. However, because regular functions might expect an aligned
stack, the interrupt controller will forcibly re-align the stack when an
interrupt happens in such a leaf function (controlled by the STKALIGN
flag, defaults to on). This means that stack size calculation (as used
in TinyGo) needs to make sure this extra space for stack re-alignment is
available.

This commit fixes this by aligning the stack size that will be used for
new goroutines.

Additionally, it increases the stack canary size from 4 to 8 bytes, to
keep the stack aligned. This is not strictly necessary but is required
by the AAPCS so let's do it anyway just to be sure.
2021-07-07 09:25:47 +02:00
soypat 444dded92c move xtoi2 to parse.go 2021-07-02 18:49:14 +02:00
Patricio Whittingslow 42785e08e8 add MAC address implementation to net 2021-07-02 18:49:14 +02:00
sago35 2d633e3a28 version: update TinyGo version to 0.20.0-dev 2021-07-02 18:47:30 +02:00
Ayke van Laethem 64d048c47c main: release version 0.19.0 2021-06-30 20:05:10 +02:00
sago35 c8e231bc0b targets: add serial and serial-port key to JSON files for seeed boards 2021-06-29 09:07:02 +02:00
sago35 b00cfc001e targets: add serial and serial-port key to JSON files for adafruit boards 2021-06-29 09:07:02 +02:00
sago35 e127ceac67 machine/feather-nrf52840-sense: fix msd-volume-name 2021-06-28 11:38:10 +02:00
sago35 e5453ebe27 machine/feather-nrf52840-sense: add board definition for Adafruit Feather nRF52840 Sense 2021-06-26 15:37:17 +02:00
deadprogram 0e267dd230 targets: add serial key to JSON files for newly added rp2040 boards, and also nano-33-ble board
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-06-25 22:06:16 +02:00
Ayke van Laethem 96e863f0f3 all: add a flag to the command line to select the serial implementation
This can be very useful for some purposes:

  * It makes it possible to disable the UART in cases where it is not
    needed or needs to be disabled to conserve power.
  * It makes it possible to disable the serial output to reduce code
    size, which may be important for some chips. Sometimes, a few kB can
    be saved this way.
  * It makes it possible to override the default, for example you might
    want to use an actual UART to debug the USB-CDC implementation.

It also lowers the dependency on having machine.Serial defined, which is
often not defined when targeting a chip. Eventually, we might want to
make it possible to write `-target=nrf52` or `-target=atmega328p` for
example to target the chip itself with no board specific assumptions.

The defaults don't change. I checked this by running `make smoketest`
before and after and comparing the results.
2021-06-25 17:58:39 +02:00
Ayke van Laethem 75298bb84b os: implement process related functions
This commit implements various process related functions like
os.Getuid() and os.Getpid(). It also implements or improves this support
in the syscall package if it isn't available yet.
2021-06-25 16:14:47 +02:00
Ayke van Laethem e65592599c compiler: implement syscall.rawSyscallNoError in inline assembly
This makes it possible to call syscall.Getpid() on Linux, for example.
These syscalls never return an error so don't need any error checking.
2021-06-25 16:14:47 +02:00
Yurii Soldak e02f308d43 rp2040: fix for nano-rp2040 board 2021-06-24 17:34:14 +02:00
Yurii Soldak bfe3f68647 smoke&readme: add missing boards 2021-06-24 17:34:14 +02:00
Ayke van Laethem 2bb70812a8 compiler: add function and global section pragmas
This patch adds a new pragma for functions and globals to set the
section name. This can be useful to place a function or global in a
special device specific section, for example:

  * Functions may be placed in RAM to make them run faster, or in flash
    (if RAM is the default) to not let them take up RAM.
  * DMA memory may only be placed in a special memory area.
  * Some RAM may be faster than other RAM, and some globals may be
    performance critical thus placing them in this special RAM area can
    help.
  * Some (large) global variables may need to be placed in external RAM,
    which can be done by placing them in a special section.

To use it, you have to place a function or global in a special section,
for example:

    //go:section .externalram
    var externalRAMBuffer [1024]byte

This can then be placed in a special section of the linker script, for
example something like this:

    .bss.extram (NOLOAD) : {
        *(.externalram)
    } > ERAM
2021-06-24 15:00:30 +02:00
Ayke van Laethem 293f4ea7bc compiler: add tests for pragmas
These pragmas weren't really tested anywhere, except that some code
might break if they are not properly applied.

These tests make it easy to see they work correctly and also provide a
logical place to add new pragma tests.

I've also made a slight change to how functions and globals are created:
with the change they're also created in the IR even if they're not
referenced. This makes testing easier.
2021-06-24 15:00:30 +02:00
Ayke van Laethem c3032660c9 wasi: remove wasm build tag
The wasm build tag together with GOARCH=arm was causing problems in the
internal/cpu package. In general, I think having two architecture build
tag will only cause problems (in this case, wasm and arm) so I've
removed the wasm build tag and replaced it with tinygo.wasm.

This is similar to the tinygo.riscv build tag, which is used for older
Go versions that don't yet have RISC-V support in the standard library
(and therefore pretend to be GOARCH=arm instead).
2021-06-22 09:03:23 +02:00
Ayke van Laethem d94f42f6e2 crypto/rand: replace this package with a TinyGo version
This package provides access to an operating system resource
(cryptographic numbers) and so needs to be replaced with a TinyGo
version that does this in a different way.

I've made the following choices while adding this feature:

  - I'm using the getentropy call whenever possible (most POSIX like
    systems), because it is easier to use and more reliable. Linux is
    the exception: it only added getentropy relatively recently.
  - I've left bare-metal implementations to a future patch. This because
    it's hard to reliably get cryptographically secure random numbers on
    embedded devices: most devices do not have a hardware PRNG for this
    purpose.
2021-06-21 18:22:31 +02:00
Ayke van Laethem d8ac7ccaae interp: fix a bug in pointer cast workaround
This was triggered by the following code:

    var smallPrimesProduct = new(big.Int).SetUint64(16294579238595022365)

It is part of the new TinyGo version of the crypto/rand package.
2021-06-21 18:22:31 +02:00
Federico G. Schwindt 64058c3efb net: os: add more stubs for 1.15
Fix importing net/http.
2021-06-21 16:21:44 +02:00
Ayke van Laethem e107efa63f main: detect specific serial port IDs based on USB vid/pid
This makes it possible to flash a board even when there are multiple
different kinds of boards attached, e.g. an Arduino Uno and a Circuit
Playground Express. You can find the VID/PID pair in several ways:

 1. By running `lsusb` before and after attaching the board and looking
    at the new USB device.
 2. By grepping for `usb_PID` and `usb_VID` in the TinyGo source code.
 3. By checking the Arduino IDE boards.txt from the vendor.

Note that one board may have multiple VID/PID pairs:

  * The bootloader and main program may have a different PID, so far
    I've seen that the main program generally has the bootloader PID
    with 0x8000 added.
  * The software running on the board may have an erroneous PID, for
    example from a different board. I've seen this happen a few times.
  * A single board may have had some revisions which changed the PID.
    This is particularly true for the Arduino Uno.

As a fallback, if the given VID/PID pair isn't found, the whole set of
serial ports will be used.

There are many boards which I haven't included yet simply because I
couldn't test them.
2021-06-19 16:45:56 +02:00
Kenneth Bell 8e33f1c9eb rp2040: support Adafruit Feather RP2040 2021-06-19 12:34:40 +02:00
Ayke van Laethem 1913cb76a5 cortexm: bump default stack size to 2048 bytes
Previously it was 1024 bytes, which occasionally ran into a stack
overflow. I hope that 2048 bytes will be enough for most purposes.

I've also removed some 2048-byte stack size settings in JSON files,
which are unnecessary now that the parent (cortex-m.json) sets them.
2021-06-18 13:23:50 +02:00
Ayke van Laethem cd628bcde6 nrf52840: add support for flashing with the BOSSA tool
This only works with a custom bossac build from Arduino, not with the
upstream version. It avoids needing the manual "double tap" to enter
bootloader mode before flashing firmware.
2021-06-18 13:00:00 +02:00
Ayke van Laethem d1f445735c syscall: fix int type in libc version
Int in Go and C are two different types (hence why CGo has C.int). The
code in syscall assumed they were of the same type, which led to a bug:
https://github.com/tinygo-org/tinygo/issues/1957

While the C standard makes no guarantees on the size of int, in most
modern operating systems it is 32-bits so Go int32 would be the correct
choice.
2021-06-18 08:07:01 +02:00
Yurii Soldak 28a2ad4757 gdb: use "extended-remote" instead of "remote", allows connect from another client
My gdb complains bare "remote" command is deprecated
On top of that "extended-remote" allows "disconnect" command that enables attaching from another debug client, like an IDE
See https://sourceware.org/gdb/current/onlinedocs/gdb/Connecting.html
2021-06-17 23:52:44 +02:00
Ayke van Laethem f2e8d7112c compiler: refactor method names
This commit includes two changes:

  * It makes unexported interface methods package-private, so that it's
    not possible to type-assert on an unexported method in a different
    package.
  * It makes the globals used to identify interface methods defined
    globals, so that they can (eventually) be left in the program for an
    eventual non-LTO build mode.
2021-06-17 12:17:32 +02:00
Kenneth Bell 52d640967b rp2040: patch elf to checksum 2nd stage boot 2021-06-17 12:10:04 +02:00
deadprogram 87e48c1057 machine/rp2040: implement UART0/UART1, can be used on all rp2040 boards
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-06-16 19:13:01 +02:00
sago35 b406b81416 machine: add definition for ws2812 2021-06-16 07:32:39 +02:00
Ayke van Laethem 3a458ec75c main: make flash-command portable and safer to use
Previously, flash-command would assume it could execute a command
straight via /bin/sh, at least on non-Windows systems. Otherwise it
would just split the command using `strings.Split`. This is all a bit
hacky, so I've replaced it with a proper solution: splitting the command
_before_ substituting various paths using a real shell splitter
(shlex.Split, from Google). This solves a few things:

  * It guards against special characters in path names. This can be an
    issue on Windows where the temporary path may contain spaces (this
    is uncommon on POSIX systems).
  * It is more portable, by disallowing the use of a shell. That way, it
    doesn't differentiate between Windows and non-Windows anymore.
2021-06-15 14:36:54 +02:00
Yurii Soldak 7764797061 board/nano-33-ble: pins, blinking leds and serial 2021-06-14 00:06:59 +02:00
Kenneth Bell 5f9e339cf3 stm32: support pin input interrupts 2021-06-11 09:07:32 +02:00
Kenneth Bell c017ed2242 bluepill: GPIO PinInputPullup / PinInputPulldown
Other chips support explicit control of pull-up vs pull-down for GPIO input.  Support that with bluepill also.  PinInputPullUpDown is maintained for back-compat.  It is implicit pull-down.
2021-06-11 09:07:32 +02:00
Yurii Soldak d62a9e24e5 runtime: expose memory stats 2021-06-10 22:03:00 +02:00
Federico G. Schwindt b092856238 Add more net compatibility
Required for net/http.
2021-06-10 15:33:46 +02:00
Yurii Soldak 15d77119c9 board/nano-rp2040: pins and blinking led 2021-06-09 19:01:02 +02:00
Yurii Soldak 95af444896 machine/rp2040: gpio and adc pin definitions 2021-06-09 12:27:05 +02:00
Olaf Flebbe 1f5e4e79aa support flashing pca10059 from windows 2021-06-08 14:17:04 +02:00
deadprogram 9912dd6db1 machine/rp2040: add basic support for ADC
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-06-08 09:22:51 +02:00
deadprogram 42ec3e2469 docker: use github actions to build/publish tinygo-dev dockerfile
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-06-08 07:37:31 +02:00
Ayke van Laethem 4e610a0ee7 main: escape commands while printing them with the -x flag
This should make issues such as the one in
https://github.com/tinygo-org/tinygo/issues/1910 more obvious.
2021-06-02 16:29:30 +02:00
Ayke van Laethem af65c006e6 loader: fix testing a main package
This was broken because multiple packages in the program were named
'main', even one that was imported (by the generated main package).

This fixes tests for main packages.
2021-06-02 15:50:28 +02:00
Ayke van Laethem 98f117fca4 main: add -test flag for tinygo list
This matches `go list` and is convenient for debugging.
2021-06-02 15:50:28 +02:00
Ayke van Laethem 4c95febeee main: don't consider compile-only tests as failing
Previously a command like the following would incorrectly print FAIL:

    tinygo test -c math

This commit fixes this issue by defaulting to a passing test (the test
is marked as passed if it isn't run).
2021-06-02 14:27:55 +02:00
Federico G. Schwindt 793a3175d3 reflect: add stubs required for net/http 2021-06-02 13:28:38 +02:00
Federico G. Schwindt 78d030aa7a Add os stubs required for net/http 2021-06-01 15:20:58 +02:00
Federico G. Schwindt 62f9f61664 Add runtime stubs required for net/http
Continued from #1911.
2021-06-01 15:15:12 +02:00
Federico G. Schwindt 5b82125765 Add sync.NewCond
Required by net/http.
2021-06-01 15:02:11 +02:00
Kenneth Bell 2f248bbf8b scheduler: task.Data made 64bit to avoid overflow 2021-06-01 15:00:07 +02:00
sago35 c5ea1fde61 increase stack size for access to sdcard 2021-06-01 09:16:34 +02:00
deadprogram 36dffb5554 machine/rp2040: add support for GPIO input 2021-05-31 11:43:00 +02:00
Ayke van Laethem e8c4c4a865 nrf: don't trigger a heap allocation in SPI.Transfer
By using a 1-byte buffer, two heap allocations each `SPI.Transfer` call
can be avoided.
2021-05-30 20:56:01 +02:00
Ayke van Laethem 8b79e82686 nrf: avoid heap allocation in waitForEvent
Because arm.SVCall1 lets pointers escape, the return value of
sd_softdevice_is_enabled (passed as a pointer in a parameter) will
escape and thus this value will be heap allocated.

Use a global variable for this purpose instead to avoid the heap
allocation. This is safe as waitForEvent may only be called outside of
interrupts.
2021-05-30 20:56:01 +02:00
sago35 22eeed2da1 qtpy: add pin for neopixels 2021-05-30 11:01:19 +02:00
Kenneth Bell cfbc9be9bf rp2040: git ignore generated device files 2021-05-29 19:56:50 +02:00
Rajiv Kanchan 722a3a5c94 add rp2040, pico
adds preliminary support (just enough to run blinky1) for the Raspberry Pi Pico board along with the rp2040 mcu.
2021-05-28 18:29:04 +02:00
deadprogram ed2db8a26d Revert "scheduler: task.Data made 64bit to avoid overflow"
This reverts commit fd8938c634.
2021-05-28 07:38:59 +02:00
Kenneth Bell fd8938c634 scheduler: task.Data made 64bit to avoid overflow 2021-05-28 00:02:46 +02:00
Kenneth Bell fa3dd41a4f stm32: Use TIM for runtime clock 2021-05-28 00:02:46 +02:00
Kenneth Bell 003c96edc0 stm32f103 (bluepill): add pwm 2021-05-28 00:02:46 +02:00
Kenneth Bell ac54302301 stm32f7: add pwm 2021-05-28 00:02:46 +02:00
Kenneth Bell c43a41165a stm32l4: add pwm 2021-05-28 00:02:46 +02:00
Kenneth Bell 3145c2747e stm32l0: add pwm 2021-05-28 00:02:46 +02:00
Kenneth Bell 2c4b507d34 stm32l5: add pwm 2021-05-28 00:02:46 +02:00
Kenneth Bell ee167f15de stm32: add pwm for f4 series 2021-05-28 00:02:46 +02:00
Yurii Soldak 422ebeeec7 Do not disable interrupts on abort
Allows panic messages to be printed fully into serial console
2021-05-27 09:28:08 +02:00
Ayke van Laethem c93ddb630b compiler: skip context parameter when starting regular goroutine
Do not store the context parameter (which is used for closures and
function pointers) in the goroutine start parameter bundle for direct
functions that don't need a context parameter. This avoids storing the
(undef) context parameter and thus makes the IR to start a new goroutine
simpler in most cases.

This reduces code size in the channel.go and goroutines.go tests.
Surprisingly, all test cases (when compiled with -target=microbit) have
a changed binary, I haven't investigated why but I suppose the codegen
is slightly different for the runtime.run function (which starts the
main goroutine).
2021-05-26 20:21:08 +02:00
Ayke van Laethem 3edcdb5f0d compiler: do not emit nil checks for loading closure variables
Closure variables are allocated in a parent function and are thus never
nil. Don't do a nil check before reading or modifying the value.

This commit results in a slight reduction in code size in some test
cases: calls.go, channel.go, goroutines.go, json.go, sort.go -
presumably wherever closures are used.
2021-05-26 20:21:08 +02:00
Ayke van Laethem ec325c0643 compiler: add support for running a builtin in a goroutine
Not sure why you would ever do this, but it appears to be allowed by the
Go specification and previously TinyGo would crash with an unhelpful
error message when you would do this. I don't see any practical use of
it.

The implementation simply runs the builtin directly.
2021-05-26 20:21:08 +02:00
Ayke van Laethem 87c2ccb0b9 compiler: add tests for starting a goroutine
This commit adds a test for both WebAssembly and Cortex-M targets (which
use a different way of goroutine lowering) to show how they lower
goroutines. It makes it easier to show how the output changes in future
commits.
2021-05-26 20:21:08 +02:00
Ayke van Laethem 6e1eb28ed0 main: rename goroutine tests
While LLVM coroutines are one implementation of goroutines, it is not
the only one. Therefore, rename the tests to 'goroutines' to better
describe what they're for.
2021-05-26 20:21:08 +02:00
Ayke van Laethem 45cf2a5a1a compiler: refactor goroutine code
Move the code from the compiler.go file to the goroutine.go file, which
is a more appropriate place. This keeps all the goroutine related code
in one file, to make it easier to find.
2021-05-26 20:21:08 +02:00
deadprogram 423cae86df docker: update dev dockerfile to Go 1.16
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-26 17:33:50 +02:00
deadprogram ea6b65e360 cmsis-svd: update with latest to sync with upstream repo
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-25 22:50:08 +02:00
Kenneth Bell e3b98dabfd Support chained interrupt handlers
Multiple calls to interrupt.New are permitted with handlers called sequentially in undefined order.
2021-05-25 20:44:49 +02:00
sago35 e312cb0fe7 os: add FileMode constants from Go 1.16 2021-05-23 21:44:27 +02:00
Ayke van Laethem 541d8dcd2e reflect: implement AppendSlice
This implementation of AppendSlice simply calls through to the version
used in the runtime: runtime.sliceAppend.
2021-05-22 21:41:06 +02:00
Ayke van Laethem c8742e2b96 reflect: use SliceHeader and StringHeader variant for internal use
These variants uses an unsafe.Pointer instead of uintptr so that the
pointer/non-pointer fields match those of real slices and strings. This
may be necessary in the future once we switch to a precise garbage
collector.
2021-05-22 21:41:06 +02:00
Ayke van Laethem 711889bc3f cgo: implement prefix parsing
This implements expressions such as "-5" and "-5 - 2", in other words,
negative numbers.
2021-05-21 17:54:13 +02:00
Ayke van Laethem 70f8eeaca0 cgo: parse binary operators
This follows the Pratt parser design.
2021-05-21 17:54:13 +02:00
Ayke van Laethem 3339d0f47e cgo: create skeleton of a Pratt parser
This converts the existing const parser to the basics of a Pratt parser,
following the book "Writing An Interpreter In Go" by Thorsten Ball. It
doesn't really do anything interesting yet, it simply converts the
existing code (with existing tests) to the new structure.
2021-05-21 17:54:13 +02:00
Federico G. Schwindt a38b5c4e01 Add a stub for os.ReadDir()
This is needed by crypto/x509 in some configuration.
Related to #1888.
2021-05-20 14:14:04 +02:00
Federico G. Schwindt b20905da13 Add support for net.IP 2021-05-20 13:46:19 +02:00
Ayke van Laethem 95e4dcfb53 interp: ignore inline assembly in markExternal
The markExternal function is used when a global (function or global
variable) is somehow run at runtime. All the other globals it refers to
are from then on no longer known at compile time, so can't be used by
the interp package anymore.

This can also include inline assembly. While it is possible to modify
globals that way, it is only possible to modify exported globals:
similar to calling an undefined function (in C for example).
2021-05-20 07:42:19 +02:00
Ayke van Laethem 841f19f49e ci: disable building some optional Clang components
This commit disables the Clang static analyzer and ARCMigrate components
of Clang. These aren't used at the moment in TinyGo so don't need to be
enabled. This reduces the build by 200 files (2909 -> 2709).

The idea comes from here (via LLVM weekly):
https://www.cambus.net/speedbuilding-llvm-clang-in-5-minutes/
2021-05-19 19:12:26 +02:00
sago35 2085ffb334 version: update TinyGo version to 0.19.0-dev 2021-05-14 11:47:07 +02:00
Ayke van Laethem b67351babe machine: define Serial as the default output
Previously, the machine.UART0 object had two meanings:

  - it was the first UART on the chip
  - it was the default output for println

These two meanings conflict, and resulted in workarounds like:

  - Defining UART0 to refer to the USB-CDC interface (atsamd21,
    atsamd51, nrf52840), even though that clearly isn't an UART.
  - Defining NRF_UART0 to avoid a conflict with UART0 (which was
    redefined as a USB-CDC interface).
  - Defining aliases like UART0 = UART1, which refer to the same
    hardware peripheral (stm32).

This commit changes this to use a new machine.Serial object for the
default serial port. It might refer to the first or second UART
depending on the board, or even to the USB-CDC interface. Also, UART0
now really refers to the first UART on the chip, no longer to a USB-CDC
interface.

The changes in the runtime package are all just search+replace. The
changes in the machine package are a mixture of search+replace and
manual modifications.

This commit does not affect binary size, in fact it doesn't affect the
resulting binary at all.
2021-05-13 16:43:37 +02:00
Ayke van Laethem aa5b8d0df7 machine: make UART objects pointer receivers
This means that machine.UART0, machine.UART1, etc are of type
*machine.UART, not machine.UART. This makes them easier to pass around
and avoids surprises when they are passed around by value while they
should be passed around by reference.

There is a small code size impact in some cases, but it is relatively
minor.
2021-05-13 16:43:37 +02:00
Ayke van Laethem 7c949ad386 machine: make USBCDC global a pointer
Make the USBCDC use a pointer receiver everywhere. This makes it easier
to pass around the object in the future.

This commit sometimes changes code size, but not significantly (a few
bytes) and usually in a positive way.

My eventual goal is the following:

  - Declare `machine.USB` (or similar, name TBD) as a pointer receiver
    for the USB-CDC interface.
  - Let `machine.UART0` always point to an UART, never actually to a
    USBCDC object.
  - Define `machine.Serial`, which is either a real UART or an USB-CDC,
    depending on the board.

This way, if you want a real UART you can use machine.UARTx and if you
just want to print to the default serial port, you can use
machine.Serial.

This change does have an effect on code size and memory consumption.
There is often a small reduction (-8 bytes) in RAM consumption and an
increase in flash consumption.
2021-05-13 16:43:37 +02:00
sago35 1646326164 Update README.md 2021-05-12 12:22:08 +02:00
Ayke van Laethem e44cb7e519 main: version 0.18.0 2021-05-12 07:23:49 +02:00
Ayke van Laethem d1e96fd0a8 wasm: scan globals conservatively
Make the GC globals scan phase conservative instead of precise on
WebAssembly. This reduces code size at the risk of introducing some
false positives.

This is a stopgap measure to mitigate an issue with the precise scanning
of globals that doesn't track all pointers. It works for regular globals
but globals created in the interp package don't always have a type and
therefore may be missed by the AddGlobalsBitmap pass.
The same issue is present on Linux and macOS, but is not as noticeable
there.
2021-05-11 18:15:36 +02:00
Ayke van Laethem ff5d0c9886 compiler: only check for default stack size with tasks scheduler
With -scheduler=none, there are no goroutines so there is no stack size
anywhere. Therefore, don't check whether the default stack size is set.
2021-05-11 00:17:03 +02:00
Yurii Soldak d7ec9ddcd2 Discover USB ports only
This will ignore f.ex. bluetooth
2021-05-10 13:27:59 +02:00
sago35 e7c6bd3730 atsame5x: add support for CAN 2021-05-10 12:27:10 +02:00
Ayke van Laethem 9f5066aa6f runtime: use the tasks scheduler instead of coroutines
This results in smaller and likely more efficient code. It does require
some architecture specific code for each architecture, but I've kept the
amount of code as small as possible.
2021-05-09 17:40:13 +02:00
Ayke van Laethem 3b24fedf92 compiler: use wasm for tests
The next commit will change the implementation of func values on Linux
as a result of switching to a task-based scheduler. To keep the
compiler/testdata/func.go test working as expected, switch to
WebAssembly tests.
2021-05-09 17:40:13 +02:00
Ayke van Laethem 8cd2a462b9 runtime: remove the asyncScheduler constant
There is no reason to specialize this per chip as it is only ever used
for JavaScript. Not only that, it is causing confusion and is yet
another quirk to learn when porting the runtime to a new
microcontroller.
2021-05-08 23:08:12 +02:00
Ayke van Laethem 25b045d0a7 runtime: improve timers on nrf, and samd chips
This commit improves the timers on various microcontrollers to better
deal with counter wraparound. The result is a reduction in RAM size of
around 12 bytes and a small effect (sometimes positive, sometimes
negative) on flash consumption. But perhaps more importantly: getting
the current time is now interrupt-safe (it previously could result in a
race condition) and the timer will now be correct when the timer isn't
retrieved for a long duration. Before this commit, a call to `time.Now`
more than 8 minutes after the previous call could result in an incorrect
time.

For more details, see:
https://www.eevblog.com/forum/microcontrollers/correct-timing-by-timer-overflow-count/msg749617/#msg749617
2021-05-08 20:59:40 +02:00
Ayke van Laethem 78acbdf0d9 main: match go test output
This commit makes the output of `tinygo test` similar to that of `go
test`. It changes the following things in the process:

  * Running multiple tests in a single command is now possible. They
    aren't paralellized yet.
  * Packages with no test files won't crash TinyGo, instead it logs it
    in the same way the Go toolchain does.
2021-05-06 20:04:16 +02:00
Federico G. Schwindt 617e2791ef Add -llvm-features parameter
With this is possible to enable e.g., SIMD in WASM using -llvm-features
+simd128.  Multiple features can be specified separated by comma,
e.g., -llvm-features +simd128,+tail-call

With help from @deadprogram and @aykevl.
2021-05-06 18:07:14 +02:00
Kenneth Bell a0908ff55b compiler: openocd commands in tinygo command line 2021-05-06 15:09:41 +02:00
Ayke van Laethem 2f1f8fb075 machine: move PinMode to central location
It is always implemented exactly the same way (as an uint8) so there is
no reason to implement it in each target separately.

This also makes it easier to add some documentation to it.
2021-05-06 13:59:12 +02:00
sago35 6f61b83ad5 atsamd21: remove special handling for SPI-24mhz 2021-05-06 10:32:24 +02:00
Dan Kegel 8dfefb46d1 wasi: do not crash if argc is 0
Instead, leave args at its default value (which provides a fake argv[0] as it has for a long time).

linux and mac do not seem affected.

Fixes #1862 (tinygo apps after v0.17.0-113-g7b761fa crash if run without argv[0])
2021-05-05 19:16:28 +02:00
Ayke van Laethem 959442dc82 unix: use conservative GC by default
This commit does two things:

 1. It makes it possible to grow the heap on Linux and MacOS by
    allocating 1GB of virtual memory on startup and then slowly using it
    as necessary, when running out of available heap space.
 2. It switches the default GC to be the conservative GC (previously
    extalloc). This is good for consistency with other platforms that
    all use this same GC.

This makes the extalloc GC unused by default.
2021-05-05 17:20:15 +02:00
Ayke van Laethem c1aa152a63 unix: avoid possible heap allocation with -opt=0
This heap allocation would normally be optimized away, but with -opt=0
perhaps not. This is a problem if the conservative GC is used, because
the conservative GC needs to be initialized before use.
2021-05-05 17:20:15 +02:00
sago35 dd3d8a363a qtpy: fix i2c setting 2021-05-05 10:12:08 +02:00
sago35 bb509ec91d atsamd51, atsamd21: fix ADC.Get() value at 8bit and 10bit 2021-05-05 06:51:09 +02:00
Ayke van Laethem 944f022060 interp: support extractvalue/insertvalue with multiple operands
TinyGo doesn't emit these instructions, but they can occur as a result
of optimizations.
2021-05-04 21:21:56 +02:00
Ayke van Laethem cd517a30af transform: split interface and reflect lowering
These two passes are related, but can definitely work independently.
Which is what this change does: it splits the two passes. This should
make it easier to change these two new passes in the future.

This change now also enables slightly better testing by testing these
two passes independently. In particular, the reflect lowering pass got
some actual tests: it was barely unit-tested before.

I have verified that this doesn't really change code size, at least not
on the microbit target. Two tests do change, but in a very minor way
(and in opposite direction).
2021-05-03 20:10:49 +02:00
Olivier Fauchon 52d8655eec Patch Cleanup 2021-05-03 18:16:46 +02:00
Olivier Fauchon f5786941e5 Fix bad I2C0/I2C1 declaration 2021-05-03 18:16:46 +02:00
Ayke van Laethem 1f73941c43 ci: bump Xcode version to use macOS 10.14
The CircleCI macOS builds are failing, probably due to the old macOS
version that's used. This version (10.13 High Sierra) isn't supported
anymore on Homebrew so it seems best to me to simply bump the version.

I picked Xcode 11.1.0 because 10.3.0 is somehow triggering an error
while trying to install QEMU (the Python install fails).

Because of this newer Xcode version, I had to add an extra flag
(-isysroot) to the default command line for MacOS. The reason is that
this newer Xcode version no longer stores header files in /usr/local, an
SDK must be specified manually. With this change, the default SDK is
used.
2021-05-02 23:55:10 +02:00
Raqbit abeab51d00 Add Arduino Nano w/ New Bootloader target
Since 2018, Arduino Nanos and clones are sold with a new bootloader, which
requires programming at 115200 baud instead of the 57600 baud required
by the old one.
2021-05-01 17:09:46 +02:00
sago35 9ef75f17bf atsamd51, atsame5x: unify samd51 and same5x 2021-04-29 09:20:44 +02:00
Ayke van Laethem c3992bd77b compiler: improve position information
In many cases, position information is not stored in Go SSA instructions
because they don't exit directly in the source code. This includes
implicit type conversions, implicit returns at the end of a function,
the creation of a (hidden) slice when calling a variadic function, and
many other cases. I'm not sure where this information is supposed to
come from, but this patch takes the value (usually) from the value the
instruction refers to. This seems to work well for these implicit
conversions.

I've also added a few extra tests to the heap-to-stack transform pass,
of which one requires this improved position information.
2021-04-26 16:15:57 +02:00
Ayke van Laethem f79e66ac2e cortexm: disable FPU on Cortex-M4
On some boards the FPU is already enabled on startup, probably as part
of the bootloader. On other chips it was enabled as part of the runtime
startup code. In all these cases, enabling the FPU is currently
unsupported: the automatic stack sizing of goroutines assumes that the
processor won't need to reserve space for FPU registers. Enabling the
FPU therefore can lead to a stack overflow.

This commit either removes the code that enables the FPU, or simply
disables it in startup code. A future change should fully enable the FPU
so that operations on float32 can be performed by the FPU instead of in
software, greatly speeding up such code.
2021-04-24 18:41:40 +02:00
Ayke van Laethem 4eac212695 gen-device: add extra constants and rename them to be Go style
- Add some extra fields: FPUPresent, CPU and NVICPrioBits which may
    come in handy at a later time (and are easy to add).
  - Rename DEVICE to Device, to match Go style.

This is in preparation to the next commit, which requires the FPUPresent
flag.
2021-04-24 18:41:40 +02:00
deadprogram b661882391 machine/usbcdc: remove remaining heap allocations for USB CDC implementations
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-04-23 23:37:24 +02:00
Ayke van Laethem 321488dcfe machine: avoid heap allocations in USB code
This commit replaces most heap allocations in USB related code with
stack allocations. This is important for several reasons:

  - It avoids running the GC unnecessarily.
  - It reduces code size by 400-464 bytes.
  - USB code might be called from interrupt handlers. The heap may be in
    an inconsistent state when that happens if main thread code also
    performs heap allocations.

The last one is by far the most important one: not doing heap
allocations in interrupts is critical for correctness. But the code size
reduction alone should be worth it.

There are two heap allocations in USB related code left: in the function
receiveUSBControlPacket (SAMD21 and SAMD51). This heap allocation must
also be removed because it runs in an interrupt, but I've left that for
a future change.
2021-04-23 23:37:24 +02:00
Ayke van Laethem 80caf2dab2 copiler: add function attributes to some runtime calls
This allows better escape analysis even without being able to see the
entire program. This makes the stack allocation test case more complete
but probably won't have much of an effect outside of that (as the
compiler is able to infer these attributes in the whole-program
functionattrs pass).
2021-04-22 19:53:42 +02:00
Ayke van Laethem c466465c32 main: add -print-allocs flag that lets you print all heap allocations
This flag, if set, is a regexp for function names. If there are heap
allocations in the matching function names, these heap allocations will
be printed with an explanation why the heap allocation exists (and why
the object can't be stack allocated).
2021-04-22 19:53:42 +02:00
Ayke van Laethem 404b65941a transform: move tests to transform_test package
This allows for adding more advanced tests, for example tests that use
the compiler package so that test sources can be written in Go instead
of LLVM IR.
2021-04-22 19:53:42 +02:00
Kenneth Bell 25f3adb47e stm32: support SPI on L4 series 2021-04-21 21:09:41 +02:00
sago35 b9043b649d atsamd51: fix PWM support in atsamd51p20
This change is related to the following commit
72acda22b0
2021-04-21 15:02:47 +02:00
Ayke van Laethem 7b761fac78 runtime: implement command line arguments in hosted environments
Implement command line arguments for Linux, MacOS and WASI.
2021-04-21 10:32:09 +02:00
Ayke van Laethem c47cdfa66f runtime: implement environment variables for Linux 2021-04-21 10:32:09 +02:00
Ayke van Laethem 768a15c1dd interp: remove map support
The interp package is in many cases able to execute map functions in the
runtime directly. This is probably slower than adding special support
for them in the interp package and also doesn't cover all cases (most
importantly, map keys that contain pointers) but removing this code also
removes a large amount of code that needs to be maintained and is
susceptible to hard-to-find bugs.

As a side effect, this resulted in different output of the
testdata/map.go test because the test relied on the existing iteration
order of TinyGo maps. I've updated the test to not rely on this test,
making the output compatible with what the Go toolchain would output.
2021-04-21 07:37:22 +02:00
Ayke van Laethem c1c3be1aa7 interp: fix phi instruction
I've discovered a bug in the implementation of the PHI instruction in
the interp package. This commit fixes the bug.

I've found this issue while investigating an issue with maps after
running interp per package.
2021-04-21 07:37:22 +02:00
sago35 b2e72c96f4 ci: improve llvm-build cache 2021-04-19 17:24:52 +02:00
Ayke van Laethem f706219996 builder: hard code Clang compiler
At the moment, all targets use the Clang compiler to compile C and
assembly files. There is no good reason to make this configurable
anymore and in fact it will make future changes more complicated (and
thus more likely to have bugs). Therefore, I've removed support for
setting the compiler.

Note that the same is not true for the linker. While it makes sense to
standardize on the Clang compiler (because if Clang doesn't support a
target, TinyGo is unlikely to support it either), linkers will remain
configurable for the foreseeable future. One example is Xtensa, which is
supported by the Xtensa LLVM fork but doesn't have support in ld.lld
yet.

I've also fixed a bug in compileAndCacheCFile: it wasn't using the right
CFlags for caching purposes. This could lead to using stale caches. This
commit fixes that too.
2021-04-19 13:14:33 +02:00
sago35 6152a661e8 ci: improve llvm-source cache 2021-04-19 00:55:42 +02:00
Dan Kegel f1a5743f77 Make fmt-check happy again 2021-04-17 00:01:37 +02:00
sago35 9f52fe4e4a atsame51: add initial support for feather-m4-can 2021-04-16 17:49:46 +02:00
developer cb886a35c9 PWM Support for atmega1280
Add arduino mega 1280 PWM test
2021-04-16 17:47:31 +02:00
Tobias Theel 5707022951 add goroot for snap installs 2021-04-15 17:34:21 +02:00
sago35 bd212cc000 atsame54: add initial support for atsame54-xpro 2021-04-15 15:43:37 +02:00
Ayke van Laethem 6dd5666ed1 wasm: use WASI ABI for exit function
This improves compatibility between the regular browser target
(-target=wasm) and the WASI target (-target=wasi). Specifically, it
allows running WASI tests like this:

    tinygo test -target=wasi encoding/base32
2021-04-15 08:45:08 +02:00
Ayke van Laethem f145663464 cortexm: add __isr_vector symbol
This doesn't change the firmware, but it does make the disassembly of
the ELF files. Before:

    Disassembly of section .text:

    00000000 <(machine.UART).Write-0x100>:
           0:       20001000        .word   0x20001000
           4:       000009db        .word   0x000009db
           8:       00000f05        .word   0x00000f05
           c:       00000f0b        .word   0x00000f0b
          10:       00000f05        .word   0x00000f05

After:

    Disassembly of section .text:

    00000000 <__isr_vector>:
           0:       20001000        .word   0x20001000
           4:       000009db        .word   0x000009db
           8:       00000f05        .word   0x00000f05
           c:       00000f0b        .word   0x00000f0b
          10:       00000f05        .word   0x00000f05

The difference is that the disassembler will now use a proper symbol name
instead of using the closest by symbol (in this case, (machine.UART).Write).
This makes the disassembly easier to read.
2021-04-15 07:38:52 +02:00
Ayke van Laethem 0d66475e10 nrf52833: add PWM support
This chip wasn't included in the PR for PWM support. Adding this support
is very easy, luckily.
2021-04-14 23:42:02 +02:00
Ayke van Laethem 22b143eba8 microbit-v2: add support for S113 SoftDevice
This currently doesn't work with `tinygo flash` yet (even with
`-programmer=openocd`), you can use pyocd instead. For example, from the
Bluetooth package:

    tinygo build -o test.hex -target=microbit-v2-s113v7 ./examples/advertisement/
    pyocd flash --target=nrf52 test.hex

I intend to add support for pyocd to work around this issue, so that a simple
`tinygo flash` suffices.
2021-04-14 22:55:52 +02:00
Ayke van Laethem 3fe13a72bd microbit: remove LED constant
There doesn't appear to be a user-controllable LED outside of the LED
matrix. In fact, the pin assigned for this was P13, which was connected
to the SPI SCK pin.
2021-04-14 17:40:32 +02:00
Ayke van Laethem d919905c96 all: clean up Cortex-M target files
In this commit I've moved all core-specific flags to files for that
specific core. This is a bit of a cleanup (less duplicated JSON) but
should also help in the future when core-specific changes are made, such
as core specific build tags or when the FPU finally gets supported in
TinyGo.

Some notable specific changes:

  - I've removed floating point flags from the Teensy 3.6 target. The
    reason is that the FPU is not yet supported in TinyGo (in goroutine
    stack switching for example) and floating point numbers would only
    be supported by C files, not Go files (because the LLVM FPU feature
    flags aren't used). This would create an ABI mismatch across CGo.
  - I've added the "cpu":"cortex-m7" to the cortex-m7.json file to match
    the configuration for the Teensy 4.0. This implies a change to the
    nucleo-f722ze (because now it has its CPU field set). Somehow that
    reduces the code size, so it looks like a good change.

I don't believe any of these changes should have any practical
consequences.

One issue I've found is in the Cortex-M33 target: it uses armv7m, which
is incorrect: it should be armv8m. But the chip is backwards compatible
so this should mostly work. Switching to armv8m led to a compilation
failure because PRIMASK isn't defined, this may be an actual bug.
2021-04-14 09:17:54 +02:00
Ayke van Laethem 96b1b76483 all: use -Qunused-arguments only for assembly files
The -Qunused-arguments flag disables the warning where some flags are
not relevant to a compilation. This commonly happens when compiling
assembly files (.s or .S files) because some flags are specific to C and
not relevant to assembly.
Because practically all baremetal targets need some form of assembly,
this flag is added to most CFlags. This creates a lot of noise. And it
is also added for compiling C code where it might hide bugs (by hiding
the fact a flag is actually unused).

This commit adds the flag to all assembly compilations and removes them
from all target JSON files.
2021-04-14 09:17:54 +02:00
sago35 f234df7a50 cmsis-svd: add svd file for the atsame5x 2021-04-14 06:39:36 +02:00
Agurato e6d5c26df5 Fix RGBA color interpretation for GameBoyAdvance 2021-04-13 18:51:14 +02:00
Kenneth Bell ae59e7703e stm32: make SPI CLK fast to fix data issue
See "STM32F40x and STM32F41x Errata sheet" - SPI CLK port must be 'fast' or 'very fast' to avoid data corruption on last bit (at the APB clocks we configure).
2021-04-13 07:38:30 +02:00
Ayke van Laethem e587b1d1b4 reflect: implement New function
This is very important for some use cases, for example for Vecty.
2021-04-12 14:49:26 +02:00
Ayke van Laethem 57271d7eaa compiler: decouple func lowering from interface type codes
There is no good reason for func values to refer to interface type
codes. The only thing they need is a stable identifier for function
signatures, which is easily created as a new kind of globals. Decoupling
makes it easier to change interface related code.
2021-04-12 12:07:42 +02:00
Ayke van Laethem 8383552552 compiler: add func tests
This is basically just a golden test for the "switch" style of func
lowering. The next commit will make changes to this lowering, which will
be visible in the test output.
2021-04-12 12:07:42 +02:00
developer aa8e12c464 Arduino Mega 1280 support
Fix ldflags

Update targets/arduino-mega1280.json

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

Update atmega1280.json

Update Makefile
2021-04-12 11:03:13 +02:00
Ayke van Laethem e7a05b6e74 transform: do not lower zero-sized alloc to alloca
The LLVM CoroFrame pass appears to be tripping over this zero-sized
alloca. Therefore, do what the runtime would do: return a pointer to
runtime.zeroSizedAlloc. Or just don't deal with this case. But don't
emit a zero sized alloca to avoid this LLVM bug.

More information: https://bugs.llvm.org/show_bug.cgi?id=49916
2021-04-12 08:11:28 +02:00
Ayke van Laethem 2fd8f103ab transform: fix func lowering assertion failure
The func-lowering pass has started to fail in the dev branch, probably
as a result of replacing the ConstPropagation pass with the IPSCCP pass.
This commit makes the code a bit more robust and should be able to
handle all possible cases (not just ptrtoint).
2021-04-12 08:11:28 +02:00
Ayke van Laethem 33f76d1c2e main: implement -ldflags="-X ..."
This commit implements replacing some global variables with a different
value, if the global variable has no initializer. For example, if you
have:

    package main

    var version string

you can replace the value with -ldflags="-X main.version=0.2".

Right now it only works for uninitialized globals. The Go tooling also
supports initialized globals (var version = "<undefined>") but that is a
bit hard to combine with how initialized globals are currently
implemented.

The current implementation still allows caching package IR files while
making sure the values don't end up in the build cache. This means
compiling a program multiple times with different values will use the
cached package each time, inserting the string value only late in the
build process.

Fixes #1045
2021-04-09 18:33:48 +02:00
Ayke van Laethem ea8f7ba1f9 main: add tests for less common build configurations
Don't run the entire test suite for these options, as that would quickly
explode the testing time (making it less likely people actually run it).
Instead, run just one test for each configuration that should check for
most issues.
2021-04-09 18:33:48 +02:00
Ayke van Laethem 0ffe5ac2fa main: clean up tests
- Explicitly list all test cases. This makes it possible to store
    tests in testdata/ that aren't tested on all platforms.
  - Clean up filesystem and env test, by running them in a subtest and
    deduplicating some code and removing the additionalArgs parameter.
2021-04-09 18:33:48 +02:00
Ayke van Laethem 7bac93aab3 main: remove -cflags and -ldflags flags
These are unnecessary now that they are supported in CGo.
2021-04-09 18:33:48 +02:00
Ayke van Laethem b61751e429 compiler: check for errors
Some errors were generated but never returned or never checked in the
test function. That's a problem. Therefore this commit fixes this
oversight (by me).
2021-04-09 14:05:44 +02:00
Ayke van Laethem 25dac32a88 transform: use IPSCCP pass instead of the constant propagation pass
The constant propagation pass is removed in LLVM 12, so this pass needs
to be replaced anyway. The direct replacement would be the SCCP (sparse
conditional constant propagation) pass, but perhaps a better replacement
is the IPSCCP pass, which is an interprocedural version of the SCCP
pass and propagates constants across function calls if possible.

This is not always a code size reduction, but it appears to reduce code
size in a majority of cases. It certainly reduces code size in almost
all WebAssembly tests I did.
2021-04-08 12:31:26 +02:00
Ayke van Laethem 56cf69a66b builder: run function passes per package
This should result in a small compile time reduction for incremental
builds, somewhere around 5-9%.

This commit, while small, required many previous commits to not regress
binary size. Right now binary size is basically identical with very few
changes in size (the only baremetal program that changed in size did so
with a 4 byte increase).

This commit is one extra step towards doing as much work as possible in
the parallel and cached package build step, out of the serial LTO phase.
Later improvements in this area have this change as a prerequisite.
2021-04-08 11:40:59 +02:00
Ayke van Laethem 04d12bf2ba interp: add support for switch statement
A switch statement is not normally emitted by the compiler package, but
LLVM function passes may convert a series of if/else pairs to a switch
statement. A future change will run function passes in the package
compile phase, so the interp package (which is also run after all
modules are merged together) will need to deal with these new switch
statements.
2021-04-08 11:40:59 +02:00
Ayke van Laethem 0b7957d612 compiler: optimize string literals and globals
This commit optimizes string literals and globals by setting the
appropriate alignment and using a nil pointer in zero-length strings.

  - Setting the alignment for string values has a surprisingly large
    effect, up to around 2% in binary size. I suspect that LLVM will
    pick some default alignment for larger byte arrays if no alignment
    has been specified and forcing an alignment of 1 will pack all
    strings closer together.
  - Using nil for zero-length strings also has a positive effect, but
    I'm not sure why. Perhaps it makes some optimizations more trivial.
  - Always setting the alignment on globals improves code size slightly,
    probably for the same reasons setting the alignment of string
    literals improves code size. The effect is much smaller, however.

This commit might have an effect on performance, but if it does this
should be tested separately and such a large win in binary size should
definitely not be ignored for small embedded systems.
2021-04-08 11:40:59 +02:00
Ayke van Laethem 61243f6c57 transform: don't rely on struct name of runtime.typecodeID
Sometimes, LLVM may rename named structs when merging modules.
Therefore, we can't rely on typecodeID structs to retain their struct
names.

This commit changes the interface lowering pass to not rely on these
names. The interp package does however still rely on this name, but I
hope to fix that in the future.
2021-04-08 11:40:59 +02:00
Ayke van Laethem 49ec3eb58e builder: add optsize attribute while building the package
This simplifies future changes. While the move itself is very simple, it
required some other changes to a few transforms that create new
functions to add the optsize attribute manually. It also required
abstracting away the optimization level flags (based on the -opt flag)
so that it can easily be retrieved from the config object.

This commit does not impact binary size on baremetal and WebAssembly.
I've seen a few tests on linux/amd64 grow slightly in size, but I'm not
too worried about those.
2021-04-08 11:40:59 +02:00
sago35 fa6c1b69ce build: improve error messages in getDefaultPort(), support for multiple ports 2021-04-08 10:32:20 +02:00
deadprogram 1e9a41dc94 modules: add latest go-llvm because seems like older SHA is missing?
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-04-07 18:10:43 +02:00
Kenneth Bell a30671751f stm32: add nucleo-l031k6 support
Adds i2c for all L0 series

UART, Blinky (LED) and i2c tested
2021-04-07 17:20:19 +02:00
Ayke van Laethem c246978dd7 ci: limit test runs of assert-test-linux to two jobs
Instead of the regular build, it's the `make test` line that fails due
to OOM. This is because testing means that a lot of test binaries need
to be built while the regular build only needs to link one binary.

This improves https://github.com/tinygo-org/tinygo/pull/1774 and should
hopefully actually fix the OOM errors.
2021-04-07 08:08:40 +02:00
Ayke van Laethem 72acda22b0 machine: refactor PWM support
This commit refactors PWM support in the machine package to be more
flexible. The new API can be used to produce tones at a specific
frequency and control servos in a portable way, by abstracting over
counter widths and prescalers.
2021-04-06 20:36:10 +02:00
1275 changed files with 97522 additions and 24183 deletions
+65 -342
View File
@@ -6,395 +6,118 @@ commands:
- run:
name: "Pull submodules"
command: git submodule update --init
apt-dependencies:
parameters:
llvm:
type: string
steps:
- run:
name: "Install apt dependencies"
command: |
echo 'deb https://apt.llvm.org/buster/ llvm-toolchain-buster-<<parameters.llvm>> 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 \
llvm-<<parameters.llvm>>-dev \
clang-<<parameters.llvm>> \
libclang-<<parameters.llvm>>-dev \
lld-<<parameters.llvm>> \
gcc-arm-linux-gnueabihf \
gcc-aarch64-linux-gnu \
qemu-system-arm \
qemu-user \
gcc-avr \
avr-libc
sudo apt-get install --no-install-recommends libc6-dev-i386 lib32gcc-8-dev
install-node:
steps:
- run:
name: "Install node.js"
command: |
wget https://nodejs.org/dist/v10.15.1/node-v10.15.1-linux-x64.tar.xz
sudo tar -C /usr/local -xf node-v10.15.1-linux-x64.tar.xz
sudo ln -s /usr/local/node-v10.15.1-linux-x64/bin/node /usr/bin/node
rm node-v10.15.1-linux-x64.tar.xz
install-chrome:
steps:
- run:
name: "Install Chrome"
command: |
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb
install-wasmtime:
steps:
- run:
name: "Install wasmtime"
command: |
curl https://wasmtime.dev/install.sh -sSf | bash
sudo ln -s ~/.wasmtime/bin/wasmtime /usr/local/bin/wasmtime
install-xtensa-toolchain:
parameters:
variant:
type: string
steps:
- run:
name: "Install Xtensa toolchain"
command: |
curl -L https://github.com/espressif/crosstool-NG/releases/download/esp-2020r2/xtensa-esp32-elf-gcc8_2_0-esp-2020r2-<<parameters.variant>>.tar.gz -o xtensa-esp32-elf-gcc8_2_0-esp-2020r2-<<parameters.variant>>.tar.gz
sudo tar -C /usr/local -xf xtensa-esp32-elf-gcc8_2_0-esp-2020r2-<<parameters.variant>>.tar.gz
sudo ln -s /usr/local/xtensa-esp32-elf/bin/xtensa-esp32-elf-ld /usr/local/bin/xtensa-esp32-elf-ld
rm xtensa-esp32-elf-gcc8_2_0-esp-2020r2-<<parameters.variant>>.tar.gz
llvm-source-linux:
steps:
- restore_cache:
keys:
- llvm-source-11-v1
- llvm-source-18-v1
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-11-v1
key: llvm-source-18-v1
paths:
- llvm-project
build-wasi-libc:
- llvm-project/clang/lib/Headers
- llvm-project/clang/include
- llvm-project/compiler-rt
- llvm-project/lld/include
- llvm-project/llvm/include
hack-ninja-jobs:
steps:
- run:
name: "Hack Ninja to use less jobs"
command: |
echo -e '#!/bin/sh\n/usr/bin/ninja -j3 "$@"' > /go/bin/ninja
chmod +x /go/bin/ninja
build-binaryen-linux:
steps:
- restore_cache:
keys:
- wasi-libc-sysroot-v4
- binaryen-linux-v3
- run:
name: "Build wasi-libc"
command: make wasi-libc
name: "Build Binaryen"
command: |
make binaryen
- save_cache:
key: wasi-libc-sysroot-v4
key: binaryen-linux-v3
paths:
- lib/wasi-libc/sysroot
- build/wasm-opt
test-linux:
parameters:
llvm:
type: string
fmt-check:
type: boolean
default: true
steps:
- checkout
- submodules
- apt-dependencies:
llvm: "<<parameters.llvm>>"
- install-node
- install-chrome
- install-wasmtime
- run:
name: "Install apt dependencies"
command: |
echo 'deb https://apt.llvm.org/bullseye/ llvm-toolchain-bullseye-<<parameters.llvm>> main' > /etc/apt/sources.list.d/llvm.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
apt-get update
apt-get install --no-install-recommends -y \
llvm-<<parameters.llvm>>-dev \
clang-<<parameters.llvm>> \
libclang-<<parameters.llvm>>-dev \
lld-<<parameters.llvm>> \
cmake \
ninja-build
- hack-ninja-jobs
- build-binaryen-linux
- restore_cache:
keys:
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-v2-{{ checksum "go.mod" }}
- go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-v4-{{ checksum "go.mod" }}
- llvm-source-linux
- run: go install -tags=llvm<<parameters.llvm>> .
- restore_cache:
keys:
- wasi-libc-sysroot-systemclang-v3
- wasi-libc-sysroot-systemclang-v7
- run: make wasi-libc
- save_cache:
key: wasi-libc-sysroot-systemclang-v3
key: wasi-libc-sysroot-systemclang-v7
paths:
- lib/wasi-libc/sysroot
- run: go test -v -tags=llvm<<parameters.llvm>> ./cgo ./compileopts ./compiler ./interp ./transform .
- when:
condition: <<parameters.fmt-check>>
steps:
- run:
# Do this before gen-device so that it doesn't check the
# formatting of generated files.
name: Check Go code formatting
command: make fmt-check lint
- run: make gen-device -j4
- run: make smoketest XTENSA=0
- run: make tinygo-test
- run: make wasmtest
- save_cache:
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths:
- ~/.cache/go-build
- /go/pkg/mod
- run: make fmt-check
assert-test-linux:
steps:
- checkout
- submodules
- run:
name: "Install apt dependencies"
command: |
sudo apt-get update
sudo apt-get install \
gcc-arm-linux-gnueabihf \
libc6-dev-armel-cross \
gcc-aarch64-linux-gnu \
libc6-dev-arm64-cross \
qemu-system-arm \
qemu-user \
gcc-avr \
avr-libc
sudo apt-get install --no-install-recommends libc6-dev-i386 lib32gcc-6-dev
- install-node
- install-wasmtime
- install-xtensa-toolchain:
variant: "linux-amd64"
- restore_cache:
keys:
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-v2-{{ checksum "go.mod" }}
- llvm-source-linux
- restore_cache:
keys:
- llvm-build-11-linux-v2-assert
- run:
name: "Build LLVM"
command: |
if [ ! -f llvm-build/lib/liblldELF.a ]
then
# install dependencies
sudo apt-get install cmake ninja-build
# hack ninja to use less jobs
echo -e '#!/bin/sh\n/usr/bin/ninja -j3 "$@"' > /go/bin/ninja
chmod +x /go/bin/ninja
# build!
make ASSERT=1 llvm-build
fi
- save_cache:
key: llvm-build-11-linux-v2-assert
paths:
llvm-build
- run: |
# Note: -p=2 limits parallelism to two jobs at a time, which is
# necessary to keep memory consumption down and avoid OOM (for a
# 2CPU/4GB executor).
GOFLAGS="-p=2" make ASSERT=1
- build-wasi-libc
- run:
name: "Test TinyGo"
command: make ASSERT=1 test
- save_cache:
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths:
- ~/.cache/go-build
- /go/pkg/mod
- run: make gen-device -j4
- run: make smoketest TINYGO=build/tinygo
build-linux:
steps:
- checkout
- submodules
- run:
name: "Install apt dependencies"
command: |
sudo apt-get update
sudo apt-get install \
gcc-arm-linux-gnueabihf \
libc6-dev-armel-cross \
gcc-aarch64-linux-gnu \
libc6-dev-arm64-cross \
qemu-system-arm \
qemu-user \
gcc-avr \
avr-libc
sudo apt-get install --no-install-recommends libc6-dev-i386 lib32gcc-6-dev
- install-node
- install-wasmtime
- install-xtensa-toolchain:
variant: "linux-amd64"
- restore_cache:
keys:
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-v2-{{ checksum "go.mod" }}
- llvm-source-linux
- restore_cache:
keys:
- llvm-build-11-linux-v2-noassert
- run:
name: "Build LLVM"
command: |
if [ ! -f llvm-build/lib/liblldELF.a ]
then
# install dependencies
sudo apt-get install cmake ninja-build
# hack ninja to use less jobs
echo -e '#!/bin/sh\n/usr/bin/ninja -j3 "$@"' > /go/bin/ninja
chmod +x /go/bin/ninja
# build!
make llvm-build
fi
- save_cache:
key: llvm-build-11-linux-v2-noassert
paths:
llvm-build
- build-wasi-libc
- run:
name: "Test TinyGo"
command: make test
- run:
name: "Install fpm"
command: |
sudo apt-get install ruby ruby-dev
sudo gem install --no-document fpm
- run:
name: "Build TinyGo release"
command: |
make release deb -j3
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
cp -p build/release.deb /tmp/tinygo_amd64.deb
- store_artifacts:
path: /tmp/tinygo.linux-amd64.tar.gz
- store_artifacts:
path: /tmp/tinygo_amd64.deb
- save_cache:
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths:
- ~/.cache/go-build
- /go/pkg/mod
- run:
name: "Extract release tarball"
command: |
mkdir -p ~/lib
tar -C ~/lib -xf /tmp/tinygo.linux-amd64.tar.gz
ln -s ~/lib/tinygo/bin/tinygo /go/bin/tinygo
tinygo version
- run: make smoketest
build-macos:
steps:
- checkout
- submodules
- run:
name: "Install dependencies"
command: |
curl https://dl.google.com/go/go1.16.darwin-amd64.tar.gz -o go1.16.darwin-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.16.darwin-amd64.tar.gz
ln -s /usr/local/go/bin/go /usr/local/bin/go
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu
- install-xtensa-toolchain:
variant: "macos"
- restore_cache:
keys:
- go-cache-macos-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-macos-v2-{{ checksum "go.mod" }}
- restore_cache:
keys:
- llvm-source-11-macos-v1
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-11-macos-v1
paths:
- llvm-project
- restore_cache:
keys:
- llvm-build-11-macos-v2
- run:
name: "Build LLVM"
command: |
if [ ! -f llvm-build/lib/liblldELF.a ]
then
# install dependencies
HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake ninja
# build!
make llvm-build
fi
- save_cache:
key: llvm-build-11-macos-v2
paths:
llvm-build
- restore_cache:
keys:
- wasi-libc-sysroot-macos-v3
- run:
name: "Build wasi-libc"
command: make wasi-libc
- save_cache:
key: wasi-libc-sysroot-macos-v3
paths:
- lib/wasi-libc/sysroot
- run:
name: "Test TinyGo"
command: make test
- run:
name: "Build TinyGo release"
command: |
make release -j3
cp -p build/release.tar.gz /tmp/tinygo.darwin-amd64.tar.gz
- store_artifacts:
path: /tmp/tinygo.darwin-amd64.tar.gz
- run:
name: "Extract release tarball"
command: |
mkdir -p ~/lib
tar -C /usr/local/opt -xf /tmp/tinygo.darwin-amd64.tar.gz
ln -s /usr/local/opt/tinygo/bin/tinygo /usr/local/bin/tinygo
tinygo version
- run: make smoketest AVR=0
- save_cache:
key: go-cache-macos-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
key: go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths:
- ~/.cache/go-build
- /go/pkg/mod
jobs:
test-llvm10-go113:
test-llvm15-go119:
docker:
- image: circleci/golang:1.13-buster
- image: golang:1.19-bullseye
steps:
- test-linux:
llvm: "10"
test-llvm10-go114:
llvm: "15"
resource_class: large
test-llvm18-go122:
docker:
- image: circleci/golang:1.14-buster
- image: golang:1.22-bullseye
steps:
- test-linux:
llvm: "10"
test-llvm11-go115:
docker:
- image: circleci/golang:1.15-buster
steps:
- test-linux:
llvm: "11"
test-llvm11-go116:
docker:
- image: circleci/golang:1.16-buster
steps:
- test-linux:
llvm: "11"
assert-test-linux:
docker:
- image: circleci/golang:1.14-stretch
steps:
- assert-test-linux
build-linux:
docker:
- image: circleci/golang:1.14-stretch
steps:
- build-linux
build-macos:
macos:
xcode: "10.1.0"
steps:
- build-macos
llvm: "18"
resource_class: large
workflows:
test-all:
jobs:
- test-llvm10-go113
- test-llvm10-go114
- test-llvm11-go115
- test-llvm11-go116
- build-linux
- build-macos
- assert-test-linux
# 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 18 support when linking against system libraries.
- test-llvm18-go122
+5
View File
@@ -0,0 +1,5 @@
build/
llvm-*/
.github
.circleci
+159
View File
@@ -0,0 +1,159 @@
name: macOS
on:
pull_request:
push:
branches:
- dev
- release
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-macos:
name: build-macos
strategy:
matrix:
# macos-12: amd64 (oldest supported version as of 05-02-2024)
# macos-14: arm64 (oldest arm64 version)
os: [macos-12, macos-14]
include:
- os: macos-12
goarch: amd64
- os: macos-14
goarch: arm64
runs-on: ${{ matrix.os }}
steps:
- name: Install Dependencies
shell: bash
run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true
- name: Restore LLVM source cache
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-18-${{ matrix.os }}-v2
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save LLVM source cache
uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Restore LLVM build cache
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-18-${{ matrix.os }}-v2
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
shell: bash
run: |
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# install dependencies
HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake ninja
# build!
make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache
uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
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
shell: bash
run: make test GOTESTFLAGS="-short"
- name: Build TinyGo release tarball
run: make release -j3
- name: Test stdlib packages
run: make tinygo-test
- name: Make release artifact
shell: bash
run: cp -p build/release.tar.gz build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
- name: Publish release artifact
# Note: this release artifact is double-zipped, see:
# https://github.com/actions/upload-artifact/issues/39
# We can essentially pick one of these:
# - have a double-zipped artifact when downloaded from the UI
# - have a very slow artifact upload
# We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v4
with:
name: darwin-${{ matrix.goarch }}-double-zipped
path: build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
- name: Smoke tests
shell: bash
run: make smoketest TINYGO=$(PWD)/build/tinygo
test-macos-homebrew:
name: homebrew-install
runs-on: macos-latest
strategy:
matrix:
version: [16, 17, 18]
steps:
- name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@master
- name: Fix Python symlinks
run: |
# Github runners have broken symlinks, so relink
# see: https://github.com/actions/setup-python/issues/577
brew list -1 | grep python | while read formula; do brew unlink $formula; brew link --overwrite $formula; done
- name: Install LLVM
run: |
brew install llvm@${{ matrix.version }}
- name: Checkout
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
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 == 18
run: go install
- name: Check binary
if: matrix.version == 18
run: tinygo version
+110
View File
@@ -0,0 +1,110 @@
# This is the Github action to build and push the tinygo/tinygo-dev Docker image.
# If you are looking for the tinygo/tinygo "release" Docker image please see
# https://github.com/tinygo-org/docker
#
name: Docker
on:
push:
branches: [ dev, fix-docker-llvm-build ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
push_to_registry:
name: build-push-dev
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Free Disk space
shell: bash
run: |
df -h
sudo rm -rf /opt/hostedtoolcache
sudo rm -rf /usr/local/lib/android
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf /usr/local/graalvm
sudo rm -rf /usr/local/share/boost
df -h
- name: Check out the repo
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
tinygo/tinygo-dev
ghcr.io/${{ github.repository_owner }}/tinygo-dev
tags: |
type=sha,format=long
type=raw,value=latest
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Trigger Drivers repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/drivers/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger Bluetooth repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/bluetooth/actions/workflows/linux.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger TinyFS repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/tinyfs/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger TinyFont repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/tinyfont/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger TinyDraw repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/tinydraw/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
- name: Trigger TinyTerm repo build on Github Actions
run: |
curl -X POST \
-H "Authorization: Bearer ${{secrets.GHA_ACCESS_TOKEN}}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tinygo-org/tinyterm/actions/workflows/build.yml/dispatches \
-d '{"ref": "dev"}'
+400
View File
@@ -0,0 +1,400 @@
name: Linux
on:
pull_request:
push:
branches:
- dev
- release
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-linux:
# Build Linux binaries, ready for release.
# This runs inside an Alpine Linux container so we can more easily create a
# statically linked binary.
runs-on: ubuntu-latest
container:
image: golang:1.22-alpine
steps:
- name: Install apk dependencies
# 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
- 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"
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true
- name: Cache Go
uses: actions/cache@v4
with:
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
path: |
~/.cache/go-build
~/go/pkg/mod
- name: Restore LLVM source cache
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-18-linux-alpine-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save LLVM source cache
uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Restore LLVM build cache
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-18-linux-alpine-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
run: |
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# install dependencies
apk add cmake samurai python3
# build!
make llvm-build
# Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache
uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build
- name: Cache Binaryen
uses: actions/cache@v4
id: cache-binaryen
with:
key: binaryen-linux-alpine-v1
path: build/wasm-opt
- name: Build Binaryen
if: steps.cache-binaryen.outputs.cache-hit != 'true'
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
gem install --version 2.7.6 dotenv
gem install --no-document fpm
- name: Run linter
run: make lint
- name: Build TinyGo release
run: |
make release deb -j3 STATIC=1
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
cp -p build/release.deb /tmp/tinygo_amd64.deb
- name: Publish release artifact
uses: actions/upload-artifact@v4
with:
name: linux-amd64-double-zipped
path: |
/tmp/tinygo.linux-amd64.tar.gz
/tmp/tinygo_amd64.deb
test-linux-build:
# Test the binaries built in the build-linux job by running the smoke tests.
runs-on: ubuntu-latest
needs: build-linux
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true
- name: Install wasmtime
run: |
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
curl https://github.com/bytecodealliance/wasmtime/releases/download/v14.0.4/wasmtime-v14.0.4-x86_64-linux.tar.xz -o wasmtime-v14.0.4-x86_64-linux.tar.xz -SfL
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v14.0.4-x86_64-linux.tar.xz --strip-components=1 wasmtime-v14.0.4-x86_64-linux/*
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
- name: Download release artifact
uses: actions/download-artifact@v4
with:
name: linux-amd64-double-zipped
- name: Extract release tarball
run: |
mkdir -p ~/lib
tar -C ~/lib -xf tinygo.linux-amd64.tar.gz
ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo
- run: make tinygo-test-wasi-fast
- run: make tinygo-test-wasip1-fast
- run: make smoketest
assert-test-linux:
# Run all tests that can run on Linux, with LLVM assertions enabled to catch
# potential bugs.
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true
- name: Install apt dependencies
run: |
echo "Show cpuinfo; sometimes useful when troubleshooting"
cat /proc/cpuinfo
sudo apt-get update
sudo apt-get install --no-install-recommends \
qemu-system-arm \
qemu-system-riscv32 \
qemu-user \
simavr \
ninja-build
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install wasmtime
run: |
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v14.0.4/wasmtime-v14.0.4-x86_64-linux.tar.xz -o wasmtime-v14.0.4-x86_64-linux.tar.xz -SfL
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v14.0.4-x86_64-linux.tar.xz --strip-components=1 wasmtime-v14.0.4-x86_64-linux/*
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
- name: Restore LLVM source cache
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-18-linux-asserts-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save LLVM source cache
uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Restore LLVM build cache
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-18-linux-asserts-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
run: |
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# build!
make llvm-build ASSERT=1
# Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache
uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build
- name: Cache Binaryen
uses: actions/cache@v4
id: cache-binaryen
with:
key: binaryen-linux-asserts-v1
path: build/wasm-opt
- 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
- name: Build TinyGo
run: |
make ASSERT=1
echo "$(pwd)/build" >> $GITHUB_PATH
- name: Test stdlib packages
run: make tinygo-test
- run: make smoketest
- run: make wasmtest
- run: make tinygo-baremetal
build-linux-cross:
# Build ARM Linux binaries, ready for release.
# This intentionally uses an older Linux image, so that we compile against
# an older glibc version and therefore are compatible with a wide range of
# Linux distributions.
# It is set to "needs: build-linux" because it modifies the release created
# in that process to avoid doing lots of duplicate work and to avoid
# complications around precompiled libraries such as compiler-rt shipped as
# part of the release tarball.
strategy:
matrix:
goarch: [ arm, arm64 ]
include:
- goarch: arm64
toolchain: aarch64-linux-gnu
libc: arm64
- goarch: arm
toolchain: arm-linux-gnueabihf
libc: armhf
runs-on: ubuntu-20.04
needs: build-linux
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install apt dependencies
run: |
sudo apt-get update
sudo apt-get install --no-install-recommends \
qemu-user \
g++-${{ matrix.toolchain }} \
libc6-dev-${{ matrix.libc }}-cross
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true
- name: Restore LLVM source cache
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-18-linux-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save LLVM source cache
uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Restore LLVM build cache
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-18-linux-${{ matrix.goarch }}-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
run: |
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# Install build dependencies.
sudo apt-get install --no-install-recommends ninja-build
# build!
make llvm-build CROSS=${{ matrix.toolchain }}
# Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save LLVM build cache
uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
path: llvm-build
- name: Cache Binaryen
uses: actions/cache@v4
id: cache-binaryen
with:
key: binaryen-linux-${{ matrix.goarch }}-v4
path: build/wasm-opt
- name: Build Binaryen
if: steps.cache-binaryen.outputs.cache-hit != 'true'
run: |
sudo apt-get install --no-install-recommends ninja-build
git submodule update --init lib/binaryen
make CROSS=${{ matrix.toolchain }} binaryen
- name: Install fpm
run: |
sudo gem install --version 4.0.7 public_suffix
sudo gem install --version 2.7.6 dotenv
sudo gem install --no-document fpm
- name: Build TinyGo binary
run: |
make CROSS=${{ matrix.toolchain }}
- name: Download amd64 release
uses: actions/download-artifact@v4
with:
name: linux-amd64-double-zipped
- name: Extract amd64 release
run: |
mkdir -p build/release
tar -xf tinygo.linux-amd64.tar.gz -C build/release tinygo
- name: Modify release
run: |
cp -p build/tinygo build/release/tinygo/bin
cp -p build/wasm-opt build/release/tinygo/bin
- name: Create ${{ matrix.goarch }} release
run: |
make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }}
cp -p build/release.tar.gz /tmp/tinygo.linux-${{ matrix.goarch }}.tar.gz
cp -p build/release.deb /tmp/tinygo_${{ matrix.libc }}.deb
- name: Publish release artifact
uses: actions/upload-artifact@v4
with:
name: linux-${{ matrix.goarch }}-double-zipped
path: |
/tmp/tinygo.linux-${{ matrix.goarch }}.tar.gz
/tmp/tinygo_${{ matrix.libc }}.deb
+63
View File
@@ -0,0 +1,63 @@
# This is the Github action to build and push the LLVM Docker image
# used by the tinygo/tinygo-dev Docker image.
#
# It only needs to be rebuilt when updating the LLVM version.
#
# To update, make any needed changes to this file,
# then push to the "build-llvm-image" branch.
#
# The needed image will be rebuilt, which will very likely take at least 1-2 hours.
name: LLVM
on:
push:
branches: [ build-llvm-image ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-push-llvm:
name: build-push-llvm
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Check out the repo
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
tinygo/llvm-18
ghcr.io/${{ github.repository_owner }}/llvm-18
tags: |
type=sha,format=long
type=raw,value=latest
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
target: tinygo-llvm-build
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
+43
View File
@@ -0,0 +1,43 @@
name: Nix
on:
pull_request:
push:
branches:
- dev
- release
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
nix-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Pull musl
run: |
git submodule update --init lib/musl
- name: Restore LLVM source cache
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-18-linux-nix-v1
path: |
llvm-project/compiler-rt
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save LLVM source cache
uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
path: |
llvm-project/compiler-rt
- uses: cachix/install-nix-action@v22
- name: Test
run: |
nix develop --ignore-environment --keep HOME --command bash -c "go install && ~/go/bin/tinygo version && ~/go/bin/tinygo build -o test ./testdata/cgo"
+12
View File
@@ -0,0 +1,12 @@
# Command that's part of sizediff.yml. This is put in a separate file so that it
# 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/jammy/ llvm-toolchain-jammy-18 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-18-dev \
clang-18 \
libclang-18-dev \
lld-18
+91
View File
@@ -0,0 +1,91 @@
name: Binary size difference
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
sizediff:
runs-on: ubuntu-22.04
permissions:
pull-requests: write
steps:
# Prepare, install tools
- name: Add GOBIN to $PATH
run: |
echo "$HOME/go/bin" >> $GITHUB_PATH
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # fetch all history (no sparse checkout)
submodules: true
- name: Install apt dependencies
run: ./.github/workflows/sizediff-install-pkgs.sh
- name: Restore LLVM source cache
uses: actions/cache@v4
id: cache-llvm-source
with:
key: llvm-source-18-sizediff-v1
path: |
llvm-project/compiler-rt
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Cache Go
uses: actions/cache@v4
with:
key: go-cache-linux-sizediff-v2-${{ hashFiles('go.mod') }}
path: |
~/.cache/go-build
~/go/pkg/mod
- run: make gen-device -j4
- name: Download drivers repo
run: git clone https://github.com/tinygo-org/drivers.git
- name: Save HEAD
run: git branch github-actions-saved-HEAD HEAD
# Compute sizes for the PR branch
- name: Build tinygo binary for the PR branch
run: go install
- name: Determine binary sizes on the PR branch
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-pr.txt)
# Compute sizes for the dev branch
- name: Checkout dev branch
run: |
git reset --hard origin/dev
git checkout --no-recurse-submodules `git merge-base HEAD origin/dev`
- name: Install apt dependencies on the dev branch
# this is only needed on a PR that changes the LLVM version
run: ./.github/workflows/sizediff-install-pkgs.sh
- name: Build tinygo binary for the dev branch
run: go install
- name: Determine binary sizes on the dev branch
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-dev.txt)
# Create comment
# TODO: add a summary, something like:
# - overall size difference (percent)
# - number of binaries that grew / shrank / remained the same
# - don't show the full diff when no binaries changed
- name: Calculate size diff
run: ./tools/sizediff drivers/sizes-dev.txt drivers/sizes-pr.txt | tee sizediff.txt
- name: Create comment
run: |
echo "Size difference with the dev branch:" > comment.txt
echo "<details><summary>Binary size difference</summary>" >> comment.txt
echo "<pre>" >> comment.txt
cat sizediff.txt >> comment.txt
echo "</pre></details>" >> comment.txt
- name: Comment contents
run: cat comment.txt
- name: Add comment
if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
uses: thollander/actions-comment-pull-request@v2.3.1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
filePath: comment.txt
comment_tag: sizediff
+224
View File
@@ -0,0 +1,224 @@
name: Windows
on:
pull_request:
push:
branches:
- dev
- release
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-windows:
runs-on: windows-2022
steps:
- name: Configure pagefile
uses: al-cheb/configure-pagefile-action@v1.4
with:
minimum-size: 8GB
maximum-size: 24GB
disk-root: "C:"
- uses: brechtm/setup-scoop@v2
with:
scoop_update: 'false'
- name: Install Dependencies
shell: bash
run: |
scoop install ninja binaryen
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true
- name: Restore cached LLVM source
uses: actions/cache/restore@v4
id: cache-llvm-source
with:
key: llvm-source-18-windows-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save cached LLVM source
uses: actions/cache/save@v4
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Restore cached LLVM build
uses: actions/cache/restore@v4
id: cache-llvm-build
with:
key: llvm-build-18-windows-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
shell: bash
run: |
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# build!
make llvm-build CCACHE=OFF
# Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Save cached LLVM build
uses: actions/cache/save@v4
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
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: Install wasmtime
run: |
scoop install wasmtime@14.0.4
- name: make gen-device
run: make -j3 gen-device
- name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-short"
- name: Build TinyGo release tarball
shell: bash
run: make build/release -j4
- name: Make release artifact
shell: bash
working-directory: build/release
run: 7z -tzip a release.zip tinygo
- name: Publish release artifact
# Note: this release artifact is double-zipped, see:
# https://github.com/actions/upload-artifact/issues/39
# We can essentially pick one of these:
# - have a dobule-zipped artifact when downloaded from the UI
# - have a very slow artifact upload
# We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v4
with:
name: windows-amd64-double-zipped
path: build/release/release.zip
smoke-test-windows:
runs-on: windows-2022
needs: build-windows
steps:
- name: Configure pagefile
uses: al-cheb/configure-pagefile-action@v1.4
with:
minimum-size: 8GB
maximum-size: 24GB
disk-root: "C:"
- uses: brechtm/setup-scoop@v2
with:
scoop_update: 'false'
- name: Install Dependencies
shell: bash
run: |
scoop install binaryen
- name: Checkout
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v4
with:
name: windows-amd64-double-zipped
path: build/
- name: Unzip TinyGo build
shell: bash
working-directory: build
run: 7z x release.zip -r
- name: Smoke tests
shell: bash
run: make smoketest TINYGO=$(PWD)/build/tinygo/bin/tinygo
stdlib-test-windows:
runs-on: windows-2022
needs: build-windows
steps:
- name: Configure pagefile
uses: al-cheb/configure-pagefile-action@v1.4
with:
minimum-size: 8GB
maximum-size: 24GB
disk-root: "C:"
- name: Checkout
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v4
with:
name: windows-amd64-double-zipped
path: build/
- name: Unzip TinyGo build
shell: bash
working-directory: build
run: 7z x release.zip -r
- name: Test stdlib packages
run: make tinygo-test TINYGO=$(PWD)/build/tinygo/bin/tinygo
stdlib-wasi-test-windows:
runs-on: windows-2022
needs: build-windows
steps:
- name: Configure pagefile
uses: al-cheb/configure-pagefile-action@v1.4
with:
minimum-size: 8GB
maximum-size: 24GB
disk-root: "C:"
- uses: brechtm/setup-scoop@v2
with:
scoop_update: 'false'
- name: Install Dependencies
shell: bash
run: |
scoop install binaryen && scoop install wasmtime@14.0.4
- name: Checkout
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v4
with:
name: windows-amd64-double-zipped
path: build/
- name: Unzip TinyGo build
shell: bash
working-directory: build
run: 7z x release.zip -r
- name: Test stdlib packages on wasi
run: make tinygo-test-wasi-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo
+8 -2
View File
@@ -1,4 +1,3 @@
build
docs/_build
src/device/avr/*.go
src/device/avr/*.ld
@@ -16,13 +15,20 @@ src/device/stm32/*.go
src/device/stm32/*.s
src/device/kendryte/*.go
src/device/kendryte/*.s
src/device/rp/*.go
src/device/rp/*.s
vendor
llvm-build
llvm-project
build/*
# Ignore files generated by smoketest
test
test.bin
test.elf
test.exe
test.gba
test.hex
test.nro
test.wasm
wasm.wasm
wasm.wasm
+22 -6
View File
@@ -9,17 +9,33 @@
url = https://github.com/avr-rust/avr-mcu.git
[submodule "lib/cmsis-svd"]
path = lib/cmsis-svd
url = https://github.com/tinygo-org/cmsis-svd
[submodule "lib/compiler-rt"]
path = lib/compiler-rt
url = https://github.com/llvm-mirror/compiler-rt.git
branch = release_80
url = https://github.com/cmsis-svd/cmsis-svd-data.git
branch = main
[submodule "lib/wasi-libc"]
path = lib/wasi-libc
url = https://github.com/CraneStation/wasi-libc
url = https://github.com/WebAssembly/wasi-libc
[submodule "lib/picolibc"]
path = lib/picolibc
url = https://github.com/keith-packard/picolibc.git
[submodule "lib/stm32-svd"]
path = lib/stm32-svd
url = https://github.com/tinygo-org/stm32-svd
[submodule "lib/musl"]
path = lib/musl
url = git://git.musl-libc.org/musl
[submodule "lib/binaryen"]
path = lib/binaryen
url = https://github.com/WebAssembly/binaryen.git
[submodule "lib/mingw-w64"]
path = lib/mingw-w64
url = https://github.com/mingw-w64/mingw-w64.git
[submodule "lib/macos-minimal-sdk"]
path = lib/macos-minimal-sdk
url = https://github.com/aykevl/macos-minimal-sdk.git
[submodule "lib/renesas-svd"]
path = lib/renesas-svd
url = https://github.com/tinygo-org/renesas-svd.git
[submodule "src/net"]
path = src/net
url = https://github.com/tinygo-org/net.git
branch = dev
+3 -7
View File
@@ -11,19 +11,15 @@ lld so that the binary can be easily moved between systems. It also shows how to
build a release tarball that includes this binary and all necessary extra files.
**Note**: this documentation describes how to build a statically linked release
tarball. If you want to develop TinyGo, you will probably want to follow a
different guide:
* [Linux](https://tinygo.org/getting-started/linux/#source-install)
* [macOS](https://tinygo.org/getting-started/macos/#source-install)
* [Windows](https://tinygo.org/getting-started/windows/#source-install)
tarball. If you want to help with development of TinyGo itself, you should follow the guide located at https://tinygo.org/docs/guides/build/
## Dependencies
LLVM, Clang and LLD are quite light on dependencies, requiring only standard
build tools to be built. Go is of course necessary to build TinyGo itself.
* Go (1.13+)
* Go (1.19+)
* GNU Make
* Standard build tools (gcc/clang)
* git
* CMake
+1235 -2
View File
File diff suppressed because it is too large Load Diff
+1 -52
View File
@@ -1,52 +1 @@
# How to contribute
Thank you for your interest in improving TinyGo.
We would like your help to make this project better, so we appreciate any contributions. See if one of the following descriptions matches your situation:
### New to TinyGo
We'd love to get your feedback on getting started with TinyGo. Run into any difficulty, confusion, or anything else? You are not alone. We want to know about your experience, so we can help the next people. Please open a Github issue with your questions, or you can also get in touch directly with us on our Slack channel at [https://gophers.slack.com/messages/CDJD3SUP6](https://gophers.slack.com/messages/CDJD3SUP6).
### Something in TinyGo is not working as you expect
Please open a Github issue with your problem, and we will be happy to assist.
### Something in Go that you want/need does not appear to be in TinyGo
We probably have not implemented it yet. Please take a look at our [Roadmap](https://github.com/tinygo-org/tinygo/wiki/Roadmap). Your pull request adding the functionality to TinyGo would be greatly appreciated.
Please open a Github issue. We want to help, and also make sure that there is no duplications of efforts. Sometimes what you need is already being worked on by someone else.
A long tail of small (and large) language features haven't been implemented yet. In almost all cases, the compiler will show a `todo:` error from `compiler/compiler.go` when you try to use it. You can try implementing it, or open a bug report with a small code sample that fails to compile.
### Some specific hardware you want to use does not appear to be in TinyGo
As above, we probably have not implemented it yet. Your contribution adding the hardware support to TinyGo would be greatly appreciated.
Please start by opening a Github issue. We want to help you to help us to help you.
Lots of targets/boards are still unsupported. Adding an architecture often requires a few compiler changes, but if the architecture is supported you can try implementing support for a new chip or board in `src/runtime`. For details, see [this wiki entry on adding archs/chips/boards](https://github.com/tinygo-org/tinygo/wiki/Adding-a-new-board).
Microcontrollers have lots of peripherals (I2C, SPI, ADC, etc.) and many don't have an implementation yet in the `machine` package. Adding support for new peripherals is very useful.
## How to use our Github repository
The `release` branch of this repo will always have the latest released version of TinyGo. All of the active development work for the next release will take place in the `dev` branch. TinyGo will use semantic versioning and will create a tag/release for each release.
Here is how to contribute back some code or documentation:
- Fork repo
- Create a feature branch off of the `dev` branch
- Make some useful change
- Make sure the tests still pass
- Submit a pull request against the `dev` branch.
- Be kind
## How to run tests
To run the tests:
```
make test
```
Please take a look at our [Contributing](https://tinygo.org/docs/guides/contributing/) page on our web site for details. Thank you.
+34 -70
View File
@@ -1,79 +1,43 @@
# TinyGo base stage installs the most recent Go 1.15.x, LLVM 11 and the TinyGo compiler itself.
FROM golang:1.15 AS tinygo-base
# tinygo-llvm stage obtains the llvm source for TinyGo
FROM golang:1.22 AS tinygo-llvm
RUN wget -O- https://apt.llvm.org/llvm-snapshot.gpg.key| apt-key add - && \
echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-11 main" >> /etc/apt/sources.list && \
apt-get update && \
apt-get install -y llvm-11-dev libclang-11-dev lld-11 git
RUN apt-get update && \
apt-get install -y apt-utils make cmake clang-15 ninja-build && \
rm -rf \
/var/lib/apt/lists/* \
/var/log/* \
/var/tmp/* \
/tmp/*
COPY ./GNUmakefile /tinygo/GNUmakefile
RUN cd /tinygo/ && \
make llvm-source
# tinygo-llvm-build stage build the custom llvm with xtensa support
FROM tinygo-llvm AS tinygo-llvm-build
RUN cd /tinygo/ && \
make llvm-build
# tinygo-compiler-build stage builds the compiler itself
FROM tinygo-llvm-build AS tinygo-compiler-build
COPY . /tinygo
# remove submodules directories and re-init them to fix any hard-coded paths
# after copying the tinygo directory in the previous step.
# build the compiler and tools
RUN cd /tinygo/ && \
rm -rf ./lib/* && \
git submodule sync && \
git submodule update --init --recursive --force
git submodule update --init && \
make gen-device -j4 && \
make build/release
COPY ./lib/picolibc-include/* /tinygo/lib/picolibc-include/
# tinygo-compiler copies the compiler build over to a base Go container (without
# all the build tools etc).
FROM golang:1.22 AS tinygo-compiler
RUN cd /tinygo/ && \
go install /tinygo/
# tinygo-wasm stage installs the needed dependencies to compile TinyGo programs for WASM.
FROM tinygo-base AS tinygo-wasm
COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
COPY --from=tinygo-base /tinygo/src /tinygo/src
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
RUN cd /tinygo/ && \
apt-get update && \
apt-get install -y make clang-11 libllvm11 lld-11 && \
make wasi-libc
# tinygo-avr stage installs the needed dependencies to compile TinyGo programs for AVR microcontrollers.
FROM tinygo-base AS tinygo-avr
COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
COPY --from=tinygo-base /tinygo/src /tinygo/src
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
COPY --from=tinygo-base /tinygo/Makefile /tinygo/
COPY --from=tinygo-base /tinygo/tools /tinygo/tools
COPY --from=tinygo-base /tinygo/lib /tinygo/lib
RUN cd /tinygo/ && \
apt-get update && \
apt-get install -y apt-utils make binutils-avr gcc-avr avr-libc && \
make gen-device-avr && \
apt-get autoremove -y && \
apt-get clean
# tinygo-arm stage installs the needed dependencies to compile TinyGo programs for ARM microcontrollers.
FROM tinygo-base AS tinygo-arm
COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
COPY --from=tinygo-base /tinygo/src /tinygo/src
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
COPY --from=tinygo-base /tinygo/Makefile /tinygo/
COPY --from=tinygo-base /tinygo/tools /tinygo/tools
COPY --from=tinygo-base /tinygo/lib /tinygo/lib
RUN cd /tinygo/ && \
apt-get update && \
apt-get install -y apt-utils make clang-11 && \
make gen-device-nrf && make gen-device-stm32
# tinygo-all stage installs the needed dependencies to compile TinyGo programs for all platforms.
FROM tinygo-wasm AS tinygo-all
COPY --from=tinygo-base /tinygo/Makefile /tinygo/
COPY --from=tinygo-base /tinygo/tools /tinygo/tools
COPY --from=tinygo-base /tinygo/lib /tinygo/lib
RUN cd /tinygo/ && \
apt-get update && \
apt-get install -y apt-utils make clang-11 binutils-avr gcc-avr avr-libc && \
make gen-device
# Copy tinygo build.
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
# Configure the container.
ENV PATH="${PATH}:/tinygo/bin"
CMD ["tinygo"]
+931
View File
@@ -0,0 +1,931 @@
# aliases
all: tinygo
# Default build and source directories, as created by `make llvm-build`.
LLVM_BUILDDIR ?= llvm-build
LLVM_PROJECTDIR ?= llvm-project
CLANG_SRC ?= $(LLVM_PROJECTDIR)/clang
LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
# Try to autodetect LLVM build tools.
# Versions are listed here in descending priority order.
LLVM_VERSIONS = 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)
# 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)
endif
# First search for a custom built copy, then move on to explicitly version-tagged binaries, then just see if the tool is in path with its normal name.
findLLVMTool = $(call detect,$(1),$(abspath llvm-build/bin/$(1)) $(foreach ver,$(LLVM_VERSIONS),$(call toolSearchPathsVersion,$(1),$(ver))) $(1))
CLANG ?= $(call findLLVMTool,clang)
LLVM_AR ?= $(call findLLVMTool,llvm-ar)
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 ?=
GOTESTPKGS ?= ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
# tinygo binary for tests
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
endif
LLVM_OPTION += '-DLLVM_CCACHE_BUILD=$(CCACHE)'
# Allow enabling LLVM assertions
ifeq (1, $(ASSERT))
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=ON'
else
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=OFF'
endif
# Enable AddressSanitizer
ifeq (1, $(ASAN))
LLVM_OPTION += -DLLVM_USE_SANITIZER=Address
CGO_LDFLAGS += -fsanitize=address
endif
ifeq (1, $(STATIC))
# Build TinyGo as a fully statically linked binary (no dynamically loaded
# libraries such as a libc). This is not supported with glibc which is used
# on most major Linux distributions. However, it is supported in Alpine
# Linux with musl.
CGO_LDFLAGS += -static
# Also set the thread stack size to 1MB. This is necessary on musl as the
# default stack size is 128kB and LLVM uses more than that.
# For more information, see:
# https://wiki.musl-libc.org/functional-differences-from-glibc.html#Thread-stack-size
CGO_LDFLAGS += -Wl,-z,stack-size=1048576
# Build wasm-opt with static linking.
# For details, see:
# https://github.com/WebAssembly/binaryen/blob/version_102/.github/workflows/ci.yml#L181
BINARYEN_OPTION += -DCMAKE_CXX_FLAGS="-static" -DCMAKE_C_FLAGS="-static"
endif
# Cross compiling support.
ifneq ($(CROSS),)
CC = $(CROSS)-gcc
CXX = $(CROSS)-g++
LLVM_OPTION += \
-DCMAKE_C_COMPILER=$(CC) \
-DCMAKE_CXX_COMPILER=$(CXX) \
-DLLVM_DEFAULT_TARGET_TRIPLE=$(CROSS) \
-DCROSS_TOOLCHAIN_FLAGS_NATIVE="-UCMAKE_C_COMPILER;-UCMAKE_CXX_COMPILER"
ifeq ($(CROSS), arm-linux-gnueabihf)
# Assume we're building on a Debian-like distro, with QEMU installed.
LLVM_CONFIG_PREFIX = qemu-arm -L /usr/arm-linux-gnueabihf/
# The CMAKE_SYSTEM_NAME flag triggers cross compilation mode.
LLVM_OPTION += \
-DCMAKE_SYSTEM_NAME=Linux \
-DLLVM_TARGET_ARCH=ARM
GOENVFLAGS = GOARCH=arm CC=$(CC) CXX=$(CXX) CGO_ENABLED=1
BINARYEN_OPTION += -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX)
else ifeq ($(CROSS), aarch64-linux-gnu)
# Assume we're building on a Debian-like distro, with QEMU installed.
LLVM_CONFIG_PREFIX = qemu-aarch64 -L /usr/aarch64-linux-gnu/
# The CMAKE_SYSTEM_NAME flag triggers cross compilation mode.
LLVM_OPTION += \
-DCMAKE_SYSTEM_NAME=Linux \
-DLLVM_TARGET_ARCH=AArch64
GOENVFLAGS = GOARCH=arm64 CC=$(CC) CXX=$(CXX) CGO_ENABLED=1
BINARYEN_OPTION += -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX)
else
$(error Unknown cross compilation target: $(CROSS))
endif
endif
.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-nxp gen-device-avr gen-device-rp
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf debuginfopdb executionengine frontenddriver frontendhlsl frontendopenmp instrumentation interpreter ipo irreader libdriver linker lto mc mcjit objcarcopts option profiledata scalaropts support target windowsdriver windowsmanifest
ifeq ($(OS),Windows_NT)
EXE = .exe
START_GROUP = -Wl,--start-group
END_GROUP = -Wl,--end-group
# PIC needs to be disabled for libclang to work.
LLVM_OPTION += -DLLVM_ENABLE_PIC=OFF
CGO_CPPFLAGS += -DCINDEX_NO_EXPORTS
CGO_LDFLAGS += -static -static-libgcc -static-libstdc++
CGO_LDFLAGS_EXTRA += -lversion
USE_SYSTEM_BINARYEN ?= 1
else ifeq ($(shell uname -s),Darwin)
MD5SUM ?= md5
CGO_LDFLAGS += -lxar
USE_SYSTEM_BINARYEN ?= 1
else ifeq ($(shell uname -s),FreeBSD)
MD5SUM ?= md5
START_GROUP = -Wl,--start-group
END_GROUP = -Wl,--end-group
else
START_GROUP = -Wl,--start-group
END_GROUP = -Wl,--end-group
endif
# md5sum binary default, can be overridden by an environment variable
MD5SUM ?= md5sum
# Libraries that should be linked in for the statically linked Clang.
CLANG_LIB_NAMES = clangAnalysis clangAPINotes clangAST clangASTMatchers clangBasic clangCodeGen clangCrossTU clangDriver clangDynamicASTMatchers clangEdit clangExtractAPI clangFormat clangFrontend clangFrontendTool clangHandleCXX clangHandleLLVM clangIndex clangLex clangParse clangRewrite clangRewriteFrontend clangSema clangSerialization clangSupport clangTooling clangToolingASTDiff clangToolingCore clangToolingInclusions
CLANG_LIBS = $(START_GROUP) $(addprefix -l,$(CLANG_LIB_NAMES)) $(END_GROUP) -lstdc++
# Libraries that should be linked in for the statically linked LLD.
LLD_LIB_NAMES = lldCOFF lldCommon lldELF lldMachO lldMinGW lldWasm
LLD_LIBS = $(START_GROUP) $(addprefix -l,$(LLD_LIB_NAMES)) $(END_GROUP)
# Other libraries that are needed to link TinyGo.
EXTRA_LIB_NAMES = LLVMInterpreter LLVMMCA LLVMRISCVTargetMCA LLVMX86TargetMCA
# All libraries to be built and linked with the tinygo binary (lib/lib*.a).
LIB_NAMES = clang $(CLANG_LIB_NAMES) $(LLD_LIB_NAMES) $(EXTRA_LIB_NAMES)
# These build targets appear to be the only ones necessary to build all TinyGo
# dependencies. Only building a subset significantly speeds up rebuilding LLVM.
# The Makefile rules convert a name like lldELF to lib/liblldELF.a to match the
# library path (for ninja).
# This list also includes a few tools that are necessary as part of the full
# TinyGo build.
NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm lld $(addprefix lib/lib,$(addsuffix .a,$(LIB_NAMES)))
# For static linking.
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
CGO_CPPFLAGS+=$(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
CGO_CXXFLAGS=-std=c++17
CGO_LDFLAGS+=-L$(abspath $(LLVM_BUILDDIR)/lib) -lclang $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
endif
clean:
@rm -rf build
FMT_PATHS = ./*.go builder cgo/*.go compiler interp loader src transform
fmt:
@gofmt -l -w $(FMT_PATHS)
fmt-check:
@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
ifneq ($(STM32), 0)
gen-device: gen-device-stm32
endif
gen-device-avr:
@if [ ! -e lib/avr/README.md ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
$(GO) build -o ./build/gen-device-avr ./tools/gen-device-avr/
./build/gen-device-avr lib/avr/packs/atmega src/device/avr/
./build/gen-device-avr lib/avr/packs/tiny src/device/avr/
@GO111MODULE=off $(GO) fmt ./src/device/avr
build/gen-device-svd: ./tools/gen-device-svd/*.go
$(GO) build -o $@ ./tools/gen-device-svd/
gen-device-esp: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Espressif-Community -interrupts=software lib/cmsis-svd/data/Espressif-Community/ src/device/esp/
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Espressif -interrupts=software lib/cmsis-svd/data/Espressif/ src/device/esp/
GO111MODULE=off $(GO) fmt ./src/device/esp
gen-device-nrf: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/NordicSemiconductor/nrfx/tree/master/mdk lib/nrfx/mdk/ src/device/nrf/
GO111MODULE=off $(GO) fmt ./src/device/nrf
gen-device-nxp: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/NXP lib/cmsis-svd/data/NXP/ src/device/nxp/
GO111MODULE=off $(GO) fmt ./src/device/nxp
gen-device-sam: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Atmel lib/cmsis-svd/data/Atmel/ src/device/sam/
GO111MODULE=off $(GO) fmt ./src/device/sam
gen-device-sifive: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/SiFive-Community -interrupts=software lib/cmsis-svd/data/SiFive-Community/ src/device/sifive/
GO111MODULE=off $(GO) fmt ./src/device/sifive
gen-device-kendryte: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Kendryte-Community -interrupts=software lib/cmsis-svd/data/Kendryte-Community/ src/device/kendryte/
GO111MODULE=off $(GO) fmt ./src/device/kendryte
gen-device-stm32: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/tinygo-org/stm32-svd lib/stm32-svd/svd src/device/stm32/
GO111MODULE=off $(GO) fmt ./src/device/stm32
gen-device-rp: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/RaspberryPi lib/cmsis-svd/data/RaspberryPi/ src/device/rp/
GO111MODULE=off $(GO) fmt ./src/device/rp
gen-device-renesas: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/tinygo-org/renesas-svd lib/renesas-svd/ src/device/renesas/
GO111MODULE=off $(GO) fmt ./src/device/renesas
# Get LLVM sources.
$(LLVM_PROJECTDIR)/llvm:
git clone -b tinygo_xtensa_release_18.1.2 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
llvm-source: $(LLVM_PROJECTDIR)/llvm
# Configure LLVM.
TINYGO_SOURCE_DIR=$(shell pwd)
$(LLVM_BUILDDIR)/build.ninja:
mkdir -p $(LLVM_BUILDDIR) && cd $(LLVM_BUILDDIR) && cmake -G Ninja $(TINYGO_SOURCE_DIR)/$(LLVM_PROJECTDIR)/llvm "-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64;RISCV;WebAssembly" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=AVR;Xtensa" -DCMAKE_BUILD_TYPE=Release -DLIBCLANG_BUILD_STATIC=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ZLIB=OFF -DLLVM_ENABLE_ZSTD=OFF -DLLVM_ENABLE_LIBEDIT=OFF -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_ENABLE_OCAMLDOC=OFF -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF -DCLANG_ENABLE_ARCMT=OFF $(LLVM_OPTION)
# Build LLVM.
$(LLVM_BUILDDIR): $(LLVM_BUILDDIR)/build.ninja
cd $(LLVM_BUILDDIR) && ninja $(NINJA_BUILD_TARGETS)
ifneq ($(USE_SYSTEM_BINARYEN),1)
# Build Binaryen
.PHONY: binaryen
binaryen: build/wasm-opt$(EXE)
build/wasm-opt$(EXE):
mkdir -p build
cd lib/binaryen && cmake -G Ninja . -DBUILD_STATIC_LIB=ON -DBUILD_TESTS=OFF $(BINARYEN_OPTION) && ninja bin/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)
# 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
# Build the Go compiler.
tinygo:
@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" -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
test: wasi-libc check-nodejs-version
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -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
TEST_PACKAGES_SLOW = \
compress/bzip2 \
crypto/dsa \
index/suffixarray \
# Standard library packages that pass tests quickly on darwin, linux, wasi, and windows
TEST_PACKAGES_FAST = \
compress/lzw \
compress/zlib \
container/heap \
container/list \
container/ring \
crypto/des \
crypto/md5 \
crypto/rc4 \
crypto/sha1 \
crypto/sha256 \
crypto/sha512 \
debug/macho \
embed/internal/embedtest \
encoding \
encoding/ascii85 \
encoding/base32 \
encoding/base64 \
encoding/csv \
encoding/hex \
go/scanner \
hash \
hash/adler32 \
hash/crc64 \
hash/fnv \
html \
internal/itoa \
internal/profile \
math \
math/cmplx \
net/http/internal/ascii \
net/mail \
os \
path \
reflect \
sync \
testing \
testing/iotest \
text/scanner \
unicode \
unicode/utf16 \
unicode/utf8 \
$(nil)
# Assume this will go away before Go2, so only check minor version.
ifeq ($(filter $(shell $(GO) env GOVERSION | cut -f 2 -d.), 16 17 18), )
TEST_PACKAGES_FAST += crypto/internal/nistec/fiat
else
TEST_PACKAGES_FAST += crypto/elliptic/internal/fiat
endif
# archive/zip requires os.ReadAt, which is not yet supported on windows
# bytes requires mmap
# compress/flate appears to hang on wasi
# crypto/hmac fails on wasi, it exits with a "slice out of range" panic
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows
# image requires recover(), which is not yet supported on wasi
# io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi
# mime/quotedprintable requires syscall.Faccessat
# strconv requires recover() which is not yet supported on wasi
# text/tabwriter requries recover(), which is not yet supported on wasi
# text/template/parse requires recover(), which is not yet supported on wasi
# testing/fstest requires os.ReadDir, which is not yet supported on windows or wasi
# Additional standard library packages that pass tests on individual platforms
TEST_PACKAGES_LINUX := \
archive/zip \
bytes \
compress/flate \
crypto/hmac \
debug/dwarf \
debug/plan9obj \
image \
io/ioutil \
mime/quotedprintable \
net \
strconv \
testing/fstest \
text/tabwriter \
text/template/parse
TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
TEST_PACKAGES_WINDOWS := \
compress/flate \
crypto/hmac \
strconv \
text/template/parse \
$(nil)
# Report platforms on which each standard library package is known to pass tests
jointmp := $(shell echo /tmp/join.$$$$)
report-stdlib-tests-pass:
@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
@join -a1 -a2 $(jointmp).darwin $(jointmp).linux | \
join -a1 -a2 - $(jointmp).portable
@rm $(jointmp).*
# Standard library packages that pass tests quickly on the current platform
ifeq ($(shell uname),Darwin)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_DARWIN)
TEST_IOFS := true
endif
ifeq ($(shell uname),Linux)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_LINUX)
TEST_IOFS := true
endif
ifeq ($(OS),Windows_NT)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
TEST_IOFS := false
endif
# 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)
@# 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.
ifeq ($(TEST_IOFS),true)
$(TINYGO) test -stack-size=6MB io/fs
endif
tinygo-test-fast:
$(TINYGO) test $(TEST_PACKAGES_HOST)
tinygo-bench:
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
tinygo-bench-fast:
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST)
# Same thing, except for wasi rather than the current platform.
tinygo-test-wasi:
$(TINYGO) test -target wasip1 $(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
tinygo-test-wasi-fast:
$(TINYGO) test -target wasip1 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
tinygo-test-wasip1-fast:
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
tinygo-bench-wasi:
$(TINYGO) test -target wasip1 -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
tinygo-bench-wasi-fast:
$(TINYGO) test -target wasip1 -bench . $(TEST_PACKAGES_FAST)
# 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
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
tinygo-baremetal:
# Regression tests that run on a baremetal target and don't fit in either main_test.go or smoketest.
# regression test for #2666: e.g. encoding/hex must pass on baremetal
$(TINYGO) test -target cortex-m-qemu encoding/hex
.PHONY: smoketest
smoketest:
$(TINYGO) version
$(TINYGO) targets > /dev/null
# regression test for #2892
cd tests/testing/recurse && ($(TINYGO) test ./... > recurse.log && cat recurse.log && test $$(wc -l < recurse.log) = 2 && rm recurse.log)
# compile-only platform-independent examples
cd tests/text/template/smoke && $(TINYGO) test -c && rm -f smoke.test
# regression test for #2563
cd tests/os/smoke && $(TINYGO) test -c -target=pybadge && rm smoke.test
# test all examples (except pwm)
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/adc
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinkm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/button
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/button2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/echo2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/i2s
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/mcp3008
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/memstats
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit examples/microbit-blink
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/pininterrupt
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nano-rp2040 examples/rtcinterrupt
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/machinetest
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/systick
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/time-offset
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-mouse
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-keyboard
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/i2c-target
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/watchdog
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/device-id
@$(MD5SUM) test.hex
# test simulated boards on play.tinygo.org
ifneq ($(WASM), 0)
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
@$(MD5SUM) test.wasm
$(TINYGO) build -size short -o test.wasm -tags=hifive1b examples/blinky1
@$(MD5SUM) test.wasm
$(TINYGO) build -size short -o test.wasm -tags=reelboard examples/blinky1
@$(MD5SUM) test.wasm
$(TINYGO) build -size short -o test.wasm -tags=microbit examples/microbit-blink
@$(MD5SUM) test.wasm
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_express examples/blinky1
@$(MD5SUM) test.wasm
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_bluefruit examples/blinky1
@$(MD5SUM) test.wasm
$(TINYGO) build -size short -o test.wasm -tags=mch2022 examples/machinetest
@$(MD5SUM) test.wasm
$(TINYGO) build -size short -o test.wasm -tags=gopher_badge examples/blinky1
@$(MD5SUM) test.wasm
endif
# test all targets/boards
$(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit-s110v8 examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit-v2 examples/microbit-blink
@$(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=nrf52840-mdk examples/blinky1
@$(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
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=reelboard examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10056 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10056 examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10059 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10059 examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=bluemicro840 examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=trinket-m0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=gemma-m0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-bluefruit examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/i2s
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=clue-alpha examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.gba -target=gameboy-advance examples/gba-display
@$(MD5SUM) test.gba
$(TINYGO) build -size short -o test.hex -target=grandcentral-m4 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m4 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=matrixportal-m4 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pybadge examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=metro-m4-airlift examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pyportal examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=particle-argon examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=particle-boron examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=particle-xenon examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pinetime examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=x9pro examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10056-s140v7 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10059-s140v7 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=reelboard-s140v7 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pygamer examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=xiao examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/dac
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pyportal examples/dac
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840-sense examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=itsybitsy-nrf52840 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=qtpy examples/machinetest
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy41 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy40 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy36 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=p1am-100 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=atsame54-xpro examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=atsame54-xpro examples/can
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m4-can examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m4-can examples/caninterrupt
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-nano33 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-mkrwifi1010 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pico examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nano-33-ble examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nano-rp2040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=qtpy-rp2040 examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=kb2040 examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=macropad-rp2040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=badger2040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=badger2040-w examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=tufty2040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=thingplus-rp2040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=xiao-rp2040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=waveshare-rp2040-zero examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=challenger-rp2040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=trinkey-qt2040 examples/temp
@$(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=ae-rp2040 examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=thumby examples/echo
@$(MD5SUM) test.hex
# test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m4 examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/pwm
@$(MD5SUM) test.hex
# test usb
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/hid-keyboard
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/hid-keyboard
@$(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=nrf52840-s140v6-uf2-generic examples/machinetest
@$(MD5SUM) test.hex
ifneq ($(STM32), 0)
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-stm32f405 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=lgt92 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-f103rb examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-f722ze examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-l031k6 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-l432kc examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-l476rg examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-l552ze examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-wl55jc examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco-1 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco-1 examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f469disco examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=lorae5 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=swan examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=mksnanov3 examples/blinky1
@$(MD5SUM) test.hex
endif
$(TINYGO) build -size short -o test.hex -target=atmega328pb examples/blinkm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/machinetest
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-leonardo examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino -scheduler=tasks examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-mega1280 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-mega1280 examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-nano examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=attiny1616 examples/empty
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=digispark examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=digispark -gc=leaking examples/blinky1
@$(MD5SUM) test.hex
ifneq ($(XTENSA), 0)
$(TINYGO) build -size short -o test.bin -target=esp32-mini32 examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target m5stack examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target m5stick-c examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target m5paper examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest
@$(MD5SUM) test.bin
endif
$(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c3 examples/machinetest
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
@$(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
$(TINYGO) build -size short -o wasm.wasm -target=wasm-unknown examples/hello-wasm-unknown
endif
# test various compiler flags
$(TINYGO) build -size short -o test.hex -target=pca10040 -gc=none -scheduler=none examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=1 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 -serial=none examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 -serial=rtt examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -o test.nro -target=nintendoswitch examples/serial
@$(MD5SUM) test.nro
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
@$(MD5SUM) test.hex
GOOS=linux GOARCH=arm $(TINYGO) build -size short -o test.elf ./testdata/cgo
GOOS=windows GOARCH=amd64 $(TINYGO) build -size short -o test.exe ./testdata/cgo
GOOS=windows GOARCH=arm64 $(TINYGO) build -size short -o test.exe ./testdata/cgo
GOOS=darwin GOARCH=amd64 $(TINYGO) build -size short -o test ./testdata/cgo
GOOS=darwin GOARCH=arm64 $(TINYGO) build -size short -o test ./testdata/cgo
ifneq ($(OS),Windows_NT)
# TODO: this does not yet work on Windows. Somehow, unused functions are
# not garbage collected.
$(TINYGO) build -o test.elf -gc=leaking -scheduler=none examples/serial
endif
wasmtest:
$(GO) test ./tests/wasm
build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binaryen)
@mkdir -p build/release/tinygo/bin
@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/lib-common
@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
@mkdir -p build/release/tinygo/lib/musl/src
@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/libc-top-half/musl/arch
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus
@mkdir -p build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4
@echo copying source files
@cp -p build/tinygo$(EXE) build/release/tinygo/bin
ifneq ($(USE_SYSTEM_BINARYEN),1)
@cp -p build/wasm-opt$(EXE) build/release/tinygo/bin
endif
@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
@cp -rp lib/macos-minimal-sdk/* build/release/tinygo/lib/macos-minimal-sdk
@cp -rp lib/musl/arch/aarch64 build/release/tinygo/lib/musl/arch
@cp -rp lib/musl/arch/arm build/release/tinygo/lib/musl/arch
@cp -rp lib/musl/arch/generic build/release/tinygo/lib/musl/arch
@cp -rp lib/musl/arch/i386 build/release/tinygo/lib/musl/arch
@cp -rp lib/musl/arch/x86_64 build/release/tinygo/lib/musl/arch
@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/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
@cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/linux build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/math 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/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/mingw-w64/mingw-w64-crt/def-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/kernel32.def.in build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
@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/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
@cp -rp lib/picolibc/newlib/libc/locale build/release/tinygo/lib/picolibc/newlib/libc
@cp -rp lib/picolibc/newlib/libc/string build/release/tinygo/lib/picolibc/newlib/libc
@cp -rp lib/picolibc/newlib/libc/tinystdio build/release/tinygo/lib/picolibc/newlib/libc
@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/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/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/math 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 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
@cp -rp src build/release/tinygo/src
@cp -rp targets build/release/tinygo/targets
./build/release/tinygo/bin/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/compiler-rt compiler-rt
./build/release/tinygo/bin/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/compiler-rt compiler-rt
./build/release/tinygo/bin/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/compiler-rt compiler-rt
./build/release/tinygo/bin/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/picolibc picolibc
./build/release/tinygo/bin/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/picolibc picolibc
./build/release/tinygo/bin/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/picolibc picolibc
release:
tar -czf build/release.tar.gz -C build/release tinygo
DEB_ARCH ?= native
deb:
@mkdir -p build/release-deb/usr/local/bin
@mkdir -p build/release-deb/usr/local/lib
cp -ar build/release/tinygo build/release-deb/usr/local/lib/tinygo
ln -sf ../lib/tinygo/bin/tinygo build/release-deb/usr/local/bin/tinygo
fpm -f -s dir -t deb -n tinygo -a $(DEB_ARCH) -v $(shell grep "const version = " goenv/version.go | awk '{print $$NF}') -m '@tinygo-org' --description='TinyGo is a Go compiler for small places.' --license='BSD 3-Clause' --url=https://tinygo.org/ --deb-changelog CHANGELOG.md -p build/release.deb -C ./build/release-deb
ifneq ($(RELEASEONLY), 1)
release: build/release
deb: build/release
endif
lint:
go run github.com/mgechev/revive -version
# TODO: lint more directories!
# 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
go run github.com/mgechev/revive -config revive.toml compiler/... src/{os,reflect}/*.go | grep -v "should have comment or be unexported" | grep '.' | awk '{print}; END {exit NR>0}'
spell:
# Check for typos in comments. Skip git submodules etc.
go run github.com/client9/misspell/cmd/misspell -i 'ackward,devided,extint,inbetween,programmmer,rela' $$( find . -depth 1 -type d | egrep -w -v 'lib|llvm|src/net' )
+2 -2
View File
@@ -1,7 +1,7 @@
Copyright (c) 2018-2021 TinyGo Authors. All rights reserved.
Copyright (c) 2018-2023 The TinyGo Authors. All rights reserved.
TinyGo includes portions of the Go standard library.
Copyright (c) 2009-2021 The Go Authors. All rights reserved.
Copyright (c) 2009-2023 The Go Authors. All rights reserved.
TinyGo includes portions of LLVM, which is under the Apache License v2.0 with
LLVM Exceptions. See https://llvm.org/LICENSE.txt for license information.
-456
View File
@@ -1,456 +0,0 @@
# aliases
all: tinygo
# Default build and source directories, as created by `make llvm-build`.
LLVM_BUILDDIR ?= llvm-build
LLVM_PROJECTDIR ?= llvm-project
CLANG_SRC ?= $(LLVM_PROJECTDIR)/clang
LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
# Try to autodetect LLVM build tools.
detect = $(shell command -v $(1) 2> /dev/null && echo $(1))
CLANG ?= $(word 1,$(abspath $(call detect,llvm-build/bin/clang))$(call detect,clang-11)$(call detect,clang-10)$(call detect,clang))
LLVM_AR ?= $(word 1,$(abspath $(call detect,llvm-build/bin/llvm-ar))$(call detect,llvm-ar-11)$(call detect,llvm-ar-10)$(call detect,llvm-ar))
LLVM_NM ?= $(word 1,$(abspath $(call detect,llvm-build/bin/llvm-nm))$(call detect,llvm-nm-11)$(call detect,llvm-nm-10)$(call detect,llvm-nm))
# Go binary and GOROOT to select
GO ?= go
export GOROOT = $(shell $(GO) env GOROOT)
# md5sum binary
MD5SUM = md5sum
# tinygo binary for tests
TINYGO ?= $(word 1,$(call detect,tinygo)$(call detect,build/tinygo))
# Use CCACHE for LLVM if possible
ifneq (, $(shell command -v ccache 2> /dev/null))
LLVM_OPTION += '-DLLVM_CCACHE_BUILD=ON'
endif
# Allow enabling LLVM assertions
ifeq (1, $(ASSERT))
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=ON'
else
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=OFF'
endif
.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-nxp gen-device-avr
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf executionengine frontendopenmp instrumentation interpreter ipo irreader linker lto mc mcjit objcarcopts option profiledata scalaropts support target
ifeq ($(OS),Windows_NT)
EXE = .exe
START_GROUP = -Wl,--start-group
END_GROUP = -Wl,--end-group
# LLVM compiled using MinGW on Windows appears to have problems with threads.
# Without this flag, linking results in errors like these:
# libLLVMSupport.a(Threading.cpp.obj):Threading.cpp:(.text+0x55): undefined reference to `std::thread::hardware_concurrency()'
LLVM_OPTION += -DLLVM_ENABLE_THREADS=OFF -DLLVM_ENABLE_PIC=OFF
CGO_CPPFLAGS += -DCINDEX_NO_EXPORTS
CGO_LDFLAGS += -static -static-libgcc -static-libstdc++
CGO_LDFLAGS_EXTRA += -lversion
LIBCLANG_NAME = libclang
else ifeq ($(shell uname -s),Darwin)
MD5SUM = md5
LIBCLANG_NAME = clang
else ifeq ($(shell uname -s),FreeBSD)
MD5SUM = md5
LIBCLANG_NAME = clang
START_GROUP = -Wl,--start-group
END_GROUP = -Wl,--end-group
else
LIBCLANG_NAME = clang
START_GROUP = -Wl,--start-group
END_GROUP = -Wl,--end-group
endif
# Libraries that should be linked in for the statically linked Clang.
CLANG_LIB_NAMES = clangAnalysis clangARCMigrate clangAST clangASTMatchers clangBasic clangCodeGen clangCrossTU clangDriver clangDynamicASTMatchers clangEdit clangFormat clangFrontend clangFrontendTool clangHandleCXX clangHandleLLVM clangIndex clangLex clangParse clangRewrite clangRewriteFrontend clangSema clangSerialization clangStaticAnalyzerCheckers clangStaticAnalyzerCore clangStaticAnalyzerFrontend clangTooling clangToolingASTDiff clangToolingCore clangToolingInclusions
CLANG_LIBS = $(START_GROUP) $(addprefix -l,$(CLANG_LIB_NAMES)) $(END_GROUP) -lstdc++
# Libraries that should be linked in for the statically linked LLD.
LLD_LIB_NAMES = lldCOFF lldCommon lldCore lldDriver lldELF lldMachO lldMinGW lldReaderWriter lldWasm lldYAML
LLD_LIBS = $(START_GROUP) $(addprefix -l,$(LLD_LIB_NAMES)) $(END_GROUP)
# Other libraries that are needed to link TinyGo.
EXTRA_LIB_NAMES = LLVMInterpreter
# These build targets appear to be the only ones necessary to build all TinyGo
# dependencies. Only building a subset significantly speeds up rebuilding LLVM.
# The Makefile rules convert a name like lldELF to lib/liblldELF.a to match the
# library path (for ninja).
# This list also includes a few tools that are necessary as part of the full
# TinyGo build.
NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm $(addprefix lib/lib,$(addsuffix .a,$(LIBCLANG_NAME) $(CLANG_LIB_NAMES) $(LLD_LIB_NAMES) $(EXTRA_LIB_NAMES)))
# For static linking.
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
CGO_CPPFLAGS+=$(shell $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
CGO_CXXFLAGS=-std=c++14
CGO_LDFLAGS+=$(abspath $(LLVM_BUILDDIR))/lib/lib$(LIBCLANG_NAME).a -L$(abspath $(LLVM_BUILDDIR)/lib) $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
endif
clean:
@rm -rf build
FMT_PATHS = ./*.go builder cgo compiler interp loader src/device/arm src/examples src/machine src/os src/reflect src/runtime src/sync src/syscall src/internal/reflectlite transform
fmt:
@gofmt -l -w $(FMT_PATHS)
fmt-check:
@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
ifneq ($(STM32), 0)
gen-device: gen-device-stm32
endif
gen-device-avr:
@if [ ! -e lib/avr/README.md ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
$(GO) build -o ./build/gen-device-avr ./tools/gen-device-avr/
./build/gen-device-avr lib/avr/packs/atmega src/device/avr/
./build/gen-device-avr lib/avr/packs/tiny src/device/avr/
@GO111MODULE=off $(GO) fmt ./src/device/avr
build/gen-device-svd: ./tools/gen-device-svd/*.go
$(GO) build -o $@ ./tools/gen-device-svd/
gen-device-esp: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Espressif-Community -interrupts=software lib/cmsis-svd/data/Espressif-Community/ src/device/esp/
GO111MODULE=off $(GO) fmt ./src/device/esp
gen-device-nrf: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/NordicSemiconductor/nrfx/tree/master/mdk lib/nrfx/mdk/ src/device/nrf/
GO111MODULE=off $(GO) fmt ./src/device/nrf
gen-device-nxp: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/NXP lib/cmsis-svd/data/NXP/ src/device/nxp/
GO111MODULE=off $(GO) fmt ./src/device/nxp
gen-device-sam: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Atmel lib/cmsis-svd/data/Atmel/ src/device/sam/
GO111MODULE=off $(GO) fmt ./src/device/sam
gen-device-sifive: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/SiFive-Community -interrupts=software lib/cmsis-svd/data/SiFive-Community/ src/device/sifive/
GO111MODULE=off $(GO) fmt ./src/device/sifive
gen-device-kendryte: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Kendryte-Community -interrupts=software lib/cmsis-svd/data/Kendryte-Community/ src/device/kendryte/
GO111MODULE=off $(GO) fmt ./src/device/kendryte
gen-device-stm32: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/tinygo-org/stm32-svd lib/stm32-svd/svd src/device/stm32/
GO111MODULE=off $(GO) fmt ./src/device/stm32
# Get LLVM sources.
$(LLVM_PROJECTDIR)/README.md:
git clone -b xtensa_release_11.0.0 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
llvm-source: $(LLVM_PROJECTDIR)/README.md
# Configure LLVM.
TINYGO_SOURCE_DIR=$(shell pwd)
$(LLVM_BUILDDIR)/build.ninja: llvm-source
mkdir -p $(LLVM_BUILDDIR); cd $(LLVM_BUILDDIR); cmake -G Ninja $(TINYGO_SOURCE_DIR)/$(LLVM_PROJECTDIR)/llvm "-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64;RISCV;WebAssembly" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=AVR;Xtensa" -DCMAKE_BUILD_TYPE=Release -DLIBCLANG_BUILD_STATIC=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ZLIB=OFF -DLLVM_ENABLE_LIBEDIT=OFF -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_ENABLE_OCAMLDOC=OFF -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD=OFF $(LLVM_OPTION)
# Build LLVM.
$(LLVM_BUILDDIR): $(LLVM_BUILDDIR)/build.ninja
cd $(LLVM_BUILDDIR); ninja $(NINJA_BUILD_TARGETS)
# 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 WASM_CC=$(CLANG) WASM_AR=$(LLVM_AR) WASM_NM=$(LLVM_NM)
# Build the Go compiler.
tinygo:
@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)" $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X main.gitSha1=`git rev-parse --short HEAD`" .
test: wasi-libc
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test -v -buildmode exe -tags byollvm ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
# Test known-working standard library packages.
# TODO: do this in one command, parallelize, and only show failing tests (no
# implied -v flag).
.PHONY: tinygo-test
tinygo-test:
$(TINYGO) test container/heap
$(TINYGO) test container/list
$(TINYGO) test container/ring
$(TINYGO) test crypto/des
$(TINYGO) test encoding/ascii85
$(TINYGO) test encoding/base32
$(TINYGO) test encoding/hex
$(TINYGO) test hash/adler32
$(TINYGO) test hash/fnv
$(TINYGO) test hash/crc64
$(TINYGO) test math
$(TINYGO) test math/cmplx
$(TINYGO) test text/scanner
$(TINYGO) test unicode/utf8
.PHONY: smoketest
smoketest:
$(TINYGO) version
# test all examples (except pwm)
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/adc
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinkm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/button
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/button2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/i2s
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/mcp3008
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit examples/microbit-blink
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit-v2 examples/microbit-blink
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/pininterrupt
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/serial
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/systick
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
@$(MD5SUM) test.hex
# test simulated boards on play.tinygo.org
$(TINYGO) build -o test.wasm -tags=arduino examples/blinky1
@$(MD5SUM) test.wasm
$(TINYGO) build -o test.wasm -tags=hifive1b examples/blinky1
@$(MD5SUM) test.wasm
$(TINYGO) build -o test.wasm -tags=reelboard examples/blinky1
@$(MD5SUM) test.wasm
$(TINYGO) build -o test.wasm -tags=pca10040 examples/blinky2
@$(MD5SUM) test.wasm
$(TINYGO) build -o test.wasm -tags=pca10056 examples/blinky2
@$(MD5SUM) test.wasm
$(TINYGO) build -o test.wasm -tags=circuitplay_express examples/blinky1
@$(MD5SUM) test.wasm
# test all targets/boards
$(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit-s110v8 examples/echo
@$(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=pca10031 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=reelboard examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=reelboard examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10056 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10056 examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10059 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10059 examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=trinket-m0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-bluefruit examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/i2s
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=clue-alpha examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.gba -target=gameboy-advance examples/gba-display
@$(MD5SUM) test.gba
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m4 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pybadge examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=metro-m4-airlift examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pyportal examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=particle-argon examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=particle-boron examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=particle-xenon examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pinetime-devkit0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=x9pro examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10056-s140v7 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=reelboard-s140v7 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pygamer examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=xiao examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/dac
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pyportal examples/dac
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=itsybitsy-nrf52840 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=qtpy examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy40 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy36 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=p1am-100 examples/blinky1
@$(MD5SUM) test.hex
# test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m4 examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pyportal examples/pwm
@$(MD5SUM) test.hex
ifneq ($(STM32), 0)
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-stm32f405 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=lgt92 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-f103rb examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-f722ze examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-l432kc examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-l552ze examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco-1 examples/blinky1
@$(MD5SUM) test.hex
endif
ifneq ($(AVR), 0)
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino -scheduler=tasks examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-nano examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=digispark examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=digispark -gc=leaking examples/blinky1
@$(MD5SUM) test.hex
endif
ifneq ($(XTENSA), 0)
$(TINYGO) build -size short -o test.bin -target=esp32-mini32 examples/blinky1
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
@$(MD5SUM) test.bin
endif
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=hifive1-qemu examples/serial
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/export
$(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/main
# test various compiler flags
$(TINYGO) build -size short -o test.hex -target=pca10040 -gc=none -scheduler=none examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=1 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -o test.nro -target=nintendoswitch examples/serial
@$(MD5SUM) test.nro
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
@$(MD5SUM) test.hex
wasmtest:
$(GO) test ./tests/wasm
build/release: tinygo gen-device wasi-libc
@mkdir -p build/release/tinygo/bin
@mkdir -p build/release/tinygo/lib/clang/include
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
@mkdir -p build/release/tinygo/lib/compiler-rt/lib
@mkdir -p build/release/tinygo/lib/nrfx
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libc
@mkdir -p build/release/tinygo/lib/wasi-libc
@mkdir -p build/release/tinygo/pkg/armv6m-none-eabi
@mkdir -p build/release/tinygo/pkg/armv7m-none-eabi
@mkdir -p build/release/tinygo/pkg/armv7em-none-eabi
@echo copying source files
@cp -p build/tinygo$(EXE) build/release/tinygo/bin
@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
@cp -rp lib/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt/lib
@cp -rp lib/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt
@cp -rp lib/compiler-rt/README.txt build/release/tinygo/lib/compiler-rt
@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
@cp -rp lib/picolibc/newlib/libc/locale build/release/tinygo/lib/picolibc/newlib/libc
@cp -rp lib/picolibc/newlib/libc/string build/release/tinygo/lib/picolibc/newlib/libc
@cp -rp lib/picolibc/newlib/libc/tinystdio build/release/tinygo/lib/picolibc/newlib/libc
@cp -rp lib/picolibc-include build/release/tinygo/lib
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
@cp -rp src build/release/tinygo/src
@cp -rp targets build/release/tinygo/targets
./build/tinygo build-library -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/compiler-rt.a compiler-rt
./build/tinygo build-library -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/compiler-rt.a compiler-rt
./build/tinygo build-library -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/compiler-rt.a compiler-rt
./build/tinygo build-library -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/picolibc.a picolibc
./build/tinygo build-library -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/picolibc.a picolibc
./build/tinygo build-library -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/picolibc.a picolibc
release: build/release
tar -czf build/release.tar.gz -C build/release tinygo
deb: build/release
@mkdir -p build/release-deb/usr/local/bin
@mkdir -p build/release-deb/usr/local/lib
cp -ar build/release/tinygo build/release-deb/usr/local/lib/tinygo
ln -sf ../lib/tinygo/bin/tinygo build/release-deb/usr/local/bin/tinygo
fpm -f -s dir -t deb -n tinygo -v $(shell grep "const Version = " goenv/version.go | awk '{print $$NF}') -m '@tinygo-org' --description='TinyGo is a Go compiler for small places.' --license='BSD 3-Clause' --url=https://tinygo.org/ --deb-changelog CHANGELOG.md -p build/release.deb -C ./build/release-deb
+53 -63
View File
@@ -1,11 +1,13 @@
# TinyGo - Go compiler for small places
[![CircleCI](https://circleci.com/gh/tinygo-org/tinygo/tree/dev.svg?style=svg)](https://circleci.com/gh/tinygo-org/tinygo/tree/dev) [![Build Status](https://dev.azure.com/tinygo/tinygo/_apis/build/status/tinygo-CI?branchName=dev)](https://dev.azure.com/tinygo/tinygo/_build/latest?definitionId=1&branchName=dev)
[![Linux](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml) [![macOS](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml) [![Windows](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml) [![Docker](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml) [![Nix](https://github.com/tinygo-org/tinygo/actions/workflows/nix.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/nix.yml) [![CircleCI](https://circleci.com/gh/tinygo-org/tinygo/tree/dev.svg?style=svg)](https://circleci.com/gh/tinygo-org/tinygo/tree/dev)
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (Wasm), and command-line tools.
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (wasm/wasi), and command-line tools.
It reuses libraries used by the [Go language tools](https://golang.org/pkg/go/) alongside [LLVM](http://llvm.org) to provide an alternative way to compile programs written in the Go programming language.
## Embedded
Here is an example program that blinks the built-in LED when run directly on any supported board with onboard LED:
```go
@@ -35,73 +37,62 @@ The above program can be compiled and run without modification on an Arduino Uno
tinygo flash -target arduino examples/blinky1
```
## WebAssembly
TinyGo is very useful for compiling programs both for use in browsers (WASM) as well as for use on servers and other edge devices (WASI).
TinyGo programs can run in [Fastly Compute](https://www.fastly.com/documentation/guides/compute/go/), [Fermyon Spin](https://developer.fermyon.com/spin/go-components), [wazero](https://wazero.io/languages/tinygo/) and many other WebAssembly runtimes.
Here is a small TinyGo program for use by a WASI host application:
```go
package main
//go:wasm-module yourmodulename
//export add
func add(x, y uint32) uint32 {
return x + y
}
// main is required for the `wasip1` target, even if it isn't used.
func main() {}
```
This compiles the above TinyGo program for use on any WASI runtime:
```shell
tinygo build -o main.wasm -target=wasip1 main.go
```
## Installation
See the [getting started instructions](https://tinygo.org/getting-started/) for information on how to install TinyGo, as well as how to run the TinyGo compiler using our Docker container.
## Supported boards/targets
## Supported targets
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
### Embedded
The following 55 microcontroller boards are currently supported:
You can compile TinyGo programs for over 94 different microcontroller boards.
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
* [Adafruit CLUE](https://www.adafruit.com/product/4500)
* [Adafruit Feather M0](https://www.adafruit.com/product/2772)
* [Adafruit Feather M4](https://www.adafruit.com/product/3857)
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
* [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
* [Adafruit ItsyBitsy M4](https://www.adafruit.com/product/3800)
* [Adafruit ItsyBitsy nRF52840](https://www.adafruit.com/product/4481)
* [Adafruit Matrix Portal M4](https://www.adafruit.com/product/4745)
* [Adafruit Metro M4 Express Airlift](https://www.adafruit.com/product/4000)
* [Adafruit PyBadge](https://www.adafruit.com/product/4200)
* [Adafruit PyGamer](https://www.adafruit.com/product/4242)
* [Adafruit PyPortal](https://www.adafruit.com/product/4116)
* [Adafruit QT Py](https://www.adafruit.com/product/4600)
* [Adafruit Trinket M0](https://www.adafruit.com/product/3500)
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
* [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi)
* [Arduino Nano](https://store.arduino.cc/arduino-nano)
* [Arduino Nano33 IoT](https://store.arduino.cc/nano-33-iot)
* [Arduino Uno](https://store.arduino.cc/arduino-uno-rev3)
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
* [BBC micro:bit](https://microbit.org/)
* [BBC micro:bit v2](https://microbit.org/new-microbit/)
* [Digispark](http://digistump.com/products/1)
* [Dragino LoRaWAN GPS Tracker LGT-92](http://www.dragino.com/products/lora-lorawan-end-node/item/142-lgt-92.html)
* [ESP32](https://www.espressif.com/en/products/socs/esp32)
* [ESP8266](https://www.espressif.com/en/products/socs/esp8266)
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
* [Makerdiary nRF52840-MDK](https://wiki.makerdiary.com/nrf52840-mdk/)
* [Makerdiary nRF52840-MDK USB Dongle](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/)
* [nice!nano](https://docs.nicekeyboards.com/#/nice!nano/)
* [Nintendo Switch](https://www.nintendo.com/switch/)
* [Nordic Semiconductor PCA10031](https://www.nordicsemi.com/eng/Products/nRF51-Dongle)
* [Nordic Semiconductor PCA10040](https://www.nordicsemi.com/eng/Products/Bluetooth-low-energy/nRF52-DK)
* [Nordic Semiconductor PCA10056](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
* [Particle Argon](https://docs.particle.io/datasheets/wi-fi/argon-datasheet/)
* [Particle Boron](https://docs.particle.io/datasheets/cellular/boron-datasheet/)
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
* [Phytec reel board](https://www.phytec.eu/product-eu/internet-of-things/reelboard/)
* [PineTime DevKit](https://www.pine64.org/pinetime/)
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
* [ProductivityOpen P1AM-100](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html)
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
* [SiFIve HiFive1](https://www.sifive.com/boards/hifive1)
* [ST Micro "Nucleo" F103RB](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html)
* [ST Micro "Nucleo" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
* [ST Micro "Nucleo" L552ZE](https://www.st.com/en/evaluation-tools/nucleo-l552ze-q.html)
* [ST Micro STM32F103XX "Bluepill"](https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill)
* [ST Micro STM32F407 "Discovery"](https://www.st.com/en/evaluation-tools/stm32f4discovery.html)
* [X9 Pro smartwatch](https://github.com/curtpw/nRF5x-device-reverse-engineering/tree/master/X9-nrf52832-activity-tracker/)
For more information, please see https://tinygo.org/docs/reference/microcontrollers/
For more information, see [this list of boards](https://tinygo.org/microcontrollers/). Pull requests for additional support are welcome!
### WebAssembly
TinyGo programs can be compiled for both WASM and WASI targets.
For more information, see https://tinygo.org/docs/guides/webassembly/
### Operating Systems
You can also compile programs for Linux, macOS, and Windows targets.
For more information:
- Linux https://tinygo.org/docs/guides/linux/
- macOS https://tinygo.org/docs/guides/macos/
- Windows https://tinygo.org/docs/guides/windows/
## Currently supported features:
@@ -126,7 +117,7 @@ should arrive fairly quickly (under 1 min): https://invite.slack.golangbridge.or
Your contributions are welcome!
Please take a look at our [CONTRIBUTING.md](./CONTRIBUTING.md) document for details.
Please take a look at our [Contributing](https://tinygo.org/docs/guides/contributing/) page on our web site for details.
## Project Scope
@@ -140,7 +131,6 @@ Goals:
Non-goals:
* Using more than one core.
* Be efficient while using zillions of goroutines. However, good goroutine support is certainly a goal.
* Be as fast as `gc`. However, LLVM will probably be better at optimizing certain things so TinyGo might actually turn out to be faster for number crunching.
* Be able to compile every Go program out there.
-88
View File
@@ -1,88 +0,0 @@
# Avoid lengthy LLVM rebuilds on each newly pushed branch. Pull requests will
# be built anyway.
trigger:
- release
- dev
jobs:
- job: Build
timeoutInMinutes: 240 # 4h
pool:
vmImage: 'VS2017-Win2016'
steps:
- task: GoTool@0
inputs:
version: '1.16'
- checkout: self
fetchDepth: 1
- task: Cache@2
displayName: Cache LLVM source
inputs:
key: llvm-source-11-windows-v1
path: llvm-project
- task: Bash@3
displayName: Download LLVM source
inputs:
targetType: inline
script: make llvm-source
- task: CacheBeta@0
displayName: Cache LLVM build
inputs:
key: llvm-build-11-windows-v4
path: llvm-build
- task: Bash@3
displayName: Build LLVM
inputs:
targetType: inline
script: |
if [ ! -f llvm-build/lib/liblldELF.a ]
then
# install dependencies
choco install ninja
# hack ninja to use fewer jobs
echo -e 'C:\\ProgramData\\Chocolatey\\bin\\ninja -j4 %*' > /usr/bin/ninja.bat
# build!
make llvm-build
fi
- task: Bash@3
displayName: Install QEMU
inputs:
targetType: inline
script: choco install qemu --version=2020.06.12
- task: CacheBeta@0
displayName: Cache wasi-libc sysroot
inputs:
key: wasi-libc-sysroot-v4
path: lib/wasi-libc/sysroot
- task: Bash@3
displayName: Build wasi-libc
inputs:
targetType: inline
script: PATH=/usr/bin:$PATH make wasi-libc
- task: Bash@3
displayName: Test TinyGo
inputs:
targetType: inline
script: |
export PATH="$PATH:./llvm-build/bin:/c/Program Files/qemu"
unset GOROOT
make test
- task: Bash@3
displayName: Build TinyGo release tarball
inputs:
targetType: inline
script: |
export PATH="$PATH:./llvm-build/bin:/c/Program Files/qemu"
unset GOROOT
make build/release -j4
- publish: $(System.DefaultWorkingDirectory)/build/release/tinygo
displayName: Publish zip as artifact
artifact: tinygo
- task: Bash@3
displayName: Smoke tests
inputs:
targetType: inline
script: |
export PATH="$PATH:./llvm-build/bin:/c/Program Files/qemu"
unset GOROOT
make smoketest TINYGO=build/tinygo AVR=0 XTENSA=0
+98 -46
View File
@@ -3,31 +3,29 @@ package builder
import (
"bytes"
"debug/elf"
"debug/pe"
"encoding/binary"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"time"
wasm "github.com/aykevl/go-wasm"
"github.com/blakesmith/ar"
)
// makeArchive creates an arcive for static linking from a list of object files
// given as a parameter. It is equivalent to the following command:
//
// ar -rcs <archivePath> <objs...>
func makeArchive(archivePath string, objs []string) error {
// ar -rcs <archivePath> <objs...>
func makeArchive(arfile *os.File, objs []string) error {
// Open the archive file.
arfile, err := os.Create(archivePath)
if err != nil {
return err
}
defer arfile.Close()
arwriter := ar.NewWriter(arfile)
err = arwriter.WriteGlobalHeader()
err := arwriter.WriteGlobalHeader()
if err != nil {
return &os.PathError{"write ar header", archivePath, err}
return &os.PathError{Op: "write ar header", Path: arfile.Name(), Err: err}
}
// Open all object files and read the symbols for the symbol table.
@@ -35,43 +33,82 @@ func makeArchive(archivePath string, objs []string) error {
name string // symbol name
fileIndex int // index into objfiles
}{}
objfiles := make([]struct {
file *os.File
archiveOffset int32
}, len(objs))
archiveOffsets := make([]int32, len(objs))
for i, objpath := range objs {
objfile, err := os.Open(objpath)
if err != nil {
return err
}
objfiles[i].file = objfile
// Read the symbols and add them to the symbol table.
dbg, err := elf.NewFile(objfile)
if err != nil {
return err
}
symbols, err := dbg.Symbols()
if err != nil {
return err
}
for _, symbol := range symbols {
bind := elf.ST_BIND(symbol.Info)
if bind != elf.STB_GLOBAL && bind != elf.STB_WEAK {
// Don't include local symbols (STB_LOCAL).
continue
if dbg, err := elf.NewFile(objfile); err == nil {
symbols, err := dbg.Symbols()
if err != nil {
return err
}
if elf.ST_TYPE(symbol.Info) != elf.STT_FUNC {
// Not a function.
// TODO: perhaps globals variables should also be included?
continue
for _, symbol := range symbols {
bind := elf.ST_BIND(symbol.Info)
if bind != elf.STB_GLOBAL && bind != elf.STB_WEAK {
// Don't include local symbols (STB_LOCAL).
continue
}
if elf.ST_TYPE(symbol.Info) != elf.STT_FUNC && elf.ST_TYPE(symbol.Info) != elf.STT_OBJECT {
// Not a function.
continue
}
// Include in archive.
symbolTable = append(symbolTable, struct {
name string
fileIndex int
}{symbol.Name, i})
}
// Include in archive.
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 {
continue
}
if symbol.SectionNumber == 0 {
continue
}
symbolTable = append(symbolTable, struct {
name string
fileIndex int
}{symbol.Name, i})
}
} else if dbg, err := wasm.Parse(objfile); err == nil {
for _, s := range dbg.Sections {
switch section := s.(type) {
case *wasm.SectionLinking:
for _, symbol := range section.Symbols {
if symbol.Flags&wasm.LinkingSymbolFlagUndefined != 0 {
// Don't list undefined functions.
continue
}
if symbol.Flags&wasm.LinkingSymbolFlagBindingLocal != 0 {
// Don't include local symbols.
continue
}
if symbol.Kind != wasm.LinkingSymbolKindFunction && symbol.Kind != wasm.LinkingSymbolKindData {
// Link functions and data symbols.
// Some data symbols need to be included, such as
// __log_data.
continue
}
// Include in the archive.
symbolTable = append(symbolTable, struct {
name string
fileIndex int
}{symbol.Name, i})
}
}
}
} else {
return fmt.Errorf("failed to open file %s as WASM, ELF or PE/COFF: %w", objpath, err)
}
// Close file, to avoid issues with too many open files (especially on
// MacOS X).
objfile.Close()
}
// Create the symbol table buffer.
@@ -125,7 +162,14 @@ func makeArchive(archivePath string, objs []string) error {
}
// Add all object files to the archive.
for i, objfile := range objfiles {
var copyBuf bytes.Buffer
for i, objpath := range objs {
objfile, err := os.Open(objpath)
if err != nil {
return err
}
defer objfile.Close()
// Store the start index, for when we'll update the symbol table with
// the correct file start indices.
offset, err := arfile.Seek(0, os.SEEK_CUR)
@@ -133,17 +177,17 @@ func makeArchive(archivePath string, objs []string) error {
return err
}
if int64(int32(offset)) != offset {
return errors.New("large archives (4GB+) not supported: " + archivePath)
return errors.New("large archives (4GB+) not supported: " + arfile.Name())
}
objfiles[i].archiveOffset = int32(offset)
archiveOffsets[i] = int32(offset)
// Write the file header.
st, err := objfile.file.Stat()
st, err := objfile.Stat()
if err != nil {
return err
}
err = arwriter.WriteHeader(&ar.Header{
Name: filepath.Base(objfile.file.Name()),
Name: filepath.Base(objfile.Name()),
ModTime: time.Unix(0, 0),
Uid: 0,
Gid: 0,
@@ -155,22 +199,30 @@ func makeArchive(archivePath string, objs []string) error {
}
// Copy the file contents into the archive.
n, err := io.Copy(arwriter, objfile.file)
// First load all contents into a buffer, then write it all in one go to
// the archive file. This is a bit complicated, but is necessary because
// io.Copy can't deal with files that are of an odd size.
copyBuf.Reset()
n, err := io.Copy(&copyBuf, objfile)
if err != nil {
return err
return fmt.Errorf("could not copy object file into ar file: %w", err)
}
if n != st.Size() {
return errors.New("file modified during ar creation: " + archivePath)
return errors.New("file modified during ar creation: " + arfile.Name())
}
_, err = arwriter.Write(copyBuf.Bytes())
if err != nil {
return fmt.Errorf("could not copy object file into ar file: %w", err)
}
// File is not needed anymore.
objfile.file.Close()
objfile.Close()
}
// Create symbol indices.
indicesBuf := &bytes.Buffer{}
for _, sym := range symbolTable {
err = binary.Write(indicesBuf, binary.BigEndian, objfiles[sym.fileIndex].archiveOffset)
err = binary.Write(indicesBuf, binary.BigEndian, archiveOffsets[sym.fileIndex])
if err != nil {
return err
}
+780 -247
View File
File diff suppressed because it is too large Load Diff
-105
View File
@@ -1,105 +0,0 @@
package builder
import (
"io"
"os"
"path/filepath"
"time"
"github.com/tinygo-org/tinygo/goenv"
)
// Return the newest timestamp of all the file paths passed in. Used to check
// for stale caches.
func cacheTimestamp(paths []string) (time.Time, error) {
var timestamp time.Time
for _, path := range paths {
st, err := os.Stat(path)
if err != nil {
return time.Time{}, err
}
if timestamp.IsZero() {
timestamp = st.ModTime()
} else if timestamp.Before(st.ModTime()) {
timestamp = st.ModTime()
}
}
return timestamp, nil
}
// Try to load a given file from the cache. Return "", nil if no cached file can
// be found (or the file is stale), return the absolute path if there is a cache
// and return an error on I/O errors.
func cacheLoad(name string, sourceFiles []string) (string, error) {
cachepath := filepath.Join(goenv.Get("GOCACHE"), name)
cacheStat, err := os.Stat(cachepath)
if os.IsNotExist(err) {
return "", nil // does not exist
} else if err != nil {
return "", err // cannot stat cache file
}
sourceTimestamp, err := cacheTimestamp(sourceFiles)
if err != nil {
return "", err // cannot stat source files
}
if cacheStat.ModTime().After(sourceTimestamp) {
return cachepath, nil
} else {
os.Remove(cachepath)
// stale cache
return "", nil
}
}
// Store the file located at tmppath in the cache with the given name. The
// tmppath may or may not be gone afterwards.
func cacheStore(tmppath, name string, sourceFiles []string) (string, error) {
// get the last modified time
if len(sourceFiles) == 0 {
panic("cache: no source files")
}
// TODO: check the config key
dir := goenv.Get("GOCACHE")
err := os.MkdirAll(dir, 0777)
if err != nil {
return "", err
}
cachepath := filepath.Join(dir, name)
err = copyFile(tmppath, cachepath)
if err != nil {
return "", err
}
return cachepath, nil
}
// copyFile copies the given file from src to dst. It can copy over
// a possibly already existing file at the destination.
func copyFile(src, dst string) error {
inf, err := os.Open(src)
if err != nil {
return err
}
defer inf.Close()
outpath := dst + ".tmp"
outf, err := os.Create(outpath)
if err != nil {
return err
}
_, err = io.Copy(outf, inf)
if err != nil {
os.Remove(outpath)
return err
}
err = outf.Close()
if err != nil {
return err
}
return os.Rename(dst+".tmp", dst)
}
+167
View File
@@ -0,0 +1,167 @@
package builder
import (
"fmt"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/tinygo-org/tinygo/compileopts"
"tinygo.org/x/go-llvm"
)
// Test whether the Clang generated "target-cpu" and "target-features"
// attributes match the CPU and Features property in TinyGo target files.
func TestClangAttributes(t *testing.T) {
var targetNames = []string{
// Please keep this list sorted!
"atmega328p",
"atmega1280",
"atmega1284p",
"atmega2560",
"attiny85",
"cortex-m0",
"cortex-m0plus",
"cortex-m3",
"cortex-m33",
"cortex-m4",
"cortex-m7",
"esp32c3",
"fe310",
"gameboy-advance",
"k210",
"nintendoswitch",
"riscv-qemu",
"wasip1",
"wasm",
"wasm-unknown",
}
if hasBuiltinTools {
// hasBuiltinTools is set when TinyGo is statically linked with LLVM,
// which also implies it was built with Xtensa support.
targetNames = append(targetNames, "esp32", "esp8266")
}
for _, targetName := range targetNames {
targetName := targetName
t.Run(targetName, func(t *testing.T) {
testClangAttributes(t, &compileopts.Options{Target: targetName})
})
}
for _, options := range []*compileopts.Options{
{GOOS: "linux", GOARCH: "386"},
{GOOS: "linux", GOARCH: "amd64"},
{GOOS: "linux", GOARCH: "arm", GOARM: "5"},
{GOOS: "linux", GOARCH: "arm", GOARM: "6"},
{GOOS: "linux", GOARCH: "arm", GOARM: "7"},
{GOOS: "linux", GOARCH: "arm64"},
{GOOS: "darwin", GOARCH: "amd64"},
{GOOS: "darwin", GOARCH: "arm64"},
{GOOS: "windows", GOARCH: "amd64"},
{GOOS: "windows", GOARCH: "arm64"},
{GOOS: "wasip1", GOARCH: "wasm"},
} {
name := "GOOS=" + options.GOOS + ",GOARCH=" + options.GOARCH
if options.GOARCH == "arm" {
name += ",GOARM=" + options.GOARM
}
t.Run(name, func(t *testing.T) {
testClangAttributes(t, options)
})
}
}
func testClangAttributes(t *testing.T, options *compileopts.Options) {
testDir := t.TempDir()
ctx := llvm.NewContext()
defer ctx.Dispose()
target, err := compileopts.LoadTarget(options)
if err != nil {
t.Fatalf("could not load target: %s", err)
}
config := compileopts.Config{
Options: options,
Target: target,
}
// Create a very simple C input file.
srcpath := filepath.Join(testDir, "test.c")
err = os.WriteFile(srcpath, []byte("int add(int a, int b) { return a + b; }"), 0o666)
if err != nil {
t.Fatalf("could not write target file %s: %s", srcpath, err)
}
// Compile this file using Clang.
outpath := filepath.Join(testDir, "test.bc")
flags := append([]string{"-c", "-emit-llvm", "-o", outpath, srcpath}, config.CFlags(false)...)
if config.GOOS() == "darwin" {
// Silence some warnings that happen when testing GOOS=darwin on
// something other than MacOS.
flags = append(flags, "-Wno-missing-sysroot", "-Wno-incompatible-sysroot")
}
err = runCCompiler(flags...)
if err != nil {
t.Fatalf("failed to compile %s: %s", srcpath, err)
}
// Read the resulting LLVM bitcode.
mod, err := ctx.ParseBitcodeFile(outpath)
if err != nil {
t.Fatalf("could not parse bitcode file %s: %s", outpath, err)
}
defer mod.Dispose()
// Check whether the LLVM target matches.
if mod.Target() != config.Triple() {
t.Errorf("target has LLVM triple %#v but Clang makes it LLVM triple %#v", config.Triple(), mod.Target())
}
// Check the "target-cpu" and "target-features" string attribute of the add
// function.
add := mod.NamedFunction("add")
var cpu, features string
cpuAttr := add.GetStringAttributeAtIndex(-1, "target-cpu")
featuresAttr := add.GetStringAttributeAtIndex(-1, "target-features")
if !cpuAttr.IsNil() {
cpu = cpuAttr.GetStringValue()
}
if !featuresAttr.IsNil() {
features = featuresAttr.GetStringValue()
}
if cpu != config.CPU() {
t.Errorf("target has CPU %#v but Clang makes it CPU %#v", config.CPU(), cpu)
}
if features != config.Features() {
if hasBuiltinTools || runtime.GOOS != "linux" {
// Skip this step when using an external Clang invocation on Linux.
// The reason is that Debian has patched Clang in a way that
// modifies the LLVM features string, changing lots of FPU/float
// related flags. We want to test vanilla Clang, not Debian Clang.
t.Errorf("target has LLVM features\n\t%#v\nbut Clang makes it\n\t%#v", config.Features(), features)
}
}
}
// This TestMain is necessary because TinyGo may also be invoked to run certain
// LLVM tools in a separate process. Not capturing these invocations would lead
// to recursive tests.
func TestMain(m *testing.M) {
if len(os.Args) >= 2 {
switch os.Args[1] {
case "clang", "ld.lld", "wasm-ld":
// Invoke a specific tool.
err := RunTool(os.Args[1], os.Args[2:]...)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
os.Exit(0)
}
}
// Run normal tests.
os.Exit(m.Run())
}
+127
View File
@@ -0,0 +1,127 @@
package builder
import (
"bytes"
"debug/elf"
"debug/macho"
"encoding/binary"
"fmt"
"io"
"os"
"runtime"
)
// ReadBuildID reads the build ID from the currently running executable.
func ReadBuildID() ([]byte, error) {
executable, err := os.Executable()
if err != nil {
return nil, err
}
f, err := os.Open(executable)
if err != nil {
return nil, err
}
defer f.Close()
switch runtime.GOOS {
case "linux", "freebsd", "android":
// Read the GNU build id section. (Not sure about FreeBSD though...)
file, err := elf.NewFile(f)
if err != nil {
return nil, err
}
var gnuID, goID []byte
for _, section := range file.Sections {
if section.Type != elf.SHT_NOTE ||
(section.Name != ".note.gnu.build-id" && section.Name != ".note.go.buildid") {
continue
}
buf := make([]byte, section.Size)
n, err := section.ReadAt(buf, 0)
if uint64(n) != section.Size || err != nil {
return nil, fmt.Errorf("could not read build id: %w", err)
}
if section.Name == ".note.gnu.build-id" {
gnuID = buf
} else {
goID = buf
}
}
if gnuID != nil {
return gnuID, nil
} else if goID != nil {
return goID, nil
}
case "darwin":
// Read the LC_UUID load command, which contains the equivalent of a
// build ID.
file, err := macho.NewFile(f)
if err != nil {
return nil, err
}
for _, load := range file.Loads {
// Unfortunately, the debug/macho package doesn't support the
// LC_UUID command directly. So we have to read it from
// macho.LoadBytes.
load, ok := load.(macho.LoadBytes)
if !ok {
continue
}
raw := load.Raw()
command := binary.LittleEndian.Uint32(raw)
if command != 0x1b {
// Looking for the LC_UUID load command.
// LC_UUID is defined here as 0x1b:
// https://opensource.apple.com/source/xnu/xnu-4570.71.2/EXTERNAL_HEADERS/mach-o/loader.h.auto.html
continue
}
return raw[4:], nil
}
// Normally we would have found a build ID by now. But not on Nix,
// unfortunately, because Nix adds -no_uuid for some reason:
// https://github.com/NixOS/nixpkgs/issues/178366
// Fall back to the same implementation that we use for Windows.
id, err := readRawGoBuildID(f, 32*1024)
if len(id) != 0 || err != nil {
return id, err
}
default:
// On other platforms (such as Windows) there isn't such a convenient
// build ID. Luckily, Go does have an equivalent of the build ID, which
// is stored as a special symbol named go.buildid. You can read it
// using `go tool buildid`, but the code below extracts it directly
// from the binary.
// Unfortunately, because of stripping with the -w flag, no symbol
// table might be available. Therefore, we have to scan the binary
// directly. Luckily the build ID is always at the start of the file.
// For details, see:
// https://github.com/golang/go/blob/master/src/cmd/internal/buildid/buildid.go
id, err := readRawGoBuildID(f, 4096)
if len(id) != 0 || err != nil {
return id, err
}
}
return nil, fmt.Errorf("could not find build ID in %v", executable)
}
// The Go toolchain stores a build ID in the binary that we can use, as a
// fallback if binary file specific build IDs can't be obtained.
// This function reads that build ID from the binary.
func readRawGoBuildID(f *os.File, prefixSize int) ([]byte, error) {
fileStart := make([]byte, prefixSize)
_, err := io.ReadFull(f, fileStart)
if err != nil {
return nil, fmt.Errorf("could not read build id from %s: %v", f.Name(), err)
}
index := bytes.Index(fileStart, []byte("\xff Go build ID: \""))
if index < 0 || index > len(fileStart)-103 {
return nil, fmt.Errorf("could not find build id in %s", f.Name())
}
buf := fileStart[index : index+103]
if bytes.HasPrefix(buf, []byte("\xff Go build ID: \"")) && bytes.HasSuffix(buf, []byte("\"\n \xff")) {
return buf[len("\xff Go build ID: \"") : len(buf)-1], nil
}
return nil, nil
}
+45 -14
View File
@@ -1,17 +1,21 @@
package builder
import (
"os"
"path/filepath"
"strings"
"github.com/tinygo-org/tinygo/goenv"
)
// These are the GENERIC_SOURCES according to CMakeList.txt.
// These are the GENERIC_SOURCES according to CMakeList.txt except for
// divmodsi4.c and udivmodsi4.c.
var genericBuiltins = []string{
"absvdi2.c",
"absvsi2.c",
"absvti2.c",
"adddf3.c",
"addsf3.c",
"addtf3.c",
"addvdi3.c",
"addvsi3.c",
"addvti3.c",
@@ -36,13 +40,12 @@ var genericBuiltins = []string{
"divdf3.c",
"divdi3.c",
"divmoddi4.c",
"divmodsi4.c",
//"divmodsi4.c",
"divmodti4.c",
"divsc3.c",
"divsf3.c",
"divsi3.c",
"divtc3.c",
"divti3.c",
"divtf3.c",
"extendsfdf2.c",
"extendhfsf2.c",
"ffsdi2.c",
@@ -72,6 +75,7 @@ var genericBuiltins = []string{
"floatunsisf.c",
"floatuntidf.c",
"floatuntisf.c",
"fp_mode.c",
//"int_util.c",
"lshrdi3.c",
"lshrti3.c",
@@ -87,7 +91,6 @@ var genericBuiltins = []string{
"mulsc3.c",
"mulsf3.c",
"multi3.c",
"multf3.c",
"mulvdi3.c",
"mulvsi3.c",
"mulvti3.c",
@@ -107,13 +110,11 @@ var genericBuiltins = []string{
"popcountti2.c",
"powidf2.c",
"powisf2.c",
"powitf2.c",
"subdf3.c",
"subsf3.c",
"subvdi3.c",
"subvsi3.c",
"subvti3.c",
"subtf3.c",
"trampoline_setup.c",
"truncdfhf2.c",
"truncdfsf2.c",
@@ -122,7 +123,7 @@ var genericBuiltins = []string{
"ucmpti2.c",
"udivdi3.c",
"udivmoddi4.c",
"udivmodsi4.c",
//"udivmodsi4.c",
"udivmodti4.c",
"udivsi3.c",
"udivti3.c",
@@ -149,6 +150,23 @@ var aeabiBuiltins = []string{
"arm/aeabi_memset.S",
"arm/aeabi_uidivmod.S",
"arm/aeabi_uldivmod.S",
// These two are not technically EABI builtins but are used by them and only
// seem to be used on ARM. LLVM seems to use __divsi3 and __modsi3 on most
// other architectures.
// Most importantly, they have a different calling convention on AVR so
// should not be used on AVR.
"divmodsi4.c",
"udivmodsi4.c",
}
var avrBuiltins = []string{
"avr/divmodhi4.S",
"avr/divmodqi4.S",
"avr/mulhi3.S",
"avr/mulqi3.S",
"avr/udivmodhi4.S",
"avr/udivmodqi4.S",
}
// CompilerRT is a library with symbols required by programs compiled with LLVM.
@@ -157,14 +175,27 @@ var aeabiBuiltins = []string{
//
// For more information, see: https://compiler-rt.llvm.org/
var CompilerRT = Library{
name: "compiler-rt",
cflags: func() []string { return []string{"-Werror", "-Wall", "-std=c11", "-nostdlibinc"} },
sourceDir: "lib/compiler-rt/lib/builtins",
sources: func(target string) []string {
name: "compiler-rt",
cflags: func(target, headerPath string) []string {
return []string{"-Werror", "-Wall", "-std=c11", "-nostdlibinc"}
},
sourceDir: func() string {
llvmDir := filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project/compiler-rt/lib/builtins")
if _, err := os.Stat(llvmDir); err == nil {
// Release build.
return llvmDir
}
// Development build.
return filepath.Join(goenv.Get("TINYGOROOT"), "lib/compiler-rt-builtins")
},
librarySources: func(target string) ([]string, error) {
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
builtins = append(builtins, aeabiBuiltins...)
}
return builtins
if strings.HasPrefix(target, "avr") {
builtins = append(builtins, avrBuiltins...)
}
return builtins, nil
},
}
+60 -47
View File
@@ -10,14 +10,13 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"io/fs"
"os"
"path/filepath"
"sort"
"strings"
"unicode"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
"tinygo.org/x/go-llvm"
)
@@ -34,48 +33,50 @@ import (
// Because of this complexity, every file has in fact two cached build outputs:
// the file itself, and the list of dependencies. Its operation is as follows:
//
// depfile = hash(path, compiler, cflags, ...)
// if depfile exists:
// outfile = hash of all files and depfile name
// if outfile exists:
// # cache hit
// return outfile
// # cache miss
// tmpfile = compile file
// read dependencies (side effect of compile)
// write depfile
// outfile = hash of all files and depfile name
// rename tmpfile to outfile
// depfile = hash(path, compiler, cflags, ...)
// if depfile exists:
// outfile = hash of all files and depfile name
// if outfile exists:
// # cache hit
// return outfile
// # cache miss
// tmpfile = compile file
// read dependencies (side effect of compile)
// write depfile
// outfile = hash of all files and depfile name
// rename tmpfile to outfile
//
// There are a few edge cases that are not handled:
// - If a file is added to an include path, that file may be included instead of
// some other file. This would be fixed by also including lookup failures in the
// dependencies file, but I'm not aware of a compiler which does that.
// - The Makefile syntax that compilers output has issues, see readDepFile for
// details.
// - A header file may be changed to add/remove an include. This invalidates the
// depfile but without invalidating its name. For this reason, the depfile is
// written on each new compilation (even when it seems unnecessary). However, it
// could in rare cases lead to a stale file fetched from the cache.
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, config *compileopts.Config) (string, error) {
// - If a file is added to an include path, that file may be included instead of
// some other file. This would be fixed by also including lookup failures in the
// dependencies file, but I'm not aware of a compiler which does that.
// - The Makefile syntax that compilers output has issues, see readDepFile for
// details.
// - A header file may be changed to add/remove an include. This invalidates the
// depfile but without invalidating its name. For this reason, the depfile is
// written on each new compilation (even when it seems unnecessary). However, it
// could in rare cases lead to a stale file fetched from the cache.
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands func(string, ...string)) (string, error) {
// Hash input file.
fileHash, err := hashFile(abspath)
if err != nil {
return "", err
}
// Acquire a lock (if supported).
unlock := lock(filepath.Join(goenv.Get("GOCACHE"), fileHash+".c.lock"))
defer unlock()
// Create cache key for the dependencies file.
buf, err := json.Marshal(struct {
Path string
Hash string
Compiler string
Flags []string
LLVMVersion string
}{
Path: abspath,
Hash: fileHash,
Compiler: config.Target.Compiler,
Flags: config.CFlags(),
Flags: cflags,
LLVMVersion: llvm.Version,
})
if err != nil {
@@ -87,7 +88,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, config *compi
// Load dependencies file, if possible.
depfileName := "dep-" + depfileNameHash + ".json"
depfileCachePath := filepath.Join(goenv.Get("GOCACHE"), depfileName)
depfileBuf, err := ioutil.ReadFile(depfileCachePath)
depfileBuf, err := os.ReadFile(depfileCachePath)
var dependencies []string // sorted list of dependency paths
if err == nil {
// There is a dependency file, that's great!
@@ -102,32 +103,39 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, config *compi
if err == nil {
if _, err := os.Stat(outpath); err == nil {
return outpath, nil
} else if !os.IsNotExist(err) {
} else if !errors.Is(err, fs.ErrNotExist) {
return "", err
}
}
} else if !os.IsNotExist(err) {
} else if !errors.Is(err, fs.ErrNotExist) {
// expected either nil or IsNotExist
return "", err
}
objTmpFile, err := ioutil.TempFile(goenv.Get("GOCACHE"), "tmp-*.o")
objTmpFile, err := os.CreateTemp(goenv.Get("GOCACHE"), "tmp-*.bc")
if err != nil {
return "", err
}
objTmpFile.Close()
depTmpFile, err := ioutil.TempFile(tmpdir, "dep-*.d")
depTmpFile, err := os.CreateTemp(tmpdir, "dep-*.d")
if err != nil {
return "", err
}
depTmpFile.Close()
flags := append([]string{}, cflags...) // copy cflags
flags = append(flags, "-MD", "-MV", "-MTdeps", "-MF", depTmpFile.Name()) // autogenerate dependencies
flags := append([]string{}, cflags...) // copy cflags
flags = append(flags, "-MD", "-MV", "-MTdeps", "-MF", depTmpFile.Name(), "-flto=thin") // autogenerate dependencies
flags = append(flags, "-c", "-o", objTmpFile.Name(), abspath)
if config.Options.PrintCommands {
fmt.Printf("%s %s\n", config.Target.Compiler, strings.Join(flags, " "))
if strings.ToLower(filepath.Ext(abspath)) == ".s" {
// If this is an assembly file (.s or .S, lowercase or uppercase), then
// we'll need to add -Qunused-arguments because many parameters are
// relevant to C, not assembly. And with -Werror, having meaningless
// flags (for the assembler) is a compiler error.
flags = append(flags, "-Qunused-arguments")
}
err = runCCompiler(config.Target.Compiler, flags...)
if printCommands != nil {
printCommands("clang", flags...)
}
err = runCCompiler(flags...)
if err != nil {
return "", &commandError{"failed to build", abspath, err}
}
@@ -150,7 +158,11 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, config *compi
sort.Strings(dependencySlice)
// Write dependencies file.
f, err := ioutil.TempFile(filepath.Dir(depfileCachePath), depfileName)
f, err := os.CreateTemp(filepath.Dir(depfileCachePath), depfileName)
if err != nil {
return "", err
}
buf, err = json.MarshalIndent(dependencySlice, "", "\t")
if err != nil {
panic(err) // shouldn't happen
@@ -209,7 +221,7 @@ func makeCFileCachePath(paths []string, depfileNameHash string) (string, error)
outFileNameBuf := sha512.Sum512_224(buf)
cacheKey := hex.EncodeToString(outFileNameBuf[:])
outpath := filepath.Join(goenv.Get("GOCACHE"), "obj-"+cacheKey+".o")
outpath := filepath.Join(goenv.Get("GOCACHE"), "obj-"+cacheKey+".bc")
return outpath, nil
}
@@ -232,13 +244,14 @@ func hashFile(path string) (string, error) {
// file is assumed to have a single target named deps.
//
// There are roughly three make syntax variants:
// - BSD make, which doesn't support any escaping. This means that many special
// characters are not supported in file names.
// - GNU make, which supports escaping using a backslash but when it fails to
// find a file it tries to fall back with the literal path name (to match BSD
// make).
// - NMake (Visual Studio) and Jom, which simply quote the string if there are
// any weird characters.
// - BSD make, which doesn't support any escaping. This means that many special
// characters are not supported in file names.
// - GNU make, which supports escaping using a backslash but when it fails to
// find a file it tries to fall back with the literal path name (to match BSD
// make).
// - NMake (Visual Studio) and Jom, which simply quote the string if there are
// any weird characters.
//
// Clang supports two variants: a format that's a compromise between BSD and GNU
// make (and is buggy to match GCC which is equally buggy), and NMake/Jom, which
// is at least somewhat sane. This last format isn't perfect either: it does not
@@ -246,7 +259,7 @@ func hashFile(path string) (string, error) {
// allowed on Windows, but of course can be used on POSIX like systems. Still,
// it's the most sane of any of the formats so readDepFile will use that format.
func readDepFile(filename string) ([]string, error) {
buf, err := ioutil.ReadFile(filename)
buf, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
+106 -58
View File
@@ -1,4 +1,11 @@
// +build byollvm
//go:build byollvm
// Source: https://github.com/llvm/llvm-project/blob/main/clang/tools/driver/cc1as_main.cpp
// This file needs to be updated each LLVM release.
// There are a few small modifications to make, like:
// * ExecuteAssembler is made non-static.
// * The struct AssemblerImplementation is moved to cc1as.h so it can be
// included elsewhere.
//===-- cc1as.cpp - Clang Assembler --------------------------------------===//
//
@@ -21,8 +28,8 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
@@ -38,6 +45,7 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
@@ -45,17 +53,18 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TargetParser/Triple.h"
#include <memory>
#include <optional>
#include <system_error>
using namespace clang;
using namespace clang::driver;
@@ -73,10 +82,10 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Parse the arguments.
const OptTable &OptTbl = getDriverOptTable();
const unsigned IncludedFlagsBitmask = options::CC1AsOption;
llvm::opt::Visibility VisibilityMask(options::CC1AsOption);
unsigned MissingArgIndex, MissingArgCount;
InputArgList Args = OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount,
IncludedFlagsBitmask);
InputArgList Args =
OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount, VisibilityMask);
// Check for missing argument error.
if (MissingArgCount) {
@@ -89,7 +98,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
auto ArgString = A->getAsString(Args);
std::string Nearest;
if (OptTbl.findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
if (OptTbl.findNearest(ArgString, Nearest, VisibilityMask) > 1)
Diags.Report(diag::err_drv_unknown_argument) << ArgString;
else
Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
@@ -101,6 +110,17 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Target Options
Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
if (Arg *A = Args.getLastArg(options::OPT_darwin_target_variant_triple))
Opts.DarwinTargetVariantTriple = llvm::Triple(A->getValue());
if (Arg *A = Args.getLastArg(OPT_darwin_target_variant_sdk_version_EQ)) {
VersionTuple Version;
if (Version.tryParse(A->getValue()))
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
else
Opts.DarwinTargetVariantSDKVersion = Version;
}
Opts.CPU = std::string(Args.getLastArgValue(OPT_target_cpu));
Opts.Features = Args.getAllArgValues(OPT_target_feature);
@@ -115,35 +135,31 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Any DebugInfoKind implies GenDwarfForAssembly.
Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
OPT_compress_debug_sections_EQ)) {
if (A->getOption().getID() == OPT_compress_debug_sections) {
// TODO: be more clever about the compression type auto-detection
Opts.CompressDebugSections = llvm::DebugCompressionType::GNU;
} else {
Opts.CompressDebugSections =
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
.Case("none", llvm::DebugCompressionType::None)
.Case("zlib", llvm::DebugCompressionType::Z)
.Case("zlib-gnu", llvm::DebugCompressionType::GNU)
.Default(llvm::DebugCompressionType::None);
}
if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections_EQ)) {
Opts.CompressDebugSections =
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
.Case("none", llvm::DebugCompressionType::None)
.Case("zlib", llvm::DebugCompressionType::Zlib)
.Case("zstd", llvm::DebugCompressionType::Zstd)
.Default(llvm::DebugCompressionType::None);
}
Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
Opts.RelaxELFRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
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);
Opts.DwarfDebugFlags =
std::string(Args.getLastArgValue(OPT_dwarf_debug_flags));
Opts.DwarfDebugProducer =
std::string(Args.getLastArgValue(OPT_dwarf_debug_producer));
Opts.DebugCompilationDir =
std::string(Args.getLastArgValue(OPT_fdebug_compilation_dir));
if (const Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ,
options::OPT_fdebug_compilation_dir_EQ))
Opts.DebugCompilationDir = A->getValue();
Opts.MainFileName = std::string(Args.getLastArgValue(OPT_main_file_name));
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
auto Split = StringRef(Arg).split('=');
Opts.DebugPrefixMap.insert(
{std::string(Split.first), std::string(Split.second)});
Opts.DebugPrefixMap.emplace_back(Split.first, Split.second);
}
// Frontend Options
@@ -190,6 +206,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn);
Opts.NoTypeCheck = Args.hasArg(OPT_mno_type_check);
Opts.RelocationModel =
std::string(Args.getLastArgValue(OPT_mrelocation_model, "pic"));
Opts.TargetABI = std::string(Args.getLastArgValue(OPT_target_abi));
@@ -207,6 +224,19 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
.Default(0);
}
if (auto *A = Args.getLastArg(OPT_femit_dwarf_unwind_EQ)) {
Opts.EmitDwarfUnwind =
llvm::StringSwitch<EmitDwarfUnwindType>(A->getValue())
.Case("always", EmitDwarfUnwindType::Always)
.Case("no-compact-unwind", EmitDwarfUnwindType::NoCompactUnwind)
.Case("default", EmitDwarfUnwindType::Default);
}
Opts.EmitCompactUnwindNonCanonical =
Args.hasArg(OPT_femit_compact_unwind_non_canonical);
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
return Success;
}
@@ -219,7 +249,7 @@ getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
std::error_code EC;
auto Out = std::make_unique<raw_fd_ostream>(
Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_Text));
Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_TextWithCRLF));
if (EC) {
Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
return nullptr;
@@ -228,7 +258,8 @@ getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
return Out;
}
bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
DiagnosticsEngine &Diags) {
// Get the target specific parser.
std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error);
@@ -236,11 +267,11 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
MemoryBuffer::getFileOrSTDIN(Opts.InputFile);
MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
if (std::error_code EC = Buffer.getError()) {
Error = EC.message();
return Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
return Diags.Report(diag::err_fe_error_reading)
<< Opts.InputFile << EC.message();
}
SourceMgr SrcMgr;
@@ -256,6 +287,10 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
assert(MRI && "Unable to create target register info!");
MCTargetOptions MCOptions;
MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical;
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
std::unique_ptr<MCAsmInfo> MAI(
TheTarget->createMCAsmInfo(*MRI, Opts.Triple, MCOptions));
assert(MAI && "Unable to create target asm info!");
@@ -277,11 +312,15 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
if (!Opts.SplitDwarfOutput.empty())
DwoOS = getOutputStream(Opts.SplitDwarfOutput, Diags, IsBinary);
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
// Build up the feature string from the target feature list.
std::string FS = llvm::join(Opts.Features, ",");
MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr, &MCOptions);
std::unique_ptr<MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
assert(STI && "Unable to create subtarget info!");
MCContext Ctx(Triple(Opts.Triple), MAI.get(), MRI.get(), STI.get(), &SrcMgr,
&MCOptions);
bool PIC = false;
if (Opts.RelocationModel == "static") {
@@ -294,7 +333,16 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
PIC = false;
}
MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, Ctx);
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
// 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.SaveTemporaryLabels)
Ctx.setAllowTemporaryLabels(false);
if (Opts.GenDwarfForAssembly)
@@ -316,25 +364,23 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
if (!Opts.MainFileName.empty())
Ctx.setMainFileName(StringRef(Opts.MainFileName));
Ctx.setDwarfFormat(Opts.Dwarf64 ? dwarf::DWARF64 : dwarf::DWARF32);
Ctx.setDwarfVersion(Opts.DwarfVersion);
if (Opts.GenDwarfForAssembly)
Ctx.setGenDwarfRootFile(Opts.InputFile,
SrcMgr.getMemoryBuffer(BufferIndex)->getBuffer());
// Build up the feature string from the target feature list.
std::string FS = llvm::join(Opts.Features, ",");
std::unique_ptr<MCStreamer> Str;
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
std::unique_ptr<MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
assert(MCII && "Unable to create instruction info!");
raw_pwrite_stream *Out = FDOS.get();
std::unique_ptr<buffer_ostream> BOS;
MCOptions.MCNoWarn = Opts.NoWarn;
MCOptions.MCFatalWarnings = Opts.FatalWarnings;
MCOptions.MCNoTypeCheck = Opts.NoTypeCheck;
MCOptions.ABIName = Opts.TargetABI;
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
@@ -344,7 +390,7 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
std::unique_ptr<MCCodeEmitter> CE;
if (Opts.ShowEncoding)
CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
CE.reset(TheTarget->createMCCodeEmitter(*MCII, Ctx));
std::unique_ptr<MCAsmBackend> MAB(
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
@@ -364,9 +410,11 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
}
std::unique_ptr<MCCodeEmitter> CE(
TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
TheTarget->createMCCodeEmitter(*MCII, Ctx));
std::unique_ptr<MCAsmBackend> MAB(
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
assert(MAB && "Unable to create asm backend!");
std::unique_ptr<MCObjectWriter> OW =
DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS)
: MAB->createObjectWriter(*Out);
@@ -376,16 +424,15 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
/*DWARFMustBeAtTheEnd*/ true));
Str.get()->InitSections(Opts.NoExecStack);
Str.get()->initSections(Opts.NoExecStack, *STI);
}
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
// is emitted in __LLVM,__asm section if the object file is MachO format.
if (Opts.EmbedBitcode && Ctx.getObjectFileInfo()->getObjectFileType() ==
MCObjectFileInfo::IsMachO) {
if (Opts.EmbedBitcode && Ctx.getObjectFileType() == MCContext::IsMachO) {
MCSection *AsmLabel = Ctx.getMachOSection(
"__LLVM", "__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly());
Str.get()->SwitchSection(AsmLabel);
Str.get()->switchSection(AsmLabel);
Str.get()->emitZeros(1);
}
@@ -419,12 +466,12 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
Failed = Parser->Run(Opts.NoInitialTextSection);
}
// Close Streamer first.
// It might have a reference to the output stream.
Str.reset();
// Close the output stream early.
BOS.reset();
FDOS.reset();
return Failed;
}
bool ExecuteAssembler(AssemblerInvocation &Opts,
DiagnosticsEngine &Diags) {
bool Failed = ExecuteAssemblerImpl(Opts, Diags);
// Delete output file if there were errors.
if (Failed) {
@@ -437,7 +484,7 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
return Failed;
}
static void LLVMErrorHandler(void *UserData, const std::string &Message,
static void LLVMErrorHandler(void *UserData, const char *Message,
bool GenCrashDiag) {
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
@@ -472,11 +519,12 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
return 1;
if (Asm.ShowHelp) {
getDriverOptTable().PrintHelp(
getDriverOptTable().printHelp(
llvm::outs(), "clang -cc1as [options] file...",
"Clang Integrated Assembler",
/*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,
/*ShowAllAliases=*/false);
"Clang Integrated Assembler", /*ShowHidden=*/false,
/*ShowAllAliases=*/false,
llvm::opt::Visibility(driver::options::CC1AsOption));
return 0;
}
+27 -1
View File
@@ -1,3 +1,6 @@
// Source: https://github.com/llvm/llvm-project/blob/main/clang/tools/driver/cc1as_main.cpp
// See cc1as.cpp for details.
//===-- cc1as.h - Clang Assembler ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
@@ -39,11 +42,12 @@ struct AssemblerInvocation {
unsigned SaveTemporaryLabels : 1;
unsigned GenDwarfForAssembly : 1;
unsigned RelaxELFRelocations : 1;
unsigned Dwarf64 : 1;
unsigned DwarfVersion;
std::string DwarfDebugFlags;
std::string DwarfDebugProducer;
std::string DebugCompilationDir;
std::map<const std::string, const std::string> DebugPrefixMap;
llvm::SmallVector<std::pair<std::string, std::string>, 0> DebugPrefixMap;
llvm::DebugCompressionType CompressDebugSections =
llvm::DebugCompressionType::None;
std::string MainFileName;
@@ -81,9 +85,17 @@ struct AssemblerInvocation {
unsigned NoExecStack : 1;
unsigned FatalWarnings : 1;
unsigned NoWarn : 1;
unsigned NoTypeCheck : 1;
unsigned IncrementalLinkerCompatible : 1;
unsigned EmbedBitcode : 1;
/// Whether to emit DWARF unwind info.
EmitDwarfUnwindType EmitDwarfUnwind;
// Whether to emit compact-unwind for non-canonical entries.
// Note: maybe overriden by other constraints.
unsigned EmitCompactUnwindNonCanonical : 1;
/// The name of the relocation model to use.
std::string RelocationModel;
@@ -91,6 +103,16 @@ struct AssemblerInvocation {
/// otherwise.
std::string TargetABI;
/// Darwin target variant triple, the variant of the deployment target
/// for which the code is being compiled.
std::optional<llvm::Triple> DarwinTargetVariantTriple;
/// The version of the darwin target variant SDK which was used during the
/// compilation
llvm::VersionTuple DarwinTargetVariantSDKVersion;
/// The name of a file to use with \c .secure_log_unique directives.
std::string AsSecureLogFile;
/// @}
public:
@@ -107,9 +129,13 @@ public:
NoExecStack = 0;
FatalWarnings = 0;
NoWarn = 0;
NoTypeCheck = 0;
IncrementalLinkerCompatible = 0;
Dwarf64 = 0;
DwarfVersion = 0;
EmbedBitcode = 0;
EmitDwarfUnwind = EmitDwarfUnwindType::Default;
EmitCompactUnwindNonCanonical = false;
}
static bool CreateFromArgs(AssemblerInvocation &Res,
+2 -2
View File
@@ -1,4 +1,4 @@
// +build byollvm
//go:build byollvm
#include <clang/Basic/DiagnosticOptions.h>
#include <clang/CodeGen/CodeGenAction.h>
@@ -11,7 +11,7 @@
#include <clang/FrontendTool/Utils.h>
#include <llvm/ADT/IntrusiveRefCntPtr.h>
#include <llvm/Option/Option.h>
#include <llvm/Support/Host.h>
#include <llvm/TargetParser/Host.h>
using namespace llvm;
using namespace clang;
+36 -12
View File
@@ -2,6 +2,7 @@ package builder
import (
"errors"
"fmt"
"os"
"os/exec"
"runtime"
@@ -21,13 +22,24 @@ func init() {
commands["clang"] = []string{"clang-" + llvmMajor}
commands["ld.lld"] = []string{"ld.lld-" + llvmMajor, "ld.lld"}
commands["wasm-ld"] = []string{"wasm-ld-" + llvmMajor, "wasm-ld"}
commands["lldb"] = []string{"lldb-" + llvmMajor, "lldb"}
// Add the path to a Homebrew-installed LLVM for ease of use (no need to
// manually set $PATH).
if runtime.GOOS == "darwin" {
prefix := "/usr/local/opt/llvm@" + llvmMajor + "/bin/"
var prefix string
switch runtime.GOARCH {
case "amd64":
prefix = "/usr/local/opt/llvm@" + llvmMajor + "/bin/"
case "arm64":
prefix = "/opt/homebrew/opt/llvm@" + llvmMajor + "/bin/"
default:
// unknown GOARCH
panic(fmt.Sprintf("unknown GOARCH: %s on darwin", runtime.GOARCH))
}
commands["clang"] = append(commands["clang"], prefix+"clang-"+llvmMajor)
commands["ld.lld"] = append(commands["ld.lld"], prefix+"ld.lld")
commands["wasm-ld"] = append(commands["wasm-ld"], prefix+"wasm-ld")
commands["lldb"] = append(commands["lldb"], prefix+"lldb")
}
// Add the path for when LLVM was installed with the installer from
// llvm.org, which by default doesn't add LLVM to the $PATH environment
@@ -36,6 +48,7 @@ func init() {
commands["clang"] = append(commands["clang"], "clang", "C:\\Program Files\\LLVM\\bin\\clang.exe")
commands["ld.lld"] = append(commands["ld.lld"], "lld", "C:\\Program Files\\LLVM\\bin\\lld.exe")
commands["wasm-ld"] = append(commands["wasm-ld"], "C:\\Program Files\\LLVM\\bin\\wasm-ld.exe")
commands["lldb"] = append(commands["lldb"], "C:\\Program Files\\LLVM\\bin\\lldb.exe")
}
// Add the path to LLVM installed from ports.
if runtime.GOOS == "freebsd" {
@@ -43,23 +56,34 @@ func init() {
commands["clang"] = append(commands["clang"], prefix+"clang-"+llvmMajor)
commands["ld.lld"] = append(commands["ld.lld"], prefix+"ld.lld")
commands["wasm-ld"] = append(commands["wasm-ld"], prefix+"wasm-ld")
commands["lldb"] = append(commands["lldb"], prefix+"lldb")
}
}
func execCommand(cmdNames []string, args ...string) error {
for _, cmdName := range cmdNames {
cmd := exec.Command(cmdName, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
// LookupCommand looks up the executable name for a given LLVM tool such as
// clang or wasm-ld. It returns the (relative) command that can be used to
// invoke the tool or an error if it could not be found.
func LookupCommand(name string) (string, error) {
for _, cmdName := range commands[name] {
_, err := exec.LookPath(cmdName)
if err != nil {
if err, ok := err.(*exec.Error); ok && (err.Err == exec.ErrNotFound || err.Err.Error() == "file does not exist") {
// this command was not found, try the next
if errors.Unwrap(err) == exec.ErrNotFound {
continue
}
return err
return cmdName, err
}
return nil
return cmdName, nil
}
return errors.New("none of these commands were found in your $PATH: " + strings.Join(cmdNames, " "))
return "", errors.New("none of these commands were found in your $PATH: " + strings.Join(commands[name], " "))
}
func execCommand(name string, args ...string) error {
name, err := LookupCommand(name)
if err != nil {
return err
}
cmd := exec.Command(name, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
+14 -11
View File
@@ -1,7 +1,6 @@
package builder
import (
"errors"
"fmt"
"github.com/tinygo-org/tinygo/compileopts"
@@ -13,27 +12,31 @@ import (
// uses the currently active GOPATH (from the goenv package) to determine the Go
// version to use.
func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
spec, err := compileopts.LoadTarget(options.Target)
spec, err := compileopts.LoadTarget(options)
if err != nil {
return nil, err
}
goroot := goenv.Get("GOROOT")
if goroot == "" {
return nil, errors.New("cannot locate $GOROOT, please set it manually")
if options.OpenOCDCommands != nil {
// Override the OpenOCDCommands from the target spec if specified on
// the command-line
spec.OpenOCDCommands = options.OpenOCDCommands
}
major, minor, err := goenv.GetGorootVersion(goroot)
major, minor, err := goenv.GetGorootVersion()
if err != nil {
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
return nil, err
}
if major != 1 || minor < 13 || minor > 16 {
return nil, fmt.Errorf("requires go version 1.13 through 1.16, got go%d.%d", major, minor)
if major != 1 || minor < 19 || minor > 22 {
// Note: when this gets updated, also update the Go compatibility matrix:
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
return nil, fmt.Errorf("requires go version 1.19 through 1.22, got go%d.%d", major, minor)
}
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
return &compileopts.Config{
Options: options,
Target: spec,
GoMinorVersion: minor,
ClangHeaders: clangHeaderPath,
TestConfig: options.TestConfig,
}, nil
}
+58
View File
@@ -0,0 +1,58 @@
package builder
import (
"path/filepath"
"strings"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
)
// Create a job that builds a Darwin libSystem.dylib stub library. This library
// contains all the symbols needed so that we can link against it, but it
// doesn't contain any real symbol implementations.
func makeDarwinLibSystemJob(config *compileopts.Config, tmpdir string) *compileJob {
return &compileJob{
description: "compile Darwin libSystem.dylib",
run: func(job *compileJob) (err error) {
arch := strings.Split(config.Triple(), "-")[0]
job.result = filepath.Join(tmpdir, "libSystem.dylib")
objpath := filepath.Join(tmpdir, "libSystem.o")
inpath := filepath.Join(goenv.Get("TINYGOROOT"), "lib/macos-minimal-sdk/src", arch, "libSystem.s")
// Compile assembly file to object file.
flags := []string{
"-nostdlib",
"--target=" + config.Triple(),
"-c",
"-o", objpath,
inpath,
}
if config.Options.PrintCommands != nil {
config.Options.PrintCommands("clang", flags...)
}
err = runCCompiler(flags...)
if err != nil {
return err
}
// Link object file to dynamic library.
platformVersion := strings.TrimPrefix(strings.Split(config.Triple(), "-")[2], "macosx")
flags = []string{
"-flavor", "darwin",
"-demangle",
"-dynamic",
"-dylib",
"-arch", arch,
"-platform_version", "macos", platformVersion, platformVersion,
"-install_name", "/usr/lib/libSystem.B.dylib",
"-o", job.result,
objpath,
}
if config.Options.PrintCommands != nil {
config.Options.PrintCommands("ld.lld", flags...)
}
return link("ld.lld", flags...)
},
}
}
+57
View File
@@ -0,0 +1,57 @@
package builder
import (
"debug/elf"
"fmt"
"os"
)
func getElfSectionData(executable string, sectionName string) ([]byte, elf.FileHeader, error) {
elfFile, err := elf.Open(executable)
if err != nil {
return nil, elf.FileHeader{}, err
}
defer elfFile.Close()
section := elfFile.Section(sectionName)
if section == nil {
return nil, elf.FileHeader{}, fmt.Errorf("could not find %s section", sectionName)
}
data, err := section.Data()
return data, elfFile.FileHeader, err
}
func replaceElfSection(executable string, sectionName string, data []byte) error {
fp, err := os.OpenFile(executable, os.O_RDWR, 0)
if err != nil {
return err
}
defer fp.Close()
elfFile, err := elf.Open(executable)
if err != nil {
return err
}
defer elfFile.Close()
section := elfFile.Section(sectionName)
if section == nil {
return fmt.Errorf("could not find %s section", sectionName)
}
// Implicitly check for compressed sections
if section.Size != section.FileSize {
return fmt.Errorf("expected section %s to have identical size and file size, got %d and %d", sectionName, section.Size, section.FileSize)
}
// Only permit complete replacement of section
if section.Size != uint64(len(data)) {
return fmt.Errorf("expected section %s to have size %d, was actually %d", sectionName, len(data), section.Size)
}
// Write the replacement section data
_, err = fp.WriteAt(data, int64(section.Offset))
return err
}
-89
View File
@@ -1,89 +0,0 @@
package builder
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"tinygo.org/x/go-llvm"
)
// getClangHeaderPath returns the path to the built-in Clang headers. It tries
// multiple locations, which should make it find the directory when installed in
// various ways.
func getClangHeaderPath(TINYGOROOT string) string {
// Check whether we're running from the source directory.
path := filepath.Join(TINYGOROOT, "llvm-project", "clang", "lib", "Headers")
if _, err := os.Stat(path); !os.IsNotExist(err) {
return path
}
// Check whether we're running from the installation directory.
path = filepath.Join(TINYGOROOT, "lib", "clang", "include")
if _, err := os.Stat(path); !os.IsNotExist(err) {
return path
}
// It looks like we are built with a system-installed LLVM. Do a last
// attempt: try to use Clang headers relative to the clang binary.
llvmMajor := strings.Split(llvm.Version, ".")[0]
for _, cmdName := range commands["clang"] {
binpath, err := exec.LookPath(cmdName)
if err == nil {
// This should be the command that will also be used by
// execCommand. To avoid inconsistencies, make sure we use the
// headers relative to this command.
binpath, err = filepath.EvalSymlinks(binpath)
if err != nil {
// Unexpected.
return ""
}
// Example executable:
// /usr/lib/llvm-9/bin/clang
// Example include path:
// /usr/lib/llvm-9/lib64/clang/9.0.1/include/
llvmRoot := filepath.Dir(filepath.Dir(binpath))
clangVersionRoot := filepath.Join(llvmRoot, "lib64", "clang")
dirs64, err64 := ioutil.ReadDir(clangVersionRoot)
// Example include path:
// /usr/lib/llvm-9/lib/clang/9.0.1/include/
clangVersionRoot = filepath.Join(llvmRoot, "lib", "clang")
dirs32, err32 := ioutil.ReadDir(clangVersionRoot)
if err64 != nil && err32 != nil {
// Unexpected.
continue
}
dirnames := make([]string, len(dirs64)+len(dirs32))
dirCount := 0
for _, d := range dirs32 {
name := d.Name()
if name == llvmMajor || strings.HasPrefix(name, llvmMajor+".") {
dirnames[dirCount] = filepath.Join(llvmRoot, "lib", "clang", name)
dirCount++
}
}
for _, d := range dirs64 {
name := d.Name()
if name == llvmMajor || strings.HasPrefix(name, llvmMajor+".") {
dirnames[dirCount] = filepath.Join(llvmRoot, "lib64", "clang", name)
dirCount++
}
}
sort.Strings(dirnames)
// Check for the highest version first.
for i := dirCount - 1; i >= 0; i-- {
path := filepath.Join(dirnames[i], "include")
_, err := os.Stat(filepath.Join(path, "stdint.h"))
if err == nil {
return path
}
}
}
}
// Could not find it.
return ""
}
+50 -10
View File
@@ -13,8 +13,9 @@ import (
"debug/elf"
"encoding/binary"
"fmt"
"io/ioutil"
"os"
"sort"
"strings"
)
type espImageSegment struct {
@@ -22,7 +23,7 @@ type espImageSegment struct {
data []byte
}
// makeESPFirmare converts an input ELF file to an image file for an ESP32 or
// makeESPFirmareImage 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.
//
@@ -78,11 +79,37 @@ func makeESPFirmareImage(infile, outfile, format string) error {
// An added benefit is that we don't need to check for errors all the time.
outf := &bytes.Buffer{}
// Separate esp32 and esp32-img. The -img suffix indicates we should make an
// image, not just a binary to be flashed at 0x1000 for example.
chip := format
makeImage := false
if strings.HasSuffix(format, "-img") {
makeImage = true
chip = format[:len(format)-len("-img")]
}
if makeImage {
// The bootloader starts at 0x1000, or 4096.
// TinyGo doesn't use a separate bootloader and runs the entire
// application in the bootloader location.
outf.Write(make([]byte, 4096))
}
// Chip IDs. Source:
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L22
chip_id := map[string]uint16{
"esp32": 0x0000,
"esp32c3": 0x0005,
}[chip]
// Image header.
switch format {
case "esp32":
switch chip {
case "esp32", "esp32c3":
// Header format:
// https://github.com/espressif/esp-idf/blob/8fbb63c2/components/bootloader_support/include/esp_image_format.h#L58
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
// Note: not adding a SHA256 hash as the binary is modified by
// esptool.py while flashing and therefore the hash won't be valid
// anymore.
binary.Write(outf, binary.LittleEndian, struct {
magic uint8
segment_count uint8
@@ -91,15 +118,18 @@ func makeESPFirmareImage(infile, outfile, format string) error {
entry_addr uint32
wp_pin uint8
spi_pin_drv [3]uint8
reserved [11]uint8
chip_id uint16
min_chip_rev uint8
reserved [8]uint8
hash_appended bool
}{
magic: 0xE9,
segment_count: byte(len(segments)),
spi_mode: 0, // irrelevant, replaced by esptool when flashing
spi_speed_size: 0, // spi_speed, spi_size: replaced by esptool when flashing
spi_mode: 2, // ESP_IMAGE_SPI_MODE_DIO
spi_speed_size: 0x1f, // ESP_IMAGE_SPI_SPEED_80M, ESP_IMAGE_FLASH_SIZE_2MB
entry_addr: uint32(inf.Entry),
wp_pin: 0xEE, // disable WP pin
chip_id: chip_id,
hash_appended: true, // add a SHA256 hash
})
case "esp8266":
@@ -142,12 +172,22 @@ func makeESPFirmareImage(infile, outfile, format string) error {
outf.Write(make([]byte, 15-outf.Len()%16))
outf.WriteByte(checksum)
if format == "esp32" {
if chip != "esp8266" {
// SHA256 hash (to protect against image corruption, not for security).
hash := sha256.Sum256(outf.Bytes())
outf.Write(hash[:])
}
// QEMU (or more precisely, qemu-system-xtensa from Espressif) expects the
// image to be a certain size.
if makeImage {
// Use a default image size of 4MB.
grow := 4096*1024 - outf.Len()
if grow > 0 {
outf.Write(make([]byte, grow))
}
}
// Write the image to the output file.
return ioutil.WriteFile(outfile, outf.Bytes(), 0666)
return os.WriteFile(outfile, outf.Bytes(), 0666)
}
+137 -81
View File
@@ -4,8 +4,12 @@ package builder
// parallel while taking care of dependencies.
import (
"container/heap"
"errors"
"fmt"
"runtime"
"sort"
"strings"
"time"
)
@@ -29,7 +33,6 @@ type compileJob struct {
dependencies []*compileJob
result string // result (path)
run func(*compileJob) (err error)
state jobState
err error // error if finished
duration time.Duration // how long it took to run this job (only set after finishing)
}
@@ -44,91 +47,123 @@ func dummyCompileJob(result string) *compileJob {
}
}
// readyToRun returns whether this job is ready to run: it is itself not yet
// started and all dependencies are finished.
func (job *compileJob) readyToRun() bool {
if job.state != jobStateQueued {
// Already running or finished, so shouldn't be run again.
return false
// runJobs runs the indicated job and all its dependencies. For every job, all
// the dependencies are run first. It returns the error of the first job that
// fails.
// It runs all jobs in the order of the dependencies slice, depth-first.
// Therefore, if some jobs are preferred to run before others, they should be
// ordered as such in the job dependencies.
func runJobs(job *compileJob, sema chan struct{}) error {
if sema == nil {
// Have a default, if the semaphore isn't set. This is useful for
// tests.
sema = make(chan struct{}, runtime.NumCPU())
}
if cap(sema) == 0 {
return errors.New("cannot 0 jobs at a time")
}
// Check dependencies.
for _, dep := range job.dependencies {
if dep.state != jobStateFinished {
// A dependency is not finished, so this job has to wait until it
// is.
return false
// Create a slice of jobs to run, where all dependencies are run in order.
jobs := []*compileJob{}
addedJobs := map[*compileJob]struct{}{}
var addJobs func(*compileJob)
addJobs = func(job *compileJob) {
if _, ok := addedJobs[job]; ok {
return
}
for _, dep := range job.dependencies {
addJobs(dep)
}
jobs = append(jobs, job)
addedJobs[job] = struct{}{}
}
addJobs(job)
waiting := make(map[*compileJob]map[*compileJob]struct{}, len(jobs))
dependents := make(map[*compileJob][]*compileJob, len(jobs))
jidx := make(map[*compileJob]int)
var ready intHeap
for i, job := range jobs {
jidx[job] = i
if len(job.dependencies) == 0 {
// This job is ready to run.
ready.Push(i)
continue
}
// Construct a map for dependencies which the job is currently waiting on.
waitDeps := make(map[*compileJob]struct{})
waiting[job] = waitDeps
// Add the job to the dependents list of each dependency.
for _, dep := range job.dependencies {
dependents[dep] = append(dependents[dep], job)
waitDeps[dep] = struct{}{}
}
}
// All conditions are satisfied.
return true
}
// runJobs runs all the jobs indicated in the jobs slice and returns the error
// of the first job that fails to run.
// It runs all jobs in the order of the slice, as long as all dependencies have
// already run. Therefore, if some jobs are preferred to run before others, they
// should be ordered as such in this slice.
func runJobs(jobs []*compileJob) error {
// Create channels to communicate with the workers.
// Create a channel to accept notifications of completion.
doneChan := make(chan *compileJob)
workerChan := make(chan *compileJob)
defer close(workerChan)
// Start a number of workers.
for i := 0; i < runtime.NumCPU(); i++ {
if jobRunnerDebug {
fmt.Println("## starting worker", i)
}
go jobWorker(workerChan, doneChan)
}
// Send each job in the jobs slice to a worker, taking care of job
// dependencies.
numRunningJobs := 0
var totalTime time.Duration
start := time.Now()
for {
// If there are free workers, try starting a new job (if one is
// available). If it succeeds, try again to fill the entire worker pool.
if numRunningJobs < runtime.NumCPU() {
jobToRun := nextJob(jobs)
if jobToRun != nil {
// Start job.
for len(ready.IntSlice) > 0 || numRunningJobs != 0 {
var completed *compileJob
if len(ready.IntSlice) > 0 {
select {
case sema <- struct{}{}:
// Start a job.
job := jobs[heap.Pop(&ready).(int)]
if jobRunnerDebug {
fmt.Println("## start: ", jobToRun.description)
fmt.Println("## start: ", job.description)
}
jobToRun.state = jobStateRunning
workerChan <- jobToRun
go runJob(job, doneChan)
numRunningJobs++
continue
case completed = <-doneChan:
// A job completed.
}
} else {
// Wait for a job to complete.
completed = <-doneChan
}
// When there are no jobs running, all jobs in the jobs slice must have
// been finished. Therefore, the work is done.
if numRunningJobs == 0 {
break
}
// Wait until a job is finished.
job := <-doneChan
job.state = jobStateFinished
numRunningJobs--
totalTime += job.duration
<-sema
if jobRunnerDebug {
fmt.Println("## finished:", job.description, "(time "+job.duration.String()+")")
fmt.Println("## finished:", completed.description, "(time "+completed.duration.String()+")")
}
if job.err != nil {
// Wait for running jobs to finish.
if completed.err != nil {
// Wait for any current jobs to finish.
for numRunningJobs != 0 {
<-doneChan
numRunningJobs--
}
// Return error of first failing job.
return job.err
// The build failed.
return completed.err
}
// Update total run time.
totalTime += completed.duration
// Update dependent jobs.
for _, j := range dependents[completed] {
wait := waiting[j]
delete(wait, completed)
if len(wait) == 0 {
// This job is now ready to run.
ready.Push(jidx[j])
delete(waiting, j)
}
}
}
if len(waiting) != 0 {
// There is a dependency cycle preventing some jobs from running.
return errDependencyCycle{waiting}
}
// Some statistics, if debugging.
@@ -145,29 +180,50 @@ func runJobs(jobs []*compileJob) error {
return nil
}
// nextJob returns the first ready-to-run job.
// This is an implementation detail of runJobs.
func nextJob(jobs []*compileJob) *compileJob {
for _, job := range jobs {
if job.readyToRun() {
return job
}
}
return nil
type errDependencyCycle struct {
waiting map[*compileJob]map[*compileJob]struct{}
}
// jobWorker is the goroutine that runs received jobs.
// This is an implementation detail of runJobs.
func jobWorker(workerChan, doneChan chan *compileJob) {
for job := range workerChan {
start := time.Now()
if job.run != nil {
err := job.run(job)
if err != nil {
job.err = err
}
func (err errDependencyCycle) Error() string {
waits := make([]string, 0, len(err.waiting))
for j, wait := range err.waiting {
deps := make([]string, 0, len(wait))
for dep := range wait {
deps = append(deps, dep.description)
}
job.duration = time.Since(start)
doneChan <- job
sort.Strings(deps)
waits = append(waits, fmt.Sprintf("\t%s is waiting for [%s]",
j.description, strings.Join(deps, ", "),
))
}
sort.Strings(waits)
return "deadlock:\n" + strings.Join(waits, "\n")
}
type intHeap struct {
sort.IntSlice
}
func (h *intHeap) Push(x interface{}) {
h.IntSlice = append(h.IntSlice, x.(int))
}
func (h *intHeap) Pop() interface{} {
x := h.IntSlice[len(h.IntSlice)-1]
h.IntSlice = h.IntSlice[:len(h.IntSlice)-1]
return x
}
// runJob runs a compile job and notifies doneChan of completion.
func runJob(job *compileJob, doneChan chan *compileJob) {
start := time.Now()
if job.run != nil {
err := job.run(job)
if err != nil {
job.err = err
}
}
job.duration = time.Since(start)
doneChan <- job
}
+197 -58
View File
@@ -1,10 +1,15 @@
package builder
import (
"errors"
"io/fs"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
)
@@ -14,121 +19,220 @@ type Library struct {
// The library name, such as compiler-rt or picolibc.
name string
cflags func() []string
// makeHeaders creates a header include dir for the library
makeHeaders func(target, includeDir string) error
// The source directory, relative to TINYGOROOT.
sourceDir string
// cflags returns the C flags specific to this library
cflags func(target, headerPath string) []string
// The source directory.
sourceDir func() string
// The source files, relative to sourceDir.
sources func(target string) []string
}
librarySources func(target string) ([]string, error)
// fullPath returns the full path to the source directory.
func (l *Library) fullPath() string {
return filepath.Join(goenv.Get("TINYGOROOT"), l.sourceDir)
}
// sourcePaths returns a slice with the full paths to the source files.
func (l *Library) sourcePaths(target string) []string {
sources := l.sources(target)
paths := make([]string, len(sources))
for i, name := range sources {
paths[i] = filepath.Join(l.fullPath(), name)
}
return paths
// The source code for the crt1.o file, relative to sourceDir.
crt1Source string
}
// Load the library archive, possibly generating and caching it if needed.
// The resulting file is stored in the provided tmpdir, which is expected to be
// removed after the Load call.
func (l *Library) Load(target, tmpdir string) (path string, err error) {
job, err := l.load(target, "", tmpdir)
// The resulting directory may be stored in the provided tmpdir, which is
// expected to be removed after the Load call.
func (l *Library) Load(config *compileopts.Config, tmpdir string) (dir string, err error) {
job, unlock, err := l.load(config, tmpdir)
if err != nil {
return "", err
}
jobs := append([]*compileJob{job}, job.dependencies...)
err = runJobs(jobs)
return job.result, err
defer unlock()
err = runJobs(job, config.Options.Semaphore)
return filepath.Dir(job.result), err
}
// load returns a compile job to build this library file for the given target
// and CPU. It may return a dummy compileJob if the library build is already
// cached. The path is stored as job.result but is only valid if the job and
// job.dependencies have been run.
// cached. The path is stored as job.result but is only valid after the job has
// been run.
// The provided tmpdir will be used to store intermediary files and possibly the
// output archive file, it is expected to be removed after use.
func (l *Library) load(target, cpu, tmpdir string) (job *compileJob, err error) {
// Try to load a precompiled library.
precompiledPath := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", target, l.name+".a")
if _, err := os.Stat(precompiledPath); err == nil {
// 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)
archiveFilePath := filepath.Join(outdir, "lib.a")
if precompiled {
// Found a precompiled library for this OS/architecture. Return the path
// directly.
return dummyCompileJob(precompiledPath), nil
return dummyCompileJob(archiveFilePath), func() {}, nil
}
var outfile string
if cpu != "" {
outfile = l.name + "-" + target + "-" + cpu + ".a"
} else {
outfile = l.name + "-" + target + ".a"
}
// 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.
outname := filepath.Base(outdir)
unlock := lock(filepath.Join(goenv.Get("GOCACHE"), outname+".lock"))
var ok bool
defer func() {
if !ok {
unlock()
}
}()
// Try to fetch this library from the cache.
if path, err := cacheLoad(outfile, l.sourcePaths(target)); path != "" || err != nil {
// Cache hit.
return dummyCompileJob(path), nil
if _, err := os.Stat(archiveFilePath); err == nil {
return dummyCompileJob(archiveFilePath), func() {}, nil
}
// Cache miss, build it now.
// Create the destination directory where the components of this library
// (lib.a file, include directory) are placed.
err = os.MkdirAll(filepath.Join(goenv.Get("GOCACHE"), outname), 0o777)
if err != nil {
// Could not create directory (and not because it already exists).
return nil, nil, err
}
// Make headers if needed.
headerPath := filepath.Join(outdir, "include")
target := config.Triple()
if l.makeHeaders != nil {
if _, err = os.Stat(headerPath); err != nil {
temporaryHeaderPath, err := os.MkdirTemp(outdir, "include.tmp*")
if err != nil {
return nil, nil, err
}
defer os.RemoveAll(temporaryHeaderPath)
err = l.makeHeaders(target, temporaryHeaderPath)
if err != nil {
return nil, nil, err
}
err = os.Chmod(temporaryHeaderPath, 0o755) // TempDir uses 0o700 by default
if err != nil {
return nil, nil, err
}
err = os.Rename(temporaryHeaderPath, headerPath)
if err != nil {
switch {
case errors.Is(err, fs.ErrExist):
// Another invocation of TinyGo also seems to have already created the headers.
case runtime.GOOS == "windows" && errors.Is(err, fs.ErrPermission):
// On Windows, a rename with a destination directory that already
// exists does not result in an IsExist error, but rather in an
// access denied error. To be sure, check for this case by checking
// whether the target directory exists.
if _, err := os.Stat(headerPath); err == nil {
break
}
fallthrough
default:
return nil, nil, err
}
}
}
}
remapDir := filepath.Join(os.TempDir(), "tinygo-"+l.name)
dir := filepath.Join(tmpdir, "build-lib-"+l.name)
err = os.Mkdir(dir, 0777)
if err != nil {
return nil, err
return nil, nil, err
}
// Precalculate the flags to the compiler invocation.
// Note: -fdebug-prefix-map is necessary to make the output archive
// reproducible. Otherwise the temporary directory is stored in the archive
// itself, which varies each run.
args := append(l.cflags(), "-c", "-Oz", "-g", "-ffunction-sections", "-fdata-sections", "-Wno-macro-redefined", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir)
args := append(l.cflags(target, headerPath), "-c", "-Oz", "-gdwarf-4", "-ffunction-sections", "-fdata-sections", "-Wno-macro-redefined", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir)
resourceDir := goenv.ClangResourceDir(false)
if resourceDir != "" {
args = append(args, "-resource-dir="+resourceDir)
}
cpu := config.CPU()
if cpu != "" {
args = append(args, "-mcpu="+cpu)
// X86 has deprecated the -mcpu flag, so we need to use -march instead.
// However, ARM has not done this.
if strings.HasPrefix(target, "i386") || strings.HasPrefix(target, "x86_64") {
args = append(args, "-march="+cpu)
} else if strings.HasPrefix(target, "avr") {
args = append(args, "-mmcu="+cpu)
} else {
args = append(args, "-mcpu="+cpu)
}
}
if config.ABI() != "" {
args = append(args, "-mabi="+config.ABI())
}
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft")
if strings.Split(target, "-")[2] == "linux" {
args = append(args, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
} else {
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
}
}
if strings.HasPrefix(target, "avr") {
// AVR defaults to C float and double both being 32-bit. This deviates
// from what most code (and certainly compiler-rt) expects. So we need
// to force the compiler to use 64-bit floating point numbers for
// double.
args = append(args, "-mdouble=64")
}
if strings.HasPrefix(target, "riscv32-") {
args = append(args, "-march=rv32imac", "-mabi=ilp32", "-fforce-enable-int128")
args = append(args, "-march=rv32imac", "-fforce-enable-int128")
}
if strings.HasPrefix(target, "riscv64-") {
args = append(args, "-march=rv64gc", "-mabi=lp64")
args = append(args, "-march=rv64gc")
}
var once sync.Once
// Create job to put all the object files in a single archive. This archive
// file is the (static) library file.
var objs []string
arpath := filepath.Join(dir, l.name+".a")
job = &compileJob{
description: "ar " + l.name + ".a",
result: arpath,
description: "ar " + l.name + "/lib.a",
result: filepath.Join(goenv.Get("GOCACHE"), outname, "lib.a"),
run: func(*compileJob) error {
defer once.Do(unlock)
// Create an archive of all object files.
err := makeArchive(arpath, objs)
f, err := os.CreateTemp(outdir, "libc.a.tmp*")
if err != nil {
return err
}
err = makeArchive(f, objs)
if err != nil {
return err
}
err = f.Close()
if err != nil {
return err
}
err = os.Chmod(f.Name(), 0o644) // TempFile uses 0o600 by default
if err != nil {
return err
}
// Store this archive in the cache.
_, err = cacheStore(arpath, outfile, l.sourcePaths(target))
return err
return os.Rename(f.Name(), archiveFilePath)
},
}
sourceDir := l.sourceDir()
// Create jobs to compile all sources. These jobs are depended upon by the
// archive job above, so must be run first.
for _, srcpath := range l.sourcePaths(target) {
srcpath := srcpath // avoid concurrency issues by redefining inside the loop
objpath := filepath.Join(dir, filepath.Base(srcpath)+".o")
paths, err := l.librarySources(target)
if err != nil {
return nil, nil, err
}
for _, path := range paths {
// Strip leading "../" parts off the path.
cleanpath := path
for strings.HasPrefix(cleanpath, "../") {
cleanpath = cleanpath[3:]
}
srcpath := filepath.Join(sourceDir, path)
objpath := filepath.Join(dir, cleanpath+".o")
os.MkdirAll(filepath.Dir(objpath), 0o777)
objs = append(objs, objpath)
job.dependencies = append(job.dependencies, &compileJob{
description: "compile " + srcpath,
@@ -136,7 +240,10 @@ func (l *Library) load(target, cpu, tmpdir string) (job *compileJob, err error)
var compileArgs []string
compileArgs = append(compileArgs, args...)
compileArgs = append(compileArgs, "-o", objpath, srcpath)
err := runCCompiler("clang", compileArgs...)
if config.Options.PrintCommands != nil {
config.Options.PrintCommands("clang", compileArgs...)
}
err := runCCompiler(compileArgs...)
if err != nil {
return &commandError{"failed to build", srcpath, err}
}
@@ -145,5 +252,37 @@ func (l *Library) load(target, cpu, tmpdir string) (job *compileJob, err error)
})
}
return job, nil
// Create crt1.o job, if needed.
// Add this as a (fake) dependency to the ar file so it gets compiled.
// (It could be done in parallel with creating the ar file, but it probably
// won't make much of a difference in speed).
if l.crt1Source != "" {
srcpath := filepath.Join(sourceDir, l.crt1Source)
job.dependencies = append(job.dependencies, &compileJob{
description: "compile " + srcpath,
run: func(*compileJob) error {
var compileArgs []string
compileArgs = append(compileArgs, args...)
tmpfile, err := os.CreateTemp(outdir, "crt1.o.tmp*")
if err != nil {
return err
}
tmpfile.Close()
compileArgs = append(compileArgs, "-o", tmpfile.Name(), srcpath)
if config.Options.PrintCommands != nil {
config.Options.PrintCommands("clang", compileArgs...)
}
err = runCCompiler(compileArgs...)
if err != nil {
return &commandError{"failed to build", srcpath, err}
}
return os.Rename(tmpfile.Name(), filepath.Join(outdir, "crt1.o"))
},
})
}
ok = true
return job, func() {
once.Do(unlock)
}, nil
}
+21 -8
View File
@@ -1,19 +1,32 @@
// +build byollvm
//go:build byollvm
// This file provides C wrappers for liblld.
#include <lld/Common/Driver.h>
#include <llvm/Support/Parallel.h>
LLD_HAS_DRIVER(coff)
LLD_HAS_DRIVER(elf)
LLD_HAS_DRIVER(mingw)
LLD_HAS_DRIVER(macho)
LLD_HAS_DRIVER(wasm)
static void configure() {
#if _WIN64
// This is a hack to work around a hang in the LLD linker on Windows, with
// -DLLVM_ENABLE_THREADS=ON. It has a similar effect as the -threads=1
// linker flag, but with support for the COFF linker.
llvm::parallel::strategy = llvm::hardware_concurrency(1);
#endif
}
extern "C" {
bool tinygo_link_elf(int argc, char **argv) {
bool tinygo_link(int argc, char **argv) {
configure();
std::vector<const char*> args(argv, argv + argc);
return lld::elf::link(args, false, llvm::outs(), llvm::errs());
}
bool tinygo_link_wasm(int argc, char **argv) {
std::vector<const char*> args(argv, argv + argc);
return lld::wasm::link(args, false, llvm::outs(), llvm::errs());
lld::Result r = lld::lldMain(args, llvm::outs(), llvm::errs(), LLD_ALL_DRIVERS);
return !r.retCode;
}
} // external "C"
+104
View File
@@ -0,0 +1,104 @@
package builder
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/tinygo-org/tinygo/goenv"
)
var MinGW = Library{
name: "mingw-w64",
makeHeaders: func(target, includeDir string) error {
// copy _mingw.h
srcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib", "mingw-w64")
outf, err := os.Create(includeDir + "/_mingw.h")
if err != nil {
return err
}
defer outf.Close()
inf, err := os.Open(srcDir + "/mingw-w64-headers/crt/_mingw.h.in")
if err != nil {
return err
}
_, err = io.Copy(outf, inf)
return err
},
sourceDir: func() string { return "" }, // unused
cflags: func(target, headerPath string) []string {
// No flags necessary because there are no files to compile.
return nil
},
librarySources: func(target string) ([]string, error) {
// We only use the UCRT DLL file. No source files necessary.
return nil, nil
},
}
// makeMinGWExtraLibs returns a slice of jobs to import the correct .dll
// libraries. This is done by converting input .def files to .lib files which
// can then be linked as usual.
//
// TODO: cache the result. At the moment, it costs a few hundred milliseconds to
// compile these files.
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",
} {
outpath := filepath.Join(tmpdir, filepath.Base(name)+".lib")
inpath := filepath.Join(root, "lib/mingw-w64/mingw-w64-crt/lib-common/"+name)
job := &compileJob{
description: "create lib file " + inpath,
result: outpath,
run: func(job *compileJob) error {
defpath := inpath
var archDef, emulation string
switch goarch {
case "amd64":
archDef = "-DDEF_X64"
emulation = "i386pep"
case "arm64":
archDef = "-DDEF_ARM64"
emulation = "arm64pe"
default:
return fmt.Errorf("unsupported architecture for mingw-w64: %s", goarch)
}
if strings.HasSuffix(inpath, ".in") {
// .in files need to be preprocessed by a preprocessor (-E)
// first.
defpath = outpath + ".def"
err := runCCompiler("-E", "-x", "c", "-Wp,-w", "-P", archDef, "-DDATA", "-o", defpath, inpath, "-I"+goenv.Get("TINYGOROOT")+"/lib/mingw-w64/mingw-w64-crt/def-include/")
if err != nil {
return err
}
}
return link("ld.lld", "-m", emulation, "-o", outpath, defpath)
},
}
jobs = append(jobs, job)
}
return jobs
}
+176
View File
@@ -0,0 +1,176 @@
package builder
import (
"bytes"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
)
var Musl = Library{
name: "musl",
makeHeaders: func(target, includeDir string) error {
bits := filepath.Join(includeDir, "bits")
err := os.Mkdir(bits, 0777)
if err != nil {
return err
}
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"))
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"))
if err != nil {
return err
}
data, err := os.ReadFile(filepath.Join(muslDir, "arch", arch, "bits", "syscall.h.in"))
if err != nil {
return err
}
_, err = f.Write(bytes.ReplaceAll(data, []byte("__NR_"), []byte("SYS_")))
if err != nil {
return err
}
f.Close()
return nil
},
cflags: func(target, headerPath string) []string {
arch := compileopts.MuslArchitecture(target)
muslDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/musl")
cflags := []string{
"-std=c99", // same as in musl
"-D_XOPEN_SOURCE=700", // same as in musl
// Musl triggers some warnings and we don't want to show any
// warnings while compiling (only errors or silence), so disable
// specific warnings that are triggered in musl.
"-Werror",
"-Wno-logical-op-parentheses",
"-Wno-bitwise-op-parentheses",
"-Wno-shift-op-parentheses",
"-Wno-ignored-attributes",
"-Wno-string-plus-int",
"-Wno-ignored-pragmas",
"-Wno-tautological-constant-out-of-range-compare",
"-Wno-deprecated-non-prototype",
"-Qunused-arguments",
// Select include dirs. Don't include standard library includes
// (that would introduce host dependencies and other complications),
// but do include all the include directories expected by musl.
"-nostdlibinc",
"-I" + muslDir + "/arch/" + arch,
"-I" + muslDir + "/arch/generic",
"-I" + muslDir + "/src/include",
"-I" + muslDir + "/src/internal",
"-I" + headerPath,
"-I" + muslDir + "/include",
"-fno-stack-protector",
}
return cflags
},
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/musl/src") },
librarySources: func(target string) ([]string, error) {
arch := compileopts.MuslArchitecture(target)
globs := []string{
"env/*.c",
"errno/*.c",
"exit/*.c",
"internal/defsysinfo.c",
"internal/libc.c",
"internal/syscall_ret.c",
"internal/vdso.c",
"legacy/*.c",
"linux/*.c",
"malloc/*.c",
"malloc/mallocng/*.c",
"mman/*.c",
"math/*.c",
"signal/*.c",
"stdio/*.c",
"string/*.c",
"thread/" + arch + "/*.s",
"thread/*.c",
"time/*.c",
"unistd/*.c",
}
if arch == "arm" {
// These files need to be added to the start for some reason.
globs = append([]string{"thread/arm/*.c"}, globs...)
}
var sources []string
seenSources := map[string]struct{}{}
basepath := goenv.Get("TINYGOROOT") + "/lib/musl/src/"
for _, pattern := range globs {
matches, err := filepath.Glob(basepath + pattern)
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("musl: could not glob source dirs: %w", err)
}
if len(matches) == 0 {
return nil, fmt.Errorf("musl: did not find any files for pattern %#v", pattern)
}
for _, match := range matches {
relpath, err := filepath.Rel(basepath, match)
if err != nil {
// Not sure if this is even possible.
return nil, err
}
// Make sure architecture specific files override generic files.
id := strings.ReplaceAll(relpath, "/"+arch+"/", "/")
if _, ok := seenSources[id]; ok {
// Already seen this file, skipping this (generic) file.
continue
}
seenSources[id] = struct{}{}
sources = append(sources, relpath)
}
}
return sources, nil
},
crt1Source: "../crt/crt1.c", // lib/musl/crt/crt1.c
}
+117
View File
@@ -0,0 +1,117 @@
package builder
import (
"archive/zip"
"bytes"
"encoding/binary"
"encoding/json"
"os"
"github.com/sigurn/crc16"
"github.com/tinygo-org/tinygo/compileopts"
)
// Structure of the manifest.json file.
type jsonManifest struct {
Manifest struct {
Application struct {
BinaryFile string `json:"bin_file"`
DataFile string `json:"dat_file"`
InitPacketData nrfInitPacket `json:"init_packet_data"`
} `json:"application"`
DFUVersion float64 `json:"dfu_version"` // yes, this is a JSON number, not a string
} `json:"manifest"`
}
// Structure of the init packet.
// Source:
// https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/master/lib/sdk11/components/libraries/bootloader_dfu/dfu_init.h#L47-L57
type nrfInitPacket struct {
ApplicationVersion uint32 `json:"application_version"`
DeviceRevision uint16 `json:"device_revision"`
DeviceType uint16 `json:"device_type"`
FirmwareCRC16 uint16 `json:"firmware_crc16"`
SoftDeviceRequired []uint16 `json:"softdevice_req"` // this is actually a variable length array
}
// Create the init packet (the contents of application.dat).
func (p nrfInitPacket) createInitPacket() []byte {
buf := &bytes.Buffer{}
binary.Write(buf, binary.LittleEndian, p.DeviceType) // uint16_t device_type;
binary.Write(buf, binary.LittleEndian, p.DeviceRevision) // uint16_t device_rev;
binary.Write(buf, binary.LittleEndian, p.ApplicationVersion) // uint32_t app_version;
binary.Write(buf, binary.LittleEndian, uint16(len(p.SoftDeviceRequired))) // uint16_t softdevice_len;
binary.Write(buf, binary.LittleEndian, p.SoftDeviceRequired) // uint16_t softdevice[1];
binary.Write(buf, binary.LittleEndian, p.FirmwareCRC16)
return buf.Bytes()
}
// Make a Nordic DFU firmware image from an ELF file.
func makeDFUFirmwareImage(options *compileopts.Options, infile, outfile string) error {
// Read ELF file as input and convert it to a binary image file.
_, data, err := extractROM(infile)
if err != nil {
return err
}
// Create the zip file in memory.
// It won't be very large anyway.
buf := &bytes.Buffer{}
w := zip.NewWriter(buf)
// Write the application binary to the zip file.
binw, err := w.Create("application.bin")
if err != nil {
return err
}
_, err = binw.Write(data)
if err != nil {
return err
}
// Create the init packet.
initPacket := nrfInitPacket{
ApplicationVersion: 0xffff_ffff, // appears to be unused by the Adafruit bootloader
DeviceRevision: 0xffff, // DFU_DEVICE_REVISION_EMPTY
DeviceType: 0x0052, // ADAFRUIT_DEVICE_TYPE
FirmwareCRC16: crc16.Checksum(data, crc16.MakeTable(crc16.CRC16_CCITT_FALSE)),
SoftDeviceRequired: []uint16{0xfffe}, // DFU_SOFTDEVICE_ANY
}
// Write the init packet to the zip file.
datw, err := w.Create("application.dat")
if err != nil {
return err
}
_, err = datw.Write(initPacket.createInitPacket())
if err != nil {
return err
}
// Create the JSON manifest.
manifest := &jsonManifest{}
manifest.Manifest.Application.BinaryFile = "application.bin"
manifest.Manifest.Application.DataFile = "application.dat"
manifest.Manifest.Application.InitPacketData = initPacket
manifest.Manifest.DFUVersion = 0.5
// Write the JSON manifest to the file.
jsonw, err := w.Create("manifest.json")
if err != nil {
return err
}
enc := json.NewEncoder(jsonw)
enc.SetIndent("", " ")
err = enc.Encode(manifest)
if err != nil {
return err
}
// Finish the zip file.
err = w.Close()
if err != nil {
return err
}
return os.WriteFile(outfile, buf.Bytes(), 0o666)
}
+2 -2
View File
@@ -2,7 +2,7 @@ package builder
import (
"debug/elf"
"io/ioutil"
"io"
"os"
"sort"
@@ -87,7 +87,7 @@ func extractROM(path string) (uint64, []byte, error) {
// Pad the difference
rom = append(rom, make([]byte, diff)...)
}
data, err := ioutil.ReadAll(prog.Open())
data, err := io.ReadAll(prog.Open())
if err != nil {
return 0, nil, objcopyError{"failed to extract segment from ELF file: " + path, err}
}
+424 -109
View File
@@ -1,7 +1,9 @@
package builder
import (
"os"
"path/filepath"
"strings"
"github.com/tinygo-org/tinygo/goenv"
)
@@ -10,118 +12,431 @@ import (
// based on newlib.
var Picolibc = Library{
name: "picolibc",
cflags: func() []string {
picolibcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib/libc")
return []string{"-Werror", "-Wall", "-std=gnu11", "-D_COMPILING_NEWLIB", "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", picolibcDir + "/include", "-I" + picolibcDir + "/tinystdio", "-I" + goenv.Get("TINYGOROOT") + "/lib/picolibc-include"}
makeHeaders: func(target, includeDir string) error {
f, err := os.Create(filepath.Join(includeDir, "picolibc.h"))
if err != nil {
return err
}
return f.Close()
},
sourceDir: "lib/picolibc/newlib/libc",
sources: func(target string) []string {
return picolibcSources
cflags: func(target, headerPath string) []string {
newlibDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib")
return []string{
"-Werror",
"-Wall",
"-std=gnu11",
"-D_COMPILING_NEWLIB",
"-D_HAVE_ALIAS_ATTRIBUTE",
"-DTINY_STDIO",
"-DPOSIX_IO",
"-D_IEEE_LIBM",
"-D__OBSOLETE_MATH_FLOAT=1", // use old math code that doesn't expect a FPU
"-D__OBSOLETE_MATH_DOUBLE=0",
"-D_WANT_IO_C99_FORMATS",
"-nostdlibinc",
"-isystem", newlibDir + "/libc/include",
"-I" + newlibDir + "/libc/tinystdio",
"-I" + newlibDir + "/libm/common",
"-I" + headerPath,
}
},
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib") },
librarySources: func(target string) ([]string, error) {
sources := append([]string(nil), picolibcSources...)
if !strings.HasPrefix(target, "avr") {
// Small chips without long jumps can't compile many files (printf,
// pow, etc). Therefore exclude those source files for those chips.
// Unfortunately it's difficult to exclude only some chips, so this
// excludes those files on all AVR chips for now.
// More information:
// https://github.com/llvm/llvm-project/issues/67042
sources = append(sources, picolibcSourcesLarge...)
}
return sources, nil
},
}
var picolibcSources = []string{
"string/bcmp.c",
"string/bcopy.c",
"string/bzero.c",
"string/explicit_bzero.c",
"string/ffsl.c",
"string/ffsll.c",
"string/fls.c",
"string/flsl.c",
"string/flsll.c",
"string/gnu_basename.c",
"string/index.c",
"string/memccpy.c",
"string/memchr.c",
"string/memcmp.c",
"string/memcpy.c",
"string/memmem.c",
"string/memmove.c",
"string/mempcpy.c",
"string/memrchr.c",
"string/memset.c",
"string/rawmemchr.c",
"string/rindex.c",
"string/stpcpy.c",
"string/stpncpy.c",
"string/strcasecmp.c",
"string/strcasecmp_l.c",
"string/strcasestr.c",
"string/strcat.c",
"string/strchr.c",
"string/strchrnul.c",
"string/strcmp.c",
"string/strcoll.c",
"string/strcoll_l.c",
"string/strcpy.c",
"string/strcspn.c",
"string/strdup.c",
"string/strerror.c",
"string/strerror_r.c",
"string/strlcat.c",
"string/strlcpy.c",
"string/strlen.c",
"string/strlwr.c",
"string/strncasecmp.c",
"string/strncasecmp_l.c",
"string/strncat.c",
"string/strncmp.c",
"string/strncpy.c",
"string/strndup.c",
"string/strnlen.c",
"string/strnstr.c",
"string/strpbrk.c",
"string/strrchr.c",
"string/strsep.c",
"string/strsignal.c",
"string/strspn.c",
"string/strstr.c",
"string/strtok.c",
"string/strtok_r.c",
"string/strupr.c",
"string/strverscmp.c",
"string/strxfrm.c",
"string/strxfrm_l.c",
"string/swab.c",
"string/timingsafe_bcmp.c",
"string/timingsafe_memcmp.c",
"string/u_strerr.c",
"string/wcpcpy.c",
"string/wcpncpy.c",
"string/wcscasecmp.c",
"string/wcscasecmp_l.c",
"string/wcscat.c",
"string/wcschr.c",
"string/wcscmp.c",
"string/wcscoll.c",
"string/wcscoll_l.c",
"string/wcscpy.c",
"string/wcscspn.c",
"string/wcsdup.c",
"string/wcslcat.c",
"string/wcslcpy.c",
"string/wcslen.c",
"string/wcsncasecmp.c",
"string/wcsncasecmp_l.c",
"string/wcsncat.c",
"string/wcsncmp.c",
"string/wcsncpy.c",
"string/wcsnlen.c",
"string/wcspbrk.c",
"string/wcsrchr.c",
"string/wcsspn.c",
"string/wcsstr.c",
"string/wcstok.c",
"string/wcswidth.c",
"string/wcsxfrm.c",
"string/wcsxfrm_l.c",
"string/wcwidth.c",
"string/wmemchr.c",
"string/wmemcmp.c",
"string/wmemcpy.c",
"string/wmemmove.c",
"string/wmempcpy.c",
"string/wmemset.c",
"string/xpg_strerror_r.c",
"../../picolibc-stdio.c",
"libc/string/bcmp.c",
"libc/string/bcopy.c",
"libc/string/bzero.c",
"libc/string/explicit_bzero.c",
"libc/string/ffsl.c",
"libc/string/ffsll.c",
"libc/string/fls.c",
"libc/string/flsl.c",
"libc/string/flsll.c",
"libc/string/gnu_basename.c",
"libc/string/index.c",
"libc/string/memccpy.c",
"libc/string/memchr.c",
"libc/string/memcmp.c",
"libc/string/memcpy.c",
"libc/string/memmem.c",
"libc/string/memmove.c",
"libc/string/mempcpy.c",
"libc/string/memrchr.c",
"libc/string/memset.c",
"libc/string/rawmemchr.c",
"libc/string/rindex.c",
"libc/string/stpcpy.c",
"libc/string/stpncpy.c",
"libc/string/strcasecmp.c",
"libc/string/strcasecmp_l.c",
"libc/string/strcasestr.c",
"libc/string/strcat.c",
"libc/string/strchr.c",
"libc/string/strchrnul.c",
"libc/string/strcmp.c",
"libc/string/strcoll.c",
"libc/string/strcoll_l.c",
"libc/string/strcpy.c",
"libc/string/strcspn.c",
"libc/string/strdup.c",
"libc/string/strerror.c",
"libc/string/strerror_r.c",
"libc/string/strlcat.c",
"libc/string/strlcpy.c",
"libc/string/strlen.c",
"libc/string/strlwr.c",
"libc/string/strncasecmp.c",
"libc/string/strncasecmp_l.c",
"libc/string/strncat.c",
"libc/string/strncmp.c",
"libc/string/strncpy.c",
"libc/string/strndup.c",
"libc/string/strnlen.c",
"libc/string/strnstr.c",
"libc/string/strpbrk.c",
"libc/string/strrchr.c",
"libc/string/strsep.c",
"libc/string/strsignal.c",
"libc/string/strspn.c",
"libc/string/strstr.c",
"libc/string/strtok.c",
"libc/string/strtok_r.c",
"libc/string/strupr.c",
"libc/string/strverscmp.c",
"libc/string/strxfrm.c",
"libc/string/strxfrm_l.c",
"libc/string/swab.c",
"libc/string/timingsafe_bcmp.c",
"libc/string/timingsafe_memcmp.c",
"libc/string/u_strerr.c",
"libc/string/wcpcpy.c",
"libc/string/wcpncpy.c",
"libc/string/wcscasecmp.c",
"libc/string/wcscasecmp_l.c",
"libc/string/wcscat.c",
"libc/string/wcschr.c",
"libc/string/wcscmp.c",
"libc/string/wcscoll.c",
"libc/string/wcscoll_l.c",
"libc/string/wcscpy.c",
"libc/string/wcscspn.c",
"libc/string/wcsdup.c",
"libc/string/wcslcat.c",
"libc/string/wcslcpy.c",
"libc/string/wcslen.c",
"libc/string/wcsncasecmp.c",
"libc/string/wcsncasecmp_l.c",
"libc/string/wcsncat.c",
"libc/string/wcsncmp.c",
"libc/string/wcsncpy.c",
"libc/string/wcsnlen.c",
"libc/string/wcspbrk.c",
"libc/string/wcsrchr.c",
"libc/string/wcsspn.c",
"libc/string/wcsstr.c",
"libc/string/wcstok.c",
"libc/string/wcswidth.c",
"libc/string/wcsxfrm.c",
"libc/string/wcsxfrm_l.c",
"libc/string/wcwidth.c",
"libc/string/wmemchr.c",
"libc/string/wmemcmp.c",
"libc/string/wmemcpy.c",
"libc/string/wmemmove.c",
"libc/string/wmempcpy.c",
"libc/string/wmemset.c",
"libc/string/xpg_strerror_r.c",
}
// Parts of picolibc that are too large for small AVRs.
var picolibcSourcesLarge = []string{
// srcs_tinystdio
"libc/tinystdio/asprintf.c",
"libc/tinystdio/bufio.c",
"libc/tinystdio/clearerr.c",
"libc/tinystdio/ecvt_r.c",
"libc/tinystdio/ecvt.c",
"libc/tinystdio/ecvtf_r.c",
"libc/tinystdio/ecvtf.c",
"libc/tinystdio/fcvt.c",
"libc/tinystdio/fcvt_r.c",
"libc/tinystdio/fcvtf.c",
"libc/tinystdio/fcvtf_r.c",
"libc/tinystdio/gcvt.c",
"libc/tinystdio/gcvtf.c",
"libc/tinystdio/fclose.c",
"libc/tinystdio/fdevopen.c",
"libc/tinystdio/feof.c",
"libc/tinystdio/ferror.c",
"libc/tinystdio/fflush.c",
"libc/tinystdio/fgetc.c",
"libc/tinystdio/fgets.c",
"libc/tinystdio/fileno.c",
"libc/tinystdio/filestrget.c",
"libc/tinystdio/filestrput.c",
"libc/tinystdio/filestrputalloc.c",
"libc/tinystdio/fmemopen.c",
"libc/tinystdio/fprintf.c",
"libc/tinystdio/fputc.c",
"libc/tinystdio/fputs.c",
"libc/tinystdio/fread.c",
//"libc/tinystdio/freopen.c", // crashes with AVR, see: https://github.com/picolibc/picolibc/pull/369
"libc/tinystdio/fscanf.c",
"libc/tinystdio/fseek.c",
"libc/tinystdio/fseeko.c",
"libc/tinystdio/ftell.c",
"libc/tinystdio/ftello.c",
"libc/tinystdio/fwrite.c",
"libc/tinystdio/getchar.c",
"libc/tinystdio/gets.c",
"libc/tinystdio/matchcaseprefix.c",
"libc/tinystdio/mktemp.c",
"libc/tinystdio/perror.c",
"libc/tinystdio/printf.c",
"libc/tinystdio/putchar.c",
"libc/tinystdio/puts.c",
"libc/tinystdio/rewind.c",
"libc/tinystdio/scanf.c",
"libc/tinystdio/setbuf.c",
"libc/tinystdio/setbuffer.c",
"libc/tinystdio/setlinebuf.c",
"libc/tinystdio/setvbuf.c",
"libc/tinystdio/snprintf.c",
"libc/tinystdio/sprintf.c",
"libc/tinystdio/snprintfd.c",
"libc/tinystdio/snprintff.c",
"libc/tinystdio/sprintff.c",
"libc/tinystdio/sprintfd.c",
"libc/tinystdio/sscanf.c",
"libc/tinystdio/strfromf.c",
"libc/tinystdio/strfromd.c",
"libc/tinystdio/strtof.c",
"libc/tinystdio/strtof_l.c",
"libc/tinystdio/strtod.c",
"libc/tinystdio/strtod_l.c",
"libc/tinystdio/ungetc.c",
"libc/tinystdio/vasprintf.c",
"libc/tinystdio/vfiprintf.c",
"libc/tinystdio/vfprintf.c",
"libc/tinystdio/vfprintff.c",
"libc/tinystdio/vfscanf.c",
"libc/tinystdio/vfiscanf.c",
"libc/tinystdio/vfscanff.c",
"libc/tinystdio/vprintf.c",
"libc/tinystdio/vscanf.c",
"libc/tinystdio/vsscanf.c",
"libc/tinystdio/vsnprintf.c",
"libc/tinystdio/vsprintf.c",
"libm/common/sf_finite.c",
"libm/common/sf_copysign.c",
"libm/common/sf_modf.c",
"libm/common/sf_scalbn.c",
"libm/common/sf_cbrt.c",
"libm/common/sf_exp10.c",
"libm/common/sf_expm1.c",
"libm/common/sf_ilogb.c",
"libm/common/sf_infinity.c",
"libm/common/sf_isinf.c",
"libm/common/sf_isinff.c",
"libm/common/sf_isnan.c",
"libm/common/sf_isnanf.c",
"libm/common/sf_issignaling.c",
"libm/common/sf_log1p.c",
"libm/common/sf_nan.c",
"libm/common/sf_nextafter.c",
"libm/common/sf_pow10.c",
"libm/common/sf_rint.c",
"libm/common/sf_logb.c",
"libm/common/sf_fdim.c",
"libm/common/sf_fma.c",
"libm/common/sf_fmax.c",
"libm/common/sf_fmin.c",
"libm/common/sf_fpclassify.c",
"libm/common/sf_lrint.c",
"libm/common/sf_llrint.c",
"libm/common/sf_lround.c",
"libm/common/sf_llround.c",
"libm/common/sf_nearbyint.c",
"libm/common/sf_remquo.c",
"libm/common/sf_round.c",
"libm/common/sf_scalbln.c",
"libm/common/sf_trunc.c",
"libm/common/sf_exp.c",
"libm/common/sf_exp2.c",
"libm/common/sf_exp2_data.c",
"libm/common/sf_log.c",
"libm/common/sf_log_data.c",
"libm/common/sf_log2.c",
"libm/common/sf_log2_data.c",
"libm/common/sf_pow_log2_data.c",
"libm/common/sf_pow.c",
"libm/common/s_finite.c",
"libm/common/s_copysign.c",
"libm/common/s_modf.c",
"libm/common/s_scalbn.c",
"libm/common/s_cbrt.c",
"libm/common/s_exp10.c",
"libm/common/s_expm1.c",
"libm/common/s_ilogb.c",
"libm/common/s_infinity.c",
"libm/common/s_iseqsig.c",
"libm/common/s_isinf.c",
"libm/common/s_isinfd.c",
"libm/common/s_isnan.c",
"libm/common/s_isnand.c",
"libm/common/s_issignaling.c",
"libm/common/s_log1p.c",
"libm/common/s_nan.c",
"libm/common/s_nextafter.c",
"libm/common/s_pow10.c",
"libm/common/s_rint.c",
"libm/common/s_logb.c",
"libm/common/s_log2.c",
"libm/common/s_fdim.c",
"libm/common/s_fma.c",
"libm/common/s_fmax.c",
"libm/common/s_fmin.c",
"libm/common/s_fpclassify.c",
"libm/common/s_getpayload.c",
"libm/common/s_lrint.c",
"libm/common/s_llrint.c",
"libm/common/s_lround.c",
"libm/common/s_llround.c",
"libm/common/s_nearbyint.c",
"libm/common/s_remquo.c",
"libm/common/s_round.c",
"libm/common/s_scalbln.c",
"libm/common/s_signbit.c",
"libm/common/s_trunc.c",
"libm/common/exp.c",
"libm/common/exp2.c",
"libm/common/exp_data.c",
"libm/common/math_err_with_errno.c",
"libm/common/math_err_uflow.c",
"libm/common/math_err_oflow.c",
"libm/common/math_err_divzero.c",
"libm/common/math_err_invalid.c",
"libm/common/math_err_may_uflow.c",
"libm/common/math_err_check_uflow.c",
"libm/common/math_err_check_oflow.c",
"libm/common/math_errf_divzerof.c",
"libm/common/math_errf_invalidf.c",
"libm/common/math_errf_may_uflowf.c",
"libm/common/math_errf_oflowf.c",
"libm/common/math_errf_uflowf.c",
"libm/common/math_errf_with_errnof.c",
"libm/common/math_inexact.c",
"libm/common/math_inexactf.c",
"libm/common/log.c",
"libm/common/log_data.c",
"libm/common/log2.c",
"libm/common/log2_data.c",
"libm/common/pow.c",
"libm/common/pow_log_data.c",
"libm/math/k_cos.c",
"libm/math/k_rem_pio2.c",
"libm/math/k_sin.c",
"libm/math/k_tan.c",
"libm/math/kf_cos.c",
"libm/math/kf_rem_pio2.c",
"libm/math/kf_sin.c",
"libm/math/kf_tan.c",
"libm/math/s_acos.c",
"libm/math/s_acosh.c",
"libm/math/s_asin.c",
"libm/math/s_asinh.c",
"libm/math/s_atan.c",
"libm/math/s_atan2.c",
"libm/math/s_atanh.c",
"libm/math/s_ceil.c",
"libm/math/s_cos.c",
"libm/math/s_cosh.c",
"libm/math/s_drem.c",
"libm/math/s_erf.c",
"libm/math/s_exp.c",
"libm/math/s_exp2.c",
"libm/math/s_fabs.c",
"libm/math/s_floor.c",
"libm/math/s_fmod.c",
"libm/math/s_frexp.c",
"libm/math/s_gamma.c",
"libm/math/s_hypot.c",
"libm/math/s_j0.c",
"libm/math/s_j1.c",
"libm/math/s_jn.c",
"libm/math/s_lgamma.c",
"libm/math/s_log.c",
"libm/math/s_log10.c",
"libm/math/s_pow.c",
"libm/math/s_rem_pio2.c",
"libm/math/s_remainder.c",
"libm/math/s_scalb.c",
"libm/math/s_signif.c",
"libm/math/s_sin.c",
"libm/math/s_sincos.c",
"libm/math/s_sinh.c",
"libm/math/s_sqrt.c",
"libm/math/s_tan.c",
"libm/math/s_tanh.c",
"libm/math/s_tgamma.c",
"libm/math/sf_acos.c",
"libm/math/sf_acosh.c",
"libm/math/sf_asin.c",
"libm/math/sf_asinh.c",
"libm/math/sf_atan.c",
"libm/math/sf_atan2.c",
"libm/math/sf_atanh.c",
"libm/math/sf_ceil.c",
"libm/math/sf_cos.c",
"libm/math/sf_cosh.c",
"libm/math/sf_drem.c",
"libm/math/sf_erf.c",
"libm/math/sf_exp.c",
"libm/math/sf_exp2.c",
"libm/math/sf_fabs.c",
"libm/math/sf_floor.c",
"libm/math/sf_fmod.c",
"libm/math/sf_frexp.c",
"libm/math/sf_gamma.c",
"libm/math/sf_hypot.c",
"libm/math/sf_j0.c",
"libm/math/sf_j1.c",
"libm/math/sf_jn.c",
"libm/math/sf_lgamma.c",
"libm/math/sf_log.c",
"libm/math/sf_log10.c",
"libm/math/sf_log2.c",
"libm/math/sf_pow.c",
"libm/math/sf_rem_pio2.c",
"libm/math/sf_remainder.c",
"libm/math/sf_scalb.c",
"libm/math/sf_signif.c",
"libm/math/sf_sin.c",
"libm/math/sf_sincos.c",
"libm/math/sf_sinh.c",
"libm/math/sf_sqrt.c",
"libm/math/sf_tan.c",
"libm/math/sf_tanh.c",
"libm/math/sf_tgamma.c",
"libm/math/sr_lgamma.c",
"libm/math/srf_lgamma.c",
}
+868 -106
View File
File diff suppressed because it is too large Load Diff
+92
View File
@@ -0,0 +1,92 @@
package builder
import (
"runtime"
"testing"
"time"
"github.com/tinygo-org/tinygo/compileopts"
)
var sema = make(chan struct{}, runtime.NumCPU())
type sizeTest struct {
target string
path string
codeSize uint64
rodataSize uint64
dataSize uint64
bssSize uint64
}
// Test whether code and data size is as expected for the given targets.
// This tests both the logic of loadProgramSize and checks that code size
// doesn't change unintentionally.
//
// If you find that code or data size is reduced, then great! You can reduce the
// number in this test.
// If you find that the code or data size is increased, take a look as to why
// this is. It could be due to an update (LLVM version, Go version, etc) which
// is fine, but it could also mean that a recent change introduced this size
// increase. If so, please consider whether this new feature is indeed worth the
// size increase for all users.
func TestBinarySize(t *testing.T) {
if runtime.GOOS == "linux" && !hasBuiltinTools {
// Debian LLVM packages are modified a bit and tend to produce
// different machine code. Ideally we'd fix this (with some attributes
// or something?), but for now skip it.
t.Skip("Skip: using external LLVM version so binary size might differ")
}
// This is a small number of very diverse targets that we want to test.
tests := []sizeTest{
// microcontrollers
{"hifive1b", "examples/echo", 4484, 280, 0, 2252},
{"microbit", "examples/serial", 2732, 388, 8, 2256},
{"wioterminal", "examples/pininterrupt", 6016, 1484, 116, 6816},
// TODO: also check wasm. Right now this is difficult, because
// wasm binaries are run through wasm-opt and therefore the
// output varies by binaryen version.
}
for _, tc := range tests {
tc := tc
t.Run(tc.target+"/"+tc.path, func(t *testing.T) {
t.Parallel()
// Build the binary.
options := compileopts.Options{
Target: tc.target,
Opt: "z",
Semaphore: sema,
InterpTimeout: 60 * time.Second,
Debug: true,
VerifyIR: true,
}
target, err := compileopts.LoadTarget(&options)
if err != nil {
t.Fatal("could not load target:", err)
}
config := &compileopts.Config{
Options: &options,
Target: target,
}
result, err := Build(tc.path, "", t.TempDir(), config)
if err != nil {
t.Fatal("could not build:", err)
}
// Check whether the size of the binary matches the expected size.
sizes, err := loadProgramSize(result.Executable, nil)
if err != nil {
t.Fatal("could not read program size:", err)
}
if sizes.Code != tc.codeSize || sizes.ROData != tc.rodataSize || sizes.Data != tc.dataSize || sizes.BSS != tc.bssSize {
t.Errorf("Unexpected code size when compiling: -target=%s %s", tc.target, tc.path)
t.Errorf(" code rodata data bss")
t.Errorf("expected: %6d %6d %6d %6d", tc.codeSize, tc.rodataSize, tc.dataSize, tc.bssSize)
t.Errorf("actual: %6d %6d %6d %6d", sizes.Code, sizes.ROData, sizes.Data, sizes.BSS)
}
})
}
}
+5 -8
View File
@@ -1,4 +1,4 @@
// +build byollvm
//go:build byollvm
package builder
@@ -12,8 +12,7 @@ import (
#include <stdbool.h>
#include <stdlib.h>
bool tinygo_clang_driver(int argc, char **argv);
bool tinygo_link_elf(int argc, char **argv);
bool tinygo_link_wasm(int argc, char **argv);
bool tinygo_link(int argc, char **argv);
*/
import "C"
@@ -24,7 +23,7 @@ const hasBuiltinTools = true
// This version actually runs the tools because TinyGo was compiled while
// linking statically with LLVM (with the byollvm build tag).
func RunTool(tool string, args ...string) error {
args = append([]string{"tinygo:" + tool}, args...)
args = append([]string{tool}, args...)
var cflag *C.char
buf := C.calloc(C.size_t(len(args)), C.size_t(unsafe.Sizeof(cflag)))
@@ -40,10 +39,8 @@ func RunTool(tool string, args ...string) error {
switch tool {
case "clang":
ok = C.tinygo_clang_driver(C.int(len(args)), (**C.char)(buf))
case "ld.lld":
ok = C.tinygo_link_elf(C.int(len(args)), (**C.char)(buf))
case "wasm-ld":
ok = C.tinygo_link_wasm(C.int(len(args)), (**C.char)(buf))
case "ld.lld", "wasm-ld":
ok = C.tinygo_link(C.int(len(args)), (**C.char)(buf))
default:
return errors.New("unknown tool: " + tool)
}
+1 -1
View File
@@ -1,4 +1,4 @@
// +build !byollvm
//go:build !byollvm
package builder
+6 -21
View File
@@ -1,7 +1,6 @@
package builder
import (
"errors"
"os"
"os/exec"
@@ -9,31 +8,17 @@ import (
)
// runCCompiler invokes a C compiler with the given arguments.
func runCCompiler(command string, flags ...string) error {
if hasBuiltinTools && command == "clang" {
func runCCompiler(flags ...string) error {
if hasBuiltinTools {
// Compile this with the internal Clang compiler.
headerPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
if headerPath == "" {
return errors.New("could not locate Clang headers")
}
flags = append(flags, "-I"+headerPath)
cmd := exec.Command(os.Args[0], append([]string{"clang"}, flags...)...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
// Running some other compiler. Maybe it has been defined in the
// commands map (unlikely).
if cmdNames, ok := commands[command]; ok {
return execCommand(cmdNames, flags...)
}
// Alternatively, run the compiler directly.
cmd := exec.Command(command, flags...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
// Compile this with an external invocation of the Clang compiler.
return execCommand("clang", flags...)
}
// link invokes a linker with the given name and flags.
@@ -47,8 +32,8 @@ func link(linker string, flags ...string) error {
}
// Fall back to external command.
if cmdNames, ok := commands[linker]; ok {
return execCommand(cmdNames, flags...)
if _, ok := commands[linker]; ok {
return execCommand(linker, flags...)
}
cmd := exec.Command(linker, flags...)
+5 -3
View File
@@ -10,7 +10,7 @@ package builder
import (
"bytes"
"encoding/binary"
"io/ioutil"
"os"
"strconv"
)
@@ -26,7 +26,7 @@ func convertELFFileToUF2File(infile, outfile string, uf2FamilyID string) error {
if err != nil {
return err
}
return ioutil.WriteFile(outfile, output, 0644)
return os.WriteFile(outfile, output, 0644)
}
// convertBinToUF2 converts the binary bytes in input to UF2 formatted data.
@@ -141,11 +141,13 @@ func split(input []byte, limit int) [][]byte {
var block []byte
output := make([][]byte, 0, len(input)/limit+1)
for len(input) >= limit {
// add all blocks
block, input = input[:limit], input[limit:]
output = append(output, block)
}
if len(input) > 0 {
output = append(output, input[:len(input)])
// add remaining block (that isn't full sized)
output = append(output, input)
}
return output
}
+81
View File
@@ -0,0 +1,81 @@
package builder
import (
"os"
"path/filepath"
"github.com/tinygo-org/tinygo/goenv"
)
var WasmBuiltins = Library{
name: "wasmbuiltins",
makeHeaders: func(target, includeDir string) error {
if err := os.Mkdir(includeDir+"/bits", 0o777); err != nil {
return err
}
f, err := os.Create(includeDir + "/bits/alltypes.h")
if err != nil {
return err
}
if _, err := f.Write([]byte(wasmAllTypes)); err != nil {
return err
}
return f.Close()
},
cflags: func(target, headerPath string) []string {
libcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc")
return []string{
"-Werror",
"-Wall",
"-std=gnu11",
"-nostdlibinc",
"-isystem", libcDir + "/libc-top-half/musl/arch/wasm32",
"-isystem", libcDir + "/libc-top-half/musl/arch/generic",
"-isystem", libcDir + "/libc-top-half/musl/src/internal",
"-isystem", libcDir + "/libc-top-half/musl/src/include",
"-isystem", libcDir + "/libc-top-half/musl/include",
"-isystem", libcDir + "/libc-bottom-half/headers/public",
"-I" + headerPath,
}
},
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc") },
librarySources: func(target string) ([]string, error) {
return []string{
// memory builtins needed for llvm.memcpy.*, llvm.memmove.*, and
// llvm.memset.* LLVM intrinsics.
"libc-top-half/musl/src/string/memcpy.c",
"libc-top-half/musl/src/string/memmove.c",
"libc-top-half/musl/src/string/memset.c",
// exp, exp2, and log are needed for LLVM math builtin functions
// like llvm.exp.*.
"libc-top-half/musl/src/math/__math_divzero.c",
"libc-top-half/musl/src/math/__math_invalid.c",
"libc-top-half/musl/src/math/__math_oflow.c",
"libc-top-half/musl/src/math/__math_uflow.c",
"libc-top-half/musl/src/math/__math_xflow.c",
"libc-top-half/musl/src/math/exp.c",
"libc-top-half/musl/src/math/exp_data.c",
"libc-top-half/musl/src/math/exp2.c",
"libc-top-half/musl/src/math/log.c",
"libc-top-half/musl/src/math/log_data.c",
}, nil
},
}
// alltypes.h for wasm-libc, using the types as defined inside Clang.
const wasmAllTypes = `
typedef __SIZE_TYPE__ size_t;
typedef __INT8_TYPE__ int8_t;
typedef __INT16_TYPE__ int16_t;
typedef __INT32_TYPE__ int32_t;
typedef __INT64_TYPE__ int64_t;
typedef __UINT8_TYPE__ uint8_t;
typedef __UINT16_TYPE__ uint16_t;
typedef __UINT32_TYPE__ uint32_t;
typedef __UINT64_TYPE__ uint64_t;
typedef __UINTPTR_TYPE__ uintptr_t;
// This type is used internally in wasi-libc.
typedef double double_t;
`
+623 -694
View File
File diff suppressed because it is too large Load Diff
+17
View File
@@ -0,0 +1,17 @@
//go:build go1.22
package cgo
// Code specifically for Go 1.22.
import (
"go/ast"
"go/token"
)
func init() {
setASTFileFields = func(f *ast.File, start, end token.Pos) {
f.FileStart = start
f.FileEnd = end
}
}
+102 -34
View File
@@ -5,12 +5,11 @@ import (
"flag"
"fmt"
"go/ast"
"go/build"
"go/format"
"go/parser"
"go/token"
"go/types"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"runtime"
@@ -23,39 +22,30 @@ var flagUpdate = flag.Bool("update", false, "Update images based on test output.
// normalizeResult normalizes Go source code that comes out of tests across
// platforms and Go versions.
func normalizeResult(result string) string {
actual := strings.ReplaceAll(result, "\r\n", "\n")
func normalizeResult(t *testing.T, result string) string {
result = strings.ReplaceAll(result, "\r\n", "\n")
// Make sure all functions are wrapped, even those that would otherwise be
// single-line functions. This is necessary because Go 1.14 changed the way
// such functions are wrapped and it's important to have consistent test
// results.
re := regexp.MustCompile(`func \((.+)\)( .*?) +{ (.+) }`)
actual = re.ReplaceAllString(actual, "func ($1)$2 {\n\t$3\n}")
// This changed to 'undefined:', in Go 1.20.
result = strings.ReplaceAll(result, ": undeclared name:", ": undefined:")
// Go 1.20 added a bit more detail
result = regexp.MustCompile(`(unknown field z in struct literal).*`).ReplaceAllString(result, "$1")
return actual
return result
}
func TestCGo(t *testing.T) {
var cflags = []string{"--target=armv6m-none-eabi"}
var cflags = []string{"--target=armv6m-unknown-unknown-eabi"}
for _, name := range []string{"basic", "errors", "types", "flags", "const"} {
for _, name := range []string{
"basic",
"errors",
"types",
"symbols",
"flags",
"const",
} {
name := name // avoid a race condition
t.Run(name, func(t *testing.T) {
// Skip tests that require specific Go version.
if name == "errors" {
ok := false
for _, version := range build.Default.ReleaseTags {
if version == "go1.16" {
ok = true
break
}
}
if !ok {
t.Skip("Results for errors test are only valid for Go 1.16+")
}
}
// Read the AST in memory.
path := filepath.Join("testdata", name+".go")
fset := token.NewFileSet()
@@ -65,7 +55,7 @@ func TestCGo(t *testing.T) {
}
// Process the AST with CGo.
cgoAST, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags)
cgoFiles, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", "main", fset, cflags)
// Check the AST for type errors.
var typecheckErrors []error
@@ -76,7 +66,7 @@ func TestCGo(t *testing.T) {
Importer: simpleImporter{},
Sizes: types.SizesFor("gccgo", "arm"),
}
_, err = config.Check("", fset, []*ast.File{f, cgoAST}, nil)
_, err = config.Check("", fset, append([]*ast.File{f}, cgoFiles...), nil)
if err != nil && len(typecheckErrors) == 0 {
// Only report errors when no type errors are found (an
// unexpected condition).
@@ -101,15 +91,15 @@ func TestCGo(t *testing.T) {
}
buf.WriteString("\n")
}
err = format.Node(buf, fset, cgoAST)
err = format.Node(buf, fset, cgoFiles[0])
if err != nil {
t.Errorf("could not write out CGo AST: %v", err)
}
actual := normalizeResult(string(buf.Bytes()))
actual := normalizeResult(t, buf.String())
// Read the file with the expected output, to compare against.
outfile := filepath.Join("testdata", name+".out.go")
expectedBytes, err := ioutil.ReadFile(outfile)
expectedBytes, err := os.ReadFile(outfile)
if err != nil {
t.Fatalf("could not read expected output: %v", err)
}
@@ -120,7 +110,7 @@ func TestCGo(t *testing.T) {
// It is not. Test failed.
if *flagUpdate {
// Update the file with the expected data.
err := ioutil.WriteFile(outfile, []byte(actual), 0666)
err := os.WriteFile(outfile, []byte(actual), 0666)
if err != nil {
t.Error("could not write updated output file:", err)
}
@@ -132,6 +122,84 @@ func TestCGo(t *testing.T) {
}
}
func Test_cgoPackage_isEquivalentAST(t *testing.T) {
fieldA := &ast.Field{Type: &ast.BasicLit{Kind: token.STRING, Value: "a"}}
fieldB := &ast.Field{Type: &ast.BasicLit{Kind: token.STRING, Value: "b"}}
listOfFieldA := &ast.FieldList{List: []*ast.Field{fieldA}}
listOfFieldB := &ast.FieldList{List: []*ast.Field{fieldB}}
funcDeclA := &ast.FuncDecl{Name: &ast.Ident{Name: "a"}, Type: &ast.FuncType{Params: &ast.FieldList{}, Results: listOfFieldA}}
funcDeclB := &ast.FuncDecl{Name: &ast.Ident{Name: "b"}, Type: &ast.FuncType{Params: &ast.FieldList{}, Results: listOfFieldB}}
funcDeclNoResults := &ast.FuncDecl{Name: &ast.Ident{Name: "C"}, Type: &ast.FuncType{Params: &ast.FieldList{}}}
testCases := []struct {
name string
a, b ast.Node
expected bool
}{
{
name: "both nil",
expected: true,
},
{
name: "not same type",
a: fieldA,
b: &ast.FuncDecl{},
expected: false,
},
{
name: "Field same",
a: fieldA,
b: fieldA,
expected: true,
},
{
name: "Field different",
a: fieldA,
b: fieldB,
expected: false,
},
{
name: "FuncDecl Type Results nil",
a: funcDeclNoResults,
b: funcDeclNoResults,
expected: true,
},
{
name: "FuncDecl Type Results same",
a: funcDeclA,
b: funcDeclA,
expected: true,
},
{
name: "FuncDecl Type Results different",
a: funcDeclA,
b: funcDeclB,
expected: false,
},
{
name: "FuncDecl Type Results a nil",
a: funcDeclNoResults,
b: funcDeclB,
expected: false,
},
{
name: "FuncDecl Type Results b nil",
a: funcDeclA,
b: funcDeclNoResults,
expected: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
p := &cgoPackage{}
if got := p.isEquivalentAST(tc.a, tc.b); tc.expected != got {
t.Errorf("expected %v, got %v", tc.expected, got)
}
})
}
}
// simpleImporter implements the types.Importer interface, but only allows
// importing the unsafe package.
type simpleImporter struct {
@@ -148,7 +216,7 @@ func (i simpleImporter) Import(path string) (*types.Package, error) {
}
}
// formatDiagnostics formats the error message to be an indented comment. It
// formatDiagnostic formats the error message to be an indented comment. It
// also fixes Windows path name issues (backward slashes).
func formatDiagnostic(err error) string {
msg := err.Error()
+197 -74
View File
@@ -11,105 +11,194 @@ import (
"strings"
)
var (
prefixParseFns map[token.Token]func(*tokenizer) (ast.Expr, *scanner.Error)
precedences = map[token.Token]int{
token.OR: precedenceOr,
token.XOR: precedenceXor,
token.AND: precedenceAnd,
token.SHL: precedenceShift,
token.SHR: precedenceShift,
token.ADD: precedenceAdd,
token.SUB: precedenceAdd,
token.MUL: precedenceMul,
token.QUO: precedenceMul,
token.REM: precedenceMul,
}
)
// See: https://en.cppreference.com/w/c/language/operator_precedence
const (
precedenceLowest = iota + 1
precedenceOr
precedenceXor
precedenceAnd
precedenceShift
precedenceAdd
precedenceMul
precedencePrefix
)
func init() {
// This must be done in an init function to avoid an initialization order
// failure.
prefixParseFns = map[token.Token]func(*tokenizer) (ast.Expr, *scanner.Error){
token.IDENT: parseIdent,
token.INT: parseBasicLit,
token.FLOAT: parseBasicLit,
token.STRING: parseBasicLit,
token.CHAR: parseBasicLit,
token.LPAREN: parseParenExpr,
token.SUB: parseUnaryExpr,
}
}
// parseConst parses the given string as a C constant.
func parseConst(pos token.Pos, fset *token.FileSet, value string) (ast.Expr, *scanner.Error) {
t := newTokenizer(pos, fset, value)
expr, err := parseConstExpr(t)
if t.token != token.EOF {
expr, err := parseConstExpr(t, precedenceLowest)
t.Next()
if t.curToken != token.EOF {
return nil, &scanner.Error{
Pos: t.fset.Position(t.pos),
Msg: "unexpected token " + t.token.String(),
Pos: t.fset.Position(t.curPos),
Msg: "unexpected token " + t.curToken.String() + ", expected end of expression",
}
}
return expr, err
}
// parseConstExpr parses a stream of C tokens to a Go expression.
func parseConstExpr(t *tokenizer) (ast.Expr, *scanner.Error) {
switch t.token {
case token.LPAREN:
lparen := t.pos
t.Next()
x, err := parseConstExpr(t)
if err != nil {
return nil, err
}
if t.token != token.RPAREN {
return nil, unexpectedToken(t, token.RPAREN)
}
expr := &ast.ParenExpr{
Lparen: lparen,
X: x,
Rparen: t.pos,
}
t.Next()
return expr, nil
case token.INT, token.FLOAT, token.STRING, token.CHAR:
expr := &ast.BasicLit{
ValuePos: t.pos,
Kind: t.token,
Value: t.value,
}
t.Next()
return expr, nil
case token.IDENT:
expr := &ast.Ident{
NamePos: t.pos,
Name: "C." + t.value,
}
t.Next()
return expr, nil
case token.EOF:
func parseConstExpr(t *tokenizer, precedence int) (ast.Expr, *scanner.Error) {
if t.curToken == token.EOF {
return nil, &scanner.Error{
Pos: t.fset.Position(t.pos),
Pos: t.fset.Position(t.curPos),
Msg: "empty constant",
}
default:
}
prefix := prefixParseFns[t.curToken]
if prefix == nil {
return nil, &scanner.Error{
Pos: t.fset.Position(t.pos),
Msg: fmt.Sprintf("unexpected token %s", t.token),
Pos: t.fset.Position(t.curPos),
Msg: fmt.Sprintf("unexpected token %s", t.curToken),
}
}
leftExpr, err := prefix(t)
for t.peekToken != token.EOF && precedence < precedences[t.peekToken] {
switch t.peekToken {
case token.OR, token.XOR, token.AND, token.SHL, token.SHR, token.ADD, token.SUB, token.MUL, token.QUO, token.REM:
t.Next()
leftExpr, err = parseBinaryExpr(t, leftExpr)
}
}
return leftExpr, err
}
func parseIdent(t *tokenizer) (ast.Expr, *scanner.Error) {
return &ast.Ident{
NamePos: t.curPos,
Name: "C." + t.curValue,
}, nil
}
func parseBasicLit(t *tokenizer) (ast.Expr, *scanner.Error) {
return &ast.BasicLit{
ValuePos: t.curPos,
Kind: t.curToken,
Value: t.curValue,
}, nil
}
func parseParenExpr(t *tokenizer) (ast.Expr, *scanner.Error) {
lparen := t.curPos
t.Next()
x, err := parseConstExpr(t, precedenceLowest)
if err != nil {
return nil, err
}
t.Next()
if t.curToken != token.RPAREN {
return nil, unexpectedToken(t, token.RPAREN)
}
expr := &ast.ParenExpr{
Lparen: lparen,
X: x,
Rparen: t.curPos,
}
return expr, nil
}
func parseBinaryExpr(t *tokenizer, left ast.Expr) (ast.Expr, *scanner.Error) {
expression := &ast.BinaryExpr{
X: left,
Op: t.curToken,
OpPos: t.curPos,
}
precedence := precedences[t.curToken]
t.Next()
right, err := parseConstExpr(t, precedence)
expression.Y = right
return expression, err
}
func parseUnaryExpr(t *tokenizer) (ast.Expr, *scanner.Error) {
expression := &ast.UnaryExpr{
OpPos: t.curPos,
Op: t.curToken,
}
t.Next()
x, err := parseConstExpr(t, precedencePrefix)
expression.X = x
return expression, err
}
// unexpectedToken returns an error of the form "unexpected token FOO, expected
// BAR".
func unexpectedToken(t *tokenizer, expected token.Token) *scanner.Error {
return &scanner.Error{
Pos: t.fset.Position(t.pos),
Msg: fmt.Sprintf("unexpected token %s, expected %s", t.token, expected),
Pos: t.fset.Position(t.curPos),
Msg: fmt.Sprintf("unexpected token %s, expected %s", t.curToken, expected),
}
}
// tokenizer reads C source code and converts it to Go tokens.
type tokenizer struct {
pos token.Pos
fset *token.FileSet
token token.Token
value string
buf string
curPos, peekPos token.Pos
fset *token.FileSet
curToken, peekToken token.Token
curValue, peekValue string
buf string
}
// newTokenizer initializes a new tokenizer, positioned at the first token in
// the string.
func newTokenizer(start token.Pos, fset *token.FileSet, buf string) *tokenizer {
t := &tokenizer{
pos: start,
fset: fset,
buf: buf,
token: token.ILLEGAL,
peekPos: start,
fset: fset,
buf: buf,
peekToken: token.ILLEGAL,
}
t.Next() // Parse the first token.
// Parse the first two tokens (cur and peek).
t.Next()
t.Next()
return t
}
// Next consumes the next token in the stream. There is no return value, read
// the next token from the pos, token and value properties.
func (t *tokenizer) Next() {
t.pos += token.Pos(len(t.value))
// The previous peek is now the current token.
t.curPos = t.peekPos
t.curToken = t.peekToken
t.curValue = t.peekValue
// Parse the next peek token.
t.peekPos += token.Pos(len(t.curValue))
for {
if len(t.buf) == 0 {
t.token = token.EOF
t.peekToken = token.EOF
return
}
c := t.buf[0]
@@ -118,17 +207,51 @@ func (t *tokenizer) Next() {
// Skip whitespace.
// Based on this source, not sure whether it represents C whitespace:
// https://en.cppreference.com/w/cpp/string/byte/isspace
t.pos++
t.peekPos++
t.buf = t.buf[1:]
case c == '(' || c == ')':
case len(t.buf) >= 2 && (string(t.buf[:2]) == "||" || string(t.buf[:2]) == "&&" || string(t.buf[:2]) == "<<" || string(t.buf[:2]) == ">>"):
// Two-character tokens.
switch c {
case '&':
t.peekToken = token.LAND
case '|':
t.peekToken = token.LOR
case '<':
t.peekToken = token.SHL
case '>':
t.peekToken = token.SHR
default:
panic("unreachable")
}
t.peekValue = t.buf[:2]
t.buf = t.buf[2:]
return
case c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/' || c == '%' || c == '&' || c == '|' || c == '^':
// Single-character tokens.
// TODO: ++ (increment) and -- (decrement) operators.
switch c {
case '(':
t.token = token.LPAREN
t.peekToken = token.LPAREN
case ')':
t.token = token.RPAREN
t.peekToken = token.RPAREN
case '+':
t.peekToken = token.ADD
case '-':
t.peekToken = token.SUB
case '*':
t.peekToken = token.MUL
case '/':
t.peekToken = token.QUO
case '%':
t.peekToken = token.REM
case '&':
t.peekToken = token.AND
case '|':
t.peekToken = token.OR
case '^':
t.peekToken = token.XOR
}
t.value = t.buf[:1]
t.peekValue = t.buf[:1]
t.buf = t.buf[1:]
return
case c >= '0' && c <= '9':
@@ -146,17 +269,17 @@ func (t *tokenizer) Next() {
break
}
}
t.value = t.buf[:tokenLen]
t.peekValue = t.buf[:tokenLen]
t.buf = t.buf[tokenLen:]
if hasDot {
// Integer constants are more complicated than this but this is
// a close approximation.
// https://en.cppreference.com/w/cpp/language/integer_literal
t.token = token.FLOAT
t.value = strings.TrimRight(t.value, "f")
t.peekToken = token.FLOAT
t.peekValue = strings.TrimRight(t.peekValue, "f")
} else {
t.token = token.INT
t.value = strings.TrimRight(t.value, "uUlL")
t.peekToken = token.INT
t.peekValue = strings.TrimRight(t.peekValue, "uUlL")
}
return
case c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c == '_':
@@ -170,9 +293,9 @@ func (t *tokenizer) Next() {
break
}
}
t.value = t.buf[:tokenLen]
t.peekValue = t.buf[:tokenLen]
t.buf = t.buf[tokenLen:]
t.token = token.IDENT
t.peekToken = token.IDENT
return
case c == '"':
// String constant. Find the first '"' character that is not
@@ -188,8 +311,8 @@ func (t *tokenizer) Next() {
escape = c == '\\'
}
}
t.token = token.STRING
t.value = t.buf[:tokenLen]
t.peekToken = token.STRING
t.peekValue = t.buf[:tokenLen]
t.buf = t.buf[tokenLen:]
return
case c == '\'':
@@ -206,12 +329,12 @@ func (t *tokenizer) Next() {
escape = c == '\\'
}
}
t.token = token.CHAR
t.value = t.buf[:tokenLen]
t.peekToken = token.CHAR
t.peekValue = t.buf[:tokenLen]
t.buf = t.buf[tokenLen:]
return
default:
t.token = token.ILLEGAL
t.peekToken = token.ILLEGAL
return
}
}
+27 -2
View File
@@ -18,7 +18,7 @@ func TestParseConst(t *testing.T) {
{`(5)`, `(5)`},
{`(((5)))`, `(5)`},
{`)`, `error: 1:1: unexpected token )`},
{`5)`, `error: 1:2: unexpected token )`},
{`5)`, `error: 1:2: unexpected token ), expected end of expression`},
{" \t)", `error: 1:4: unexpected token )`},
{`5.8f`, `5.8`},
{`foo`, `C.foo`},
@@ -30,7 +30,32 @@ func TestParseConst(t *testing.T) {
{`'a'`, `'a'`},
{`0b10`, `0b10`},
{`0x1234_5678`, `0x1234_5678`},
{`5 5`, `error: 1:3: unexpected token INT`}, // test for a bugfix
{`5 5`, `error: 1:3: unexpected token INT, expected end of expression`}, // test for a bugfix
// Binary operators.
{`5+5`, `5 + 5`},
{`5-5`, `5 - 5`},
{`5*5`, `5 * 5`},
{`5/5`, `5 / 5`},
{`5%5`, `5 % 5`},
{`5&5`, `5 & 5`},
{`5|5`, `5 | 5`},
{`5^5`, `5 ^ 5`},
{`5<<5`, `5 << 5`},
{`5>>5`, `5 >> 5`},
{`5>>5 + 3`, `5 >> (5 + 3)`},
{`5>>5 ^ 3`, `5>>5 ^ 3`},
{`5||5`, `error: 1:2: unexpected token ||, expected end of expression`}, // logical binops aren't supported yet
{`(5/5)`, `(5 / 5)`},
{`1 - 2`, `1 - 2`},
{`1 - 2 + 3`, `1 - 2 + 3`},
{`1 - 2 * 3`, `1 - 2*3`},
{`(1 - 2) * 3`, `(1 - 2) * 3`},
{`1 * 2 - 3`, `1*2 - 3`},
{`1 * (2 - 3)`, `1 * (2 - 3)`},
// Unary operators.
{`-5`, `-5`},
{`-5-2`, `-5 - 2`},
{`5 - - 2`, `5 - -2`},
} {
fset := token.NewFileSet()
startPos := fset.AddFile("", -1, 1000).Pos(0)
+494 -202
View File
@@ -4,7 +4,9 @@ package cgo
// modification. It does not touch the AST itself.
import (
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"fmt"
"go/ast"
"go/scanner"
@@ -13,10 +15,13 @@ import (
"strconv"
"strings"
"unsafe"
"tinygo.org/x/go-llvm"
)
/*
#include <clang-c/Index.h> // if this fails, install libclang-10-dev
#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>
#include <stdint.h>
@@ -40,6 +45,8 @@ typedef struct {
GoCXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu);
unsigned tinygo_clang_visitChildren(GoCXCursor parent, CXCursorVisitor visitor, CXClientData client_data);
CXString tinygo_clang_getCursorSpelling(GoCXCursor c);
CXString tinygo_clang_getCursorPrettyPrinted(GoCXCursor c, CXPrintingPolicy Policy);
CXPrintingPolicy tinygo_clang_getCursorPrintingPolicy(GoCXCursor c);
enum CXCursorKind tinygo_clang_getCursorKind(GoCXCursor c);
CXType tinygo_clang_getCursorType(GoCXCursor c);
GoCXCursor tinygo_clang_getTypeDeclaration(CXType t);
@@ -47,11 +54,13 @@ CXType tinygo_clang_getTypedefDeclUnderlyingType(GoCXCursor c);
CXType tinygo_clang_getCursorResultType(GoCXCursor c);
int tinygo_clang_Cursor_getNumArguments(GoCXCursor c);
GoCXCursor tinygo_clang_Cursor_getArgument(GoCXCursor c, unsigned i);
enum CX_StorageClass tinygo_clang_Cursor_getStorageClass(GoCXCursor c);
CXSourceLocation tinygo_clang_getCursorLocation(GoCXCursor c);
CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c);
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c);
long long tinygo_clang_getEnumConstantDeclValue(GoCXCursor c);
CXType tinygo_clang_getEnumDeclIntegerType(GoCXCursor c);
unsigned tinygo_clang_Cursor_isAnonymous(GoCXCursor c);
unsigned tinygo_clang_Cursor_isBitField(GoCXCursor c);
int tinygo_clang_globals_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
@@ -72,17 +81,28 @@ var diagnosticSeverity = [...]string{
C.CXDiagnostic_Fatal: "fatal",
}
func (p *cgoPackage) parseFragment(fragment string, cflags []string, posFilename string, posLine int) {
// Alias so that cgo.go (which doesn't import Clang related stuff and is in
// theory decoupled from Clang) can also use this type.
type clangCursor = C.GoCXCursor
func init() {
// Check that we haven't messed up LLVM versioning.
// This can happen when llvm_config_*.go files in either this or the
// tinygo.org/x/go-llvm packages is incorrect. It should not ever happen
// with byollvm.
if C.LLVM_VERSION_STRING != llvm.Version {
panic("incorrect build: using LLVM version " + llvm.Version + " in the tinygo.org/x/llvm package, and version " + C.LLVM_VERSION_STRING + " in the ./cgo package")
}
}
func (f *cgoFile) readNames(fragment string, cflags []string, filename string, callback func(map[string]clangCursor)) {
index := C.clang_createIndex(0, 0)
defer C.clang_disposeIndex(index)
// pretend to be a .c file
filenameC := C.CString(posFilename + "!cgo.c")
filenameC := C.CString(filename + "!cgo.c")
defer C.free(unsafe.Pointer(filenameC))
// fix up error locations
fragment = fmt.Sprintf("# %d %#v\n", posLine+1, posFilename) + fragment
fragmentC := C.CString(fragment)
defer C.free(unsafe.Pointer(fragmentC))
@@ -122,8 +142,8 @@ func (p *cgoPackage) parseFragment(fragment string, cflags []string, posFilename
spelling := getString(C.clang_getDiagnosticSpelling(diagnostic))
severity := diagnosticSeverity[C.clang_getDiagnosticSeverity(diagnostic)]
location := C.clang_getDiagnosticLocation(diagnostic)
pos := p.getClangLocationPosition(location, unit)
p.addError(pos, severity+": "+spelling)
pos := f.getClangLocationPosition(location, unit)
f.addError(pos, severity+": "+spelling)
}
for i := 0; i < numDiagnostics; i++ {
diagnostic := C.clang_getDiagnostic(unit, C.uint(i))
@@ -138,7 +158,7 @@ func (p *cgoPackage) parseFragment(fragment string, cflags []string, posFilename
}
// Extract information required by CGo.
ref := storedRefs.Put(p)
ref := storedRefs.Put(f)
defer storedRefs.Remove(ref)
cursor := C.tinygo_clang_getTranslationUnitCursor(unit)
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_globals_visitor), C.CXClientData(ref))
@@ -158,35 +178,88 @@ func (p *cgoPackage) parseFragment(fragment string, cflags []string, posFilename
data := (*[1 << 24]byte)(unsafe.Pointer(rawData))[:size]
// Hash the contents if it isn't hashed yet.
if _, ok := p.visitedFiles[path]; !ok {
if _, ok := f.visitedFiles[path]; !ok {
// already stored
sum := sha512.Sum512_224(data)
p.visitedFiles[path] = sum[:]
f.visitedFiles[path] = sum[:]
}
}
inclusionCallbackRef := storedRefs.Put(inclusionCallback)
defer storedRefs.Remove(inclusionCallbackRef)
C.clang_getInclusions(unit, C.CXInclusionVisitor(C.tinygo_clang_inclusion_visitor), C.CXClientData(inclusionCallbackRef))
// Do all the C AST operations inside a callback. This makes sure that
// libclang related memory is only freed after it is not necessary anymore.
callback(f.names)
}
//export tinygo_clang_globals_visitor
func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
p := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoPackage)
// Convert the AST node under the given Clang cursor to a Go AST node and return
// it.
func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
kind := C.tinygo_clang_getCursorKind(c)
pos := p.getCursorPosition(c)
pos := f.getCursorPosition(c)
switch kind {
case C.CXCursor_FunctionDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
if _, required := p.missingSymbols[name]; !required {
return C.CXChildVisit_Continue
}
cursorType := C.tinygo_clang_getCursorType(c)
numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c))
fn := &functionInfo{
pos: pos,
variadic: C.clang_isFunctionTypeVariadic(cursorType) != 0,
obj := &ast.Object{
Kind: ast.Fun,
Name: "C." + name,
}
exportName := name
localName := name
var stringSignature string
if C.tinygo_clang_Cursor_getStorageClass(c) == C.CX_SC_Static {
// A static function is assigned a globally unique symbol name based
// on the file path (like _Cgo_static_2d09198adbf58f4f4655_foo) and
// has a different Go name in the form of C.foo!symbols.go instead
// of just C.foo.
path := f.importPath + "/" + filepath.Base(f.fset.File(f.file.Pos()).Name())
staticIDBuf := sha256.Sum256([]byte(path))
staticID := hex.EncodeToString(staticIDBuf[:10])
exportName = "_Cgo_static_" + staticID + "_" + name
localName = name + "!" + filepath.Base(path)
// Create a signature. This is necessary for MacOS to forward the
// call, because MacOS doesn't support aliases like ELF and PE do.
// (There is N_INDR but __attribute__((alias("..."))) doesn't work).
policy := C.tinygo_clang_getCursorPrintingPolicy(c)
defer C.clang_PrintingPolicy_dispose(policy)
C.clang_PrintingPolicy_setProperty(policy, C.CXPrintingPolicy_TerseOutput, 1)
stringSignature = getString(C.tinygo_clang_getCursorPrettyPrinted(c, policy))
stringSignature = strings.Replace(stringSignature, " "+name+"(", " "+exportName+"(", 1)
stringSignature = strings.TrimPrefix(stringSignature, "static ")
}
args := make([]*ast.Field, numArgs)
decl := &ast.FuncDecl{
Doc: &ast.CommentGroup{
List: []*ast.Comment{
{
Slash: pos - 1,
Text: "//export " + exportName,
},
},
},
Name: &ast.Ident{
NamePos: pos,
Name: "C." + localName,
Obj: obj,
},
Type: &ast.FuncType{
Func: pos,
Params: &ast.FieldList{
Opening: pos,
List: args,
Closing: pos,
},
},
}
if C.clang_isFunctionTypeVariadic(cursorType) != 0 {
decl.Doc.List = append(decl.Doc.List, &ast.Comment{
Slash: pos - 1,
Text: "//go:variadic",
})
}
p.functions[name] = fn
for i := 0; i < numArgs; i++ {
arg := C.tinygo_clang_Cursor_getArgument(c, C.uint(i))
argName := getString(C.tinygo_clang_getCursorSpelling(arg))
@@ -194,50 +267,108 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
if argName == "" {
argName = "$" + strconv.Itoa(i)
}
fn.args = append(fn.args, paramInfo{
name: argName,
typeExpr: p.makeASTType(argType, pos),
})
args[i] = &ast.Field{
Names: []*ast.Ident{
{
NamePos: pos,
Name: argName,
Obj: &ast.Object{
Kind: ast.Var,
Name: argName,
Decl: decl,
},
},
},
Type: f.makeDecayingASTType(argType, pos),
}
}
resultType := C.tinygo_clang_getCursorResultType(c)
if resultType.kind != C.CXType_Void {
fn.results = &ast.FieldList{
decl.Type.Results = &ast.FieldList{
List: []*ast.Field{
&ast.Field{
Type: p.makeASTType(resultType, pos),
{
Type: f.makeASTType(resultType, pos),
},
},
}
}
case C.CXCursor_StructDecl:
typ := C.tinygo_clang_getCursorType(c)
name := getString(C.tinygo_clang_getCursorSpelling(c))
if _, required := p.missingSymbols["struct_"+name]; !required {
return C.CXChildVisit_Continue
obj.Decl = decl
return decl, stringSignature
case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
typ := f.makeASTRecordType(c, pos)
typeName := "C." + name
typeExpr := typ.typeExpr
if typ.unionSize != 0 {
// Convert to a single-field struct type.
typeExpr = f.makeUnionField(typ)
}
p.makeASTType(typ, pos)
obj := &ast.Object{
Kind: ast.Typ,
Name: typeName,
}
typeSpec := &ast.TypeSpec{
Name: &ast.Ident{
NamePos: typ.pos,
Name: typeName,
Obj: obj,
},
Type: typeExpr,
}
obj.Decl = typeSpec
return typeSpec, typ
case C.CXCursor_TypedefDecl:
typedefType := C.tinygo_clang_getCursorType(c)
name := getString(C.clang_getTypedefName(typedefType))
if _, required := p.missingSymbols[name]; !required {
return C.CXChildVisit_Continue
typeName := "C." + name
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c)
obj := &ast.Object{
Kind: ast.Typ,
Name: typeName,
}
p.makeASTType(typedefType, pos)
typeSpec := &ast.TypeSpec{
Name: &ast.Ident{
NamePos: pos,
Name: typeName,
Obj: obj,
},
Type: f.makeASTType(underlyingType, pos),
}
if underlyingType.kind != C.CXType_Enum {
typeSpec.Assign = pos
}
obj.Decl = typeSpec
return typeSpec, nil
case C.CXCursor_VarDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
if _, required := p.missingSymbols[name]; !required {
return C.CXChildVisit_Continue
}
cursorType := C.tinygo_clang_getCursorType(c)
p.globals[name] = globalInfo{
typeExpr: p.makeASTType(cursorType, pos),
pos: pos,
typeExpr := f.makeASTType(cursorType, pos)
gen := &ast.GenDecl{
TokPos: pos,
Tok: token.VAR,
Lparen: token.NoPos,
Rparen: token.NoPos,
Doc: &ast.CommentGroup{
List: []*ast.Comment{
{
Slash: pos - 1,
Text: "//go:extern " + name,
},
},
},
}
obj := &ast.Object{
Kind: ast.Var,
Name: "C." + name,
}
valueSpec := &ast.ValueSpec{
Names: []*ast.Ident{{
NamePos: pos,
Name: "C." + name,
Obj: obj,
}},
Type: typeExpr,
}
obj.Decl = valueSpec
gen.Specs = append(gen.Specs, valueSpec)
return gen, nil
case C.CXCursor_MacroDefinition:
name := getString(C.tinygo_clang_getCursorSpelling(c))
if _, required := p.missingSymbols[name]; !required {
return C.CXChildVisit_Continue
}
sourceRange := C.tinygo_clang_getCursorExtent(c)
start := C.clang_getRangeStart(sourceRange)
end := C.clang_getRangeEnd(sourceRange)
@@ -245,17 +376,17 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
var startOffset, endOffset C.unsigned
C.clang_getExpansionLocation(start, &file, nil, nil, &startOffset)
if file == nil {
p.addError(pos, "internal error: could not find file where macro is defined")
break
f.addError(pos, "internal error: could not find file where macro is defined")
return nil, nil
}
C.clang_getExpansionLocation(end, &endFile, nil, nil, &endOffset)
if file != endFile {
p.addError(pos, "internal error: expected start and end location of a macro to be in the same file")
break
f.addError(pos, "internal error: expected start and end location of a macro to be in the same file")
return nil, nil
}
if startOffset > endOffset {
p.addError(pos, "internal error: start offset of macro is after end offset")
break
f.addError(pos, "internal error: start offset of macro is after end offset")
return nil, nil
}
// read file contents and extract the relevant byte range
@@ -263,31 +394,94 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
var size C.size_t
sourcePtr := C.clang_getFileContents(tu, file, &size)
if endOffset >= C.uint(size) {
p.addError(pos, "internal error: end offset of macro lies after end of file")
break
f.addError(pos, "internal error: end offset of macro lies after end of file")
return nil, nil
}
source := string(((*[1 << 28]byte)(unsafe.Pointer(sourcePtr)))[startOffset:endOffset:endOffset])
if !strings.HasPrefix(source, name) {
p.addError(pos, fmt.Sprintf("internal error: expected macro value to start with %#v, got %#v", name, source))
break
f.addError(pos, fmt.Sprintf("internal error: expected macro value to start with %#v, got %#v", name, source))
return nil, nil
}
value := source[len(name):]
// Try to convert this #define into a Go constant expression.
expr, scannerError := parseConst(pos+token.Pos(len(name)), p.fset, value)
expr, scannerError := parseConst(pos+token.Pos(len(name)), f.fset, value)
if scannerError != nil {
p.errors = append(p.errors, *scannerError)
f.errors = append(f.errors, *scannerError)
return nil, nil
}
if expr != nil {
// Parsing was successful.
p.constants[name] = constantInfo{expr, pos}
gen := &ast.GenDecl{
TokPos: token.NoPos,
Tok: token.CONST,
Lparen: token.NoPos,
Rparen: token.NoPos,
}
obj := &ast.Object{
Kind: ast.Con,
Name: "C." + name,
}
valueSpec := &ast.ValueSpec{
Names: []*ast.Ident{{
NamePos: pos,
Name: "C." + name,
Obj: obj,
}},
Values: []ast.Expr{expr},
}
obj.Decl = valueSpec
gen.Specs = append(gen.Specs, valueSpec)
return gen, nil
case C.CXCursor_EnumDecl:
// Visit all enums, because the fields may be used even when the enum
// type itself is not.
typ := C.tinygo_clang_getCursorType(c)
p.makeASTType(typ, pos)
obj := &ast.Object{
Kind: ast.Typ,
Name: "C." + name,
}
underlying := C.tinygo_clang_getEnumDeclIntegerType(c)
// TODO: gc's CGo implementation uses types such as `uint32` for enums
// instead of types such as C.int, which are used here.
typeSpec := &ast.TypeSpec{
Name: &ast.Ident{
NamePos: pos,
Name: "C." + name,
Obj: obj,
},
Assign: pos,
Type: f.makeASTType(underlying, pos),
}
obj.Decl = typeSpec
return typeSpec, nil
case C.CXCursor_EnumConstantDecl:
value := C.tinygo_clang_getEnumConstantDeclValue(c)
expr := &ast.BasicLit{
ValuePos: pos,
Kind: token.INT,
Value: strconv.FormatInt(int64(value), 10),
}
gen := &ast.GenDecl{
TokPos: token.NoPos,
Tok: token.CONST,
Lparen: token.NoPos,
Rparen: token.NoPos,
}
obj := &ast.Object{
Kind: ast.Con,
Name: "C." + name,
}
valueSpec := &ast.ValueSpec{
Names: []*ast.Ident{{
NamePos: pos,
Name: "C." + name,
Obj: obj,
}},
Values: []ast.Expr{expr},
}
obj.Decl = valueSpec
gen.Specs = append(gen.Specs, valueSpec)
return gen, nil
default:
f.addError(pos, fmt.Sprintf("internal error: unknown cursor type: %d", kind))
return nil, nil
}
return C.CXChildVisit_Continue
}
func getString(clangString C.CXString) (s string) {
@@ -297,6 +491,69 @@ func getString(clangString C.CXString) (s string) {
return
}
//export tinygo_clang_globals_visitor
func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
f := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoFile)
switch C.tinygo_clang_getCursorKind(c) {
case C.CXCursor_FunctionDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
f.names[name] = c
case C.CXCursor_StructDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
if name != "" {
f.names["struct_"+name] = c
}
case C.CXCursor_UnionDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
if name != "" {
f.names["union_"+name] = c
}
case C.CXCursor_TypedefDecl:
typedefType := C.tinygo_clang_getCursorType(c)
name := getString(C.clang_getTypedefName(typedefType))
f.names[name] = c
case C.CXCursor_VarDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
f.names[name] = c
case C.CXCursor_MacroDefinition:
name := getString(C.tinygo_clang_getCursorSpelling(c))
f.names[name] = c
case C.CXCursor_EnumDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
if name != "" {
// Named enum, which can be referenced from Go using C.enum_foo.
f.names["enum_"+name] = c
}
// The enum fields are in global scope, so recurse to visit them.
return C.CXChildVisit_Recurse
case C.CXCursor_EnumConstantDecl:
// We arrive here because of the "Recurse" above.
name := getString(C.tinygo_clang_getCursorSpelling(c))
f.names[name] = c
}
return C.CXChildVisit_Continue
}
// Get the precise location in the source code. Used for uniquely identifying
// source locations.
func (f *cgoFile) getUniqueLocationID(pos token.Pos, cursor C.GoCXCursor) interface{} {
clangLocation := C.tinygo_clang_getCursorLocation(cursor)
var file C.CXFile
var line C.unsigned
var column C.unsigned
C.clang_getFileLocation(clangLocation, &file, &line, &column, nil)
location := token.Position{
Filename: getString(C.clang_getFileName(file)),
Line: int(line),
Column: int(column),
}
if location.Filename == "" || location.Line == 0 {
// Not sure when this would happen, but protect from it anyway.
f.addError(pos, "could not find file/line information")
}
return location
}
// getCursorPosition returns a usable token.Pos from a libclang cursor.
func (p *cgoPackage) getCursorPosition(cursor C.GoCXCursor) token.Pos {
return p.getClangLocationPosition(C.tinygo_clang_getCursorLocation(cursor), C.tinygo_clang_Cursor_getTranslationUnit(cursor))
@@ -332,6 +589,13 @@ func (p *cgoPackage) getClangLocationPosition(location C.CXSourceLocation, tu C.
f := p.fset.AddFile(filename, -1, int(size))
f.SetLines(lines)
p.tokenFiles[filename] = f
// Add dummy file AST, to satisfy the type checker.
astFile := &ast.File{
Package: f.Pos(0),
Name: ast.NewIdent(p.packageName),
}
setASTFileFields(astFile, f.Pos(0), f.Pos(int(size)))
p.cgoFiles = append(p.cgoFiles, astFile)
}
positionFile := p.tokenFiles[filename]
@@ -380,7 +644,7 @@ func (p *cgoPackage) addErrorAfter(pos token.Pos, after, msg string) {
func (p *cgoPackage) addErrorAt(position token.Position, msg string) {
if filepath.IsAbs(position.Filename) {
// Relative paths for readability, like other Go parser errors.
relpath, err := filepath.Rel(p.dir, position.Filename)
relpath, err := filepath.Rel(p.currentDir, position.Filename)
if err == nil {
position.Filename = relpath
}
@@ -391,9 +655,55 @@ func (p *cgoPackage) addErrorAt(position token.Position, msg string) {
})
}
// makeDecayingASTType does the same as makeASTType but takes care of decaying
// types (arrays in function parameters, etc). It is otherwise identical to
// makeASTType.
func (f *cgoFile) makeDecayingASTType(typ C.CXType, pos token.Pos) ast.Expr {
// Strip typedefs, if any.
underlyingType := typ
if underlyingType.kind == C.CXType_Elaborated {
// Starting with LLVM 16, the elaborated type is used for more types.
// According to the Clang documentation, the elaborated type has no
// semantic meaning so can be stripped (it is used to better convey type
// name information).
// Source:
// https://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html#details
// > The type itself is always "sugar", used to express what was written
// > in the source code but containing no additional semantic information.
underlyingType = C.clang_Type_getNamedType(underlyingType)
}
if underlyingType.kind == C.CXType_Typedef {
c := C.tinygo_clang_getTypeDeclaration(underlyingType)
underlyingType = C.tinygo_clang_getTypedefDeclUnderlyingType(c)
// TODO: support a chain of typedefs. At the moment, it seems to get
// stuck in an endless loop when trying to get to the most underlying
// type.
}
// Check for decaying type. An example would be an array type in a
// parameter. This declaration:
// void foo(char buf[6]);
// is the same as this one:
// void foo(char *buf);
// But this one:
// void bar(char buf[6][4]);
// equals this:
// void bar(char *buf[4]);
// so not all array dimensions should be stripped, just the first one.
// TODO: there are more kinds of decaying types.
if underlyingType.kind == C.CXType_ConstantArray {
// Apply type decaying.
pointeeType := C.clang_getElementType(underlyingType)
return &ast.StarExpr{
Star: pos,
X: f.makeASTType(pointeeType, pos),
}
}
return f.makeASTType(typ, pos)
}
// makeASTType return the ast.Expr for the given libclang type. In other words,
// it converts a libclang type to a type in the Go AST.
func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
var typeName string
switch typ.kind {
case C.CXType_Char_S, C.CXType_Char_U:
@@ -454,7 +764,7 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
}
return &ast.StarExpr{
Star: pos,
X: p.makeASTType(pointeeType, pos),
X: f.makeASTType(pointeeType, pos),
}
case C.CXType_ConstantArray:
return &ast.ArrayType{
@@ -464,7 +774,7 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
Kind: token.INT,
Value: strconv.FormatInt(int64(C.clang_getArraySize(typ)), 10),
},
Elt: p.makeASTType(C.clang_getElementType(typ), pos),
Elt: f.makeASTType(C.clang_getElementType(typ), pos),
}
case C.CXType_FunctionProto:
// Be compatible with gc, which uses the *[0]byte type for function
@@ -485,71 +795,23 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
}
case C.CXType_Typedef:
name := getString(C.clang_getTypedefName(typ))
if _, ok := p.typedefs[name]; !ok {
p.typedefs[name] = nil // don't recurse
c := C.tinygo_clang_getTypeDeclaration(typ)
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c)
expr := p.makeASTType(underlyingType, pos)
if strings.HasPrefix(name, "_Cgo_") {
expr := expr.(*ast.Ident)
typeSize := C.clang_Type_getSizeOf(underlyingType)
switch expr.Name {
case "C.char":
if typeSize != 1 {
// This happens for some very special purpose architectures
// (DSPs etc.) that are not currently targeted.
// https://www.embecosm.com/2017/04/18/non-8-bit-char-support-in-clang-and-llvm/
p.addError(pos, fmt.Sprintf("unknown char width: %d", typeSize))
}
switch underlyingType.kind {
case C.CXType_Char_S:
expr.Name = "int8"
case C.CXType_Char_U:
expr.Name = "uint8"
}
case "C.schar", "C.short", "C.int", "C.long", "C.longlong":
switch typeSize {
case 1:
expr.Name = "int8"
case 2:
expr.Name = "int16"
case 4:
expr.Name = "int32"
case 8:
expr.Name = "int64"
}
case "C.uchar", "C.ushort", "C.uint", "C.ulong", "C.ulonglong":
switch typeSize {
case 1:
expr.Name = "uint8"
case 2:
expr.Name = "uint16"
case 4:
expr.Name = "uint32"
case 8:
expr.Name = "uint64"
}
}
}
p.typedefs[name] = &typedefInfo{
typeExpr: expr,
pos: pos,
}
}
c := C.tinygo_clang_getTypeDeclaration(typ)
return &ast.Ident{
NamePos: pos,
Name: "C." + name,
Name: f.getASTDeclName(name, c, false),
}
case C.CXType_Elaborated:
underlying := C.clang_Type_getNamedType(typ)
switch underlying.kind {
case C.CXType_Record:
return p.makeASTType(underlying, pos)
return f.makeASTType(underlying, pos)
case C.CXType_Enum:
return p.makeASTType(underlying, pos)
return f.makeASTType(underlying, pos)
case C.CXType_Typedef:
return f.makeASTType(underlying, pos)
default:
typeKindSpelling := getString(C.clang_getTypeKindSpelling(underlying.kind))
p.addError(pos, fmt.Sprintf("unknown elaborated type (libclang type kind %s)", typeKindSpelling))
f.addError(pos, fmt.Sprintf("unknown elaborated type (libclang type kind %s)", typeKindSpelling))
typeName = "<unknown>"
}
case C.CXType_Record:
@@ -565,65 +827,37 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
// makeASTRecordType will create an appropriate error.
cgoRecordPrefix = "record_"
}
if name == "" {
if name == "" || C.tinygo_clang_Cursor_isAnonymous(cursor) != 0 {
// Anonymous record, probably inside a typedef.
typeInfo := p.makeASTRecordType(cursor, pos)
if typeInfo.bitfields != nil || typeInfo.unionSize != 0 {
// This record is a union or is a struct with bitfields, so we
// have to declare it as a named type (for getters/setters to
// work).
p.anonStructNum++
cgoName := cgoRecordPrefix + strconv.Itoa(p.anonStructNum)
p.elaboratedTypes[cgoName] = typeInfo
return &ast.Ident{
NamePos: pos,
Name: "C." + cgoName,
}
}
return typeInfo.typeExpr
location := f.getUniqueLocationID(pos, cursor)
name = f.getUnnamedDeclName("_Ctype_"+cgoRecordPrefix+"__", location)
} else {
cgoName := cgoRecordPrefix + name
if _, ok := p.elaboratedTypes[cgoName]; !ok {
p.elaboratedTypes[cgoName] = nil // predeclare (to avoid endless recursion)
p.elaboratedTypes[cgoName] = p.makeASTRecordType(cursor, pos)
}
return &ast.Ident{
NamePos: pos,
Name: "C." + cgoName,
}
name = cgoRecordPrefix + name
}
return &ast.Ident{
NamePos: pos,
Name: f.getASTDeclName(name, cursor, false),
}
case C.CXType_Enum:
cursor := C.tinygo_clang_getTypeDeclaration(typ)
name := getString(C.tinygo_clang_getCursorSpelling(cursor))
underlying := C.tinygo_clang_getEnumDeclIntegerType(cursor)
if name == "" {
// anonymous enum
ref := storedRefs.Put(p)
defer storedRefs.Remove(ref)
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_enum_visitor), C.CXClientData(ref))
return p.makeASTType(underlying, pos)
// Anonymous enum, probably inside a typedef.
location := f.getUniqueLocationID(pos, cursor)
name = f.getUnnamedDeclName("_Ctype_enum___", location)
} else {
// named enum
if _, ok := p.enums[name]; !ok {
ref := storedRefs.Put(p)
defer storedRefs.Remove(ref)
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_enum_visitor), C.CXClientData(ref))
p.enums[name] = enumInfo{
typeExpr: p.makeASTType(underlying, pos),
pos: pos,
}
}
return &ast.Ident{
NamePos: pos,
Name: "C.enum_" + name,
}
name = "enum_" + name
}
return &ast.Ident{
NamePos: pos,
Name: f.getASTDeclName(name, cursor, false),
}
}
if typeName == "" {
// Report this as an error.
typeSpelling := getString(C.clang_getTypeSpelling(typ))
typeKindSpelling := getString(C.clang_getTypeKindSpelling(typ.kind))
p.addError(pos, fmt.Sprintf("unknown C type: %v (libclang type kind %s)", typeSpelling, typeKindSpelling))
f.addError(pos, fmt.Sprintf("unknown C type: %v (libclang type kind %s)", typeSpelling, typeKindSpelling))
typeName = "C.<unknown>"
}
return &ast.Ident{
@@ -632,9 +866,80 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
}
}
// getIntegerType returns an AST node that defines types such as C.int.
func (p *cgoPackage) getIntegerType(name string, cursor clangCursor) *ast.TypeSpec {
pos := p.getCursorPosition(cursor)
// Find a Go type that matches the size and signedness of the given C type.
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(cursor)
var goName string
typeSize := C.clang_Type_getSizeOf(underlyingType)
switch name {
case "C.char":
if typeSize != 1 {
// This happens for some very special purpose architectures
// (DSPs etc.) that are not currently targeted.
// https://www.embecosm.com/2017/04/18/non-8-bit-char-support-in-clang-and-llvm/
p.addError(pos, fmt.Sprintf("unknown char width: %d", typeSize))
}
switch underlyingType.kind {
case C.CXType_Char_S:
goName = "int8"
case C.CXType_Char_U:
goName = "uint8"
}
case "C.schar", "C.short", "C.int", "C.long", "C.longlong":
switch typeSize {
case 1:
goName = "int8"
case 2:
goName = "int16"
case 4:
goName = "int32"
case 8:
goName = "int64"
}
case "C.uchar", "C.ushort", "C.uint", "C.ulong", "C.ulonglong":
switch typeSize {
case 1:
goName = "uint8"
case 2:
goName = "uint16"
case 4:
goName = "uint32"
case 8:
goName = "uint64"
}
}
if goName == "" { // should not happen
p.addError(pos, "internal error: did not find Go type for C type "+name)
goName = "int"
}
// Construct an *ast.TypeSpec for this type.
obj := &ast.Object{
Kind: ast.Typ,
Name: name,
}
spec := &ast.TypeSpec{
Name: &ast.Ident{
NamePos: pos,
Name: name,
Obj: obj,
},
Type: &ast.Ident{
NamePos: pos,
Name: goName,
},
}
obj.Decl = spec
return spec
}
// makeASTRecordType parses a C record (struct or union) and translates it into
// a Go struct type.
func (p *cgoPackage) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elaboratedTypeInfo {
func (f *cgoFile) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elaboratedTypeInfo {
fieldList := &ast.FieldList{
Opening: pos,
Closing: pos,
@@ -644,11 +949,11 @@ func (p *cgoPackage) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elab
bitfieldNum := 0
ref := storedRefs.Put(struct {
fieldList *ast.FieldList
pkg *cgoPackage
file *cgoFile
inBitfield *bool
bitfieldNum *int
bitfieldList *[]bitfieldInfo
}{fieldList, p, &inBitfield, &bitfieldNum, &bitfieldList})
}{fieldList, f, &inBitfield, &bitfieldNum, &bitfieldList})
defer storedRefs.Remove(ref)
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_struct_visitor), C.CXClientData(ref))
renameFieldKeywords(fieldList)
@@ -677,13 +982,13 @@ func (p *cgoPackage) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elab
}
if bitfieldList != nil {
// This is valid C... but please don't do this.
p.addError(pos, "bitfield in a union is not supported")
f.addError(pos, "bitfield in a union is not supported")
}
typ := C.tinygo_clang_getCursorType(cursor)
alignInBytes := int64(C.clang_Type_getAlignOf(typ))
sizeInBytes := int64(C.clang_Type_getSizeOf(typ))
if sizeInBytes == 0 {
p.addError(pos, "zero-length union is not supported")
f.addError(pos, "zero-length union is not supported")
}
typeInfo.unionSize = sizeInBytes
typeInfo.unionAlign = alignInBytes
@@ -691,7 +996,7 @@ func (p *cgoPackage) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elab
default:
cursorKind := C.tinygo_clang_getCursorKind(cursor)
cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind))
p.addError(pos, fmt.Sprintf("expected StructDecl or UnionDecl, not %s", cursorKindSpelling))
f.addError(pos, fmt.Sprintf("expected StructDecl or UnionDecl, not %s", cursorKindSpelling))
return &elaboratedTypeInfo{
typeExpr: &ast.StructType{
Struct: pos,
@@ -705,17 +1010,17 @@ func (p *cgoPackage) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elab
func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
passed := storedRefs.Get(unsafe.Pointer(client_data)).(struct {
fieldList *ast.FieldList
pkg *cgoPackage
file *cgoFile
inBitfield *bool
bitfieldNum *int
bitfieldList *[]bitfieldInfo
})
fieldList := passed.fieldList
p := passed.pkg
f := passed.file
inBitfield := passed.inBitfield
bitfieldNum := passed.bitfieldNum
bitfieldList := passed.bitfieldList
pos := p.getCursorPosition(c)
pos := f.getCursorPosition(c)
switch cursorKind := C.tinygo_clang_getCursorKind(c); cursorKind {
case C.CXCursor_FieldDecl:
// Expected. This is a regular field.
@@ -724,7 +1029,7 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
return C.CXChildVisit_Continue
default:
cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind))
p.addError(pos, fmt.Sprintf("expected FieldDecl in struct or union, not %s", cursorKindSpelling))
f.addError(pos, fmt.Sprintf("expected FieldDecl in struct or union, not %s", cursorKindSpelling))
return C.CXChildVisit_Continue
}
name := getString(C.tinygo_clang_getCursorSpelling(c))
@@ -735,14 +1040,14 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
}
typ := C.tinygo_clang_getCursorType(c)
field := &ast.Field{
Type: p.makeASTType(typ, p.getCursorPosition(c)),
Type: f.makeASTType(typ, f.getCursorPosition(c)),
}
offsetof := int64(C.clang_Type_getOffsetOf(C.tinygo_clang_getCursorType(parent), C.CString(name)))
alignOf := int64(C.clang_Type_getAlignOf(typ) * 8)
bitfieldOffset := offsetof % alignOf
if bitfieldOffset != 0 {
if C.tinygo_clang_Cursor_isBitField(c) != 1 {
p.addError(pos, "expected a bitfield")
f.addError(pos, "expected a bitfield")
return C.CXChildVisit_Continue
}
if !*inBitfield {
@@ -775,7 +1080,7 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
}
*inBitfield = false
field.Names = []*ast.Ident{
&ast.Ident{
{
NamePos: pos,
Name: name,
Obj: &ast.Object{
@@ -789,19 +1094,6 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
return C.CXChildVisit_Continue
}
//export tinygo_clang_enum_visitor
func tinygo_clang_enum_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
p := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoPackage)
name := getString(C.tinygo_clang_getCursorSpelling(c))
pos := p.getCursorPosition(c)
value := C.tinygo_clang_getEnumConstantDeclValue(c)
p.constants[name] = constantInfo{
expr: &ast.BasicLit{pos, token.INT, strconv.FormatInt(int64(value), 10)},
pos: pos,
}
return C.CXChildVisit_Continue
}
//export tinygo_clang_inclusion_visitor
func tinygo_clang_inclusion_visitor(includedFile C.CXFile, inclusionStack *C.CXSourceLocation, includeLen C.unsigned, clientData C.CXClientData) {
callback := storedRefs.Get(unsafe.Pointer(clientData)).(func(C.CXFile))
-14
View File
@@ -1,14 +0,0 @@
// +build !byollvm
// +build !llvm10
package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-11/include
#cgo darwin CFLAGS: -I/usr/local/opt/llvm@11/include
#cgo freebsd CFLAGS: -I/usr/local/llvm11/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-11/lib -lclang
#cgo darwin LDFLAGS: -L/usr/local/opt/llvm@11/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm11/lib -lclang
*/
import "C"
-14
View File
@@ -1,14 +0,0 @@
// +build !byollvm
// +build llvm10
package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-10/include
#cgo darwin CFLAGS: -I/usr/local/opt/llvm@10/include
#cgo freebsd CFLAGS: -I/usr/local/llvm10/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-10/lib -lclang
#cgo darwin LDFLAGS: -L/usr/local/opt/llvm@10/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm10/lib -lclang
*/
import "C"
+15
View File
@@ -0,0 +1,15 @@
//go:build !byollvm && llvm15
package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-15/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@15/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@15/include
#cgo freebsd CFLAGS: -I/usr/local/llvm15/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-15/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@15/lib -lclang
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@15/lib -lclang
#cgo freebsd LDFLAGS: -L/usr/local/llvm15/lib -lclang
*/
import "C"
+21
View File
@@ -0,0 +1,21 @@
//go:build !byollvm && llvm16
package cgo
// As of 2023-05-05, there is a packaging issue with LLVM 16 on Debian:
// https://github.com/llvm/llvm-project/issues/62199
// A workaround is to fix this locally, using something like this:
//
// ln -sf ../../x86_64-linux-gnu/libclang-16.so.1 /usr/lib/llvm-16/lib/libclang.so
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-16/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@16/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@16/include
#cgo freebsd CFLAGS: -I/usr/local/llvm16/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-16/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@16/lib -lclang
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@16/lib -lclang
#cgo freebsd LDFLAGS: -L/usr/local/llvm16/lib -lclang
*/
import "C"
+15
View File
@@ -0,0 +1,15 @@
//go:build !byollvm && llvm17
package cgo
/*
#cgo linux CFLAGS: -I/usr/include/llvm-17 -I/usr/include/llvm-c-17 -I/usr/lib/llvm-17/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@17/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@17/include
#cgo freebsd CFLAGS: -I/usr/local/llvm17/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-17/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@17/lib -lclang
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@17/lib -lclang
#cgo freebsd LDFLAGS: -L/usr/local/llvm17/lib -lclang
*/
import "C"
+15
View File
@@ -0,0 +1,15 @@
//go:build !byollvm && !llvm15 && !llvm16 && !llvm17
package cgo
/*
#cgo linux CFLAGS: -I/usr/include/llvm-18 -I/usr/include/llvm-c-18 -I/usr/lib/llvm-18/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@18/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@18/include
#cgo freebsd CFLAGS: -I/usr/local/llvm18/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-18/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@18/lib -lclang
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@18/lib -lclang
#cgo freebsd LDFLAGS: -L/usr/local/llvm18/lib -lclang
*/
import "C"
+18 -2
View File
@@ -3,7 +3,7 @@
// are slightly different from the ones defined in libclang.go, but they
// should be ABI compatible.
#include <clang-c/Index.h> // if this fails, install libclang-10-dev
#include <clang-c/Index.h> // If this fails, libclang headers aren't available. Please take a look here: https://tinygo.org/docs/guides/build/
CXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu) {
return clang_getTranslationUnitCursor(tu);
@@ -17,6 +17,14 @@ CXString tinygo_clang_getCursorSpelling(CXCursor c) {
return clang_getCursorSpelling(c);
}
CXString tinygo_clang_getCursorPrettyPrinted(CXCursor c, CXPrintingPolicy policy) {
return clang_getCursorPrettyPrinted(c, policy);
}
CXPrintingPolicy tinygo_clang_getCursorPrintingPolicy(CXCursor c) {
return clang_getCursorPrintingPolicy(c);
}
enum CXCursorKind tinygo_clang_getCursorKind(CXCursor c) {
return clang_getCursorKind(c);
}
@@ -45,6 +53,10 @@ CXCursor tinygo_clang_Cursor_getArgument(CXCursor c, unsigned i) {
return clang_Cursor_getArgument(c, i);
}
enum CX_StorageClass tinygo_clang_Cursor_getStorageClass(CXCursor c) {
return clang_Cursor_getStorageClass(c);
}
CXSourceLocation tinygo_clang_getCursorLocation(CXCursor c) {
return clang_getCursorLocation(c);
}
@@ -65,6 +77,10 @@ CXType tinygo_clang_getEnumDeclIntegerType(CXCursor c) {
return clang_getEnumDeclIntegerType(c);
}
unsigned tinygo_clang_Cursor_isAnonymous(CXCursor c) {
return clang_Cursor_isAnonymous(c);
}
unsigned tinygo_clang_Cursor_isBitField(CXCursor c) {
return clang_Cursor_isBitField(c);
}
}
+1
View File
@@ -142,6 +142,7 @@ var validLinkerFlags = []*regexp.Regexp{
re(`-L([^@\-].*)`),
re(`-O`),
re(`-O([^@\-].*)`),
re(`--export=([^@\-].*)`),
re(`-f(no-)?(pic|PIC|pie|PIE)`),
re(`-f(no-)?openmp(-simd)?`),
re(`-fsanitize=([^@\-].*)`),
+1
View File
@@ -108,6 +108,7 @@ var goodLinkerFlags = [][]string{
{"-Fbar"},
{"-lbar"},
{"-Lbar"},
{"--export=my_symbol"},
{"-fpic"},
{"-fno-pic"},
{"-fPIC"},
+33 -20
View File
@@ -4,23 +4,36 @@ import "unsafe"
var _ unsafe.Pointer
type C.int16_t = int16
type C.int32_t = int32
type C.int64_t = int64
type C.int8_t = int8
type C.uint16_t = uint16
type C.uint32_t = uint32
type C.uint64_t = uint64
type C.uint8_t = uint8
type C.uintptr_t = uintptr
type C.char uint8
type C.int int32
type C.long int32
type C.longlong int64
type C.schar int8
type C.short int16
type C.uchar uint8
type C.uint uint32
type C.ulong uint32
type C.ulonglong uint64
type C.ushort uint16
//go:linkname C.CString runtime.cgo_CString
func C.CString(string) *C.char
//go:linkname C.GoString runtime.cgo_GoString
func C.GoString(*C.char) string
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func C.__GoStringN(*C.char, uintptr) string
func C.GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
type (
C.char uint8
C.schar int8
C.uchar uint8
C.short int16
C.ushort uint16
C.int int32
C.uint uint32
C.long int32
C.ulong uint32
C.longlong int64
C.ulonglong uint64
)
+35 -22
View File
@@ -4,26 +4,39 @@ import "unsafe"
var _ unsafe.Pointer
const C.bar = C.foo
const C.foo = 3
//go:linkname C.CString runtime.cgo_CString
func C.CString(string) *C.char
type C.int16_t = int16
type C.int32_t = int32
type C.int64_t = int64
type C.int8_t = int8
type C.uint16_t = uint16
type C.uint32_t = uint32
type C.uint64_t = uint64
type C.uint8_t = uint8
type C.uintptr_t = uintptr
type C.char uint8
type C.int int32
type C.long int32
type C.longlong int64
type C.schar int8
type C.short int16
type C.uchar uint8
type C.uint uint32
type C.ulong uint32
type C.ulonglong uint64
type C.ushort uint16
//go:linkname C.GoString runtime.cgo_GoString
func C.GoString(*C.char) string
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func C.__GoStringN(*C.char, uintptr) string
func C.GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
type (
C.char uint8
C.schar int8
C.uchar uint8
C.short int16
C.ushort uint16
C.int int32
C.uint uint32
C.long int32
C.ulong uint32
C.longlong int64
C.ulonglong uint64
)
const C.foo = 3
const C.bar = C.foo
+9 -1
View File
@@ -14,6 +14,12 @@ typedef someType noType; // undefined type
#define SOME_CONST_2 6) // const not used (so no error)
#define SOME_CONST_3 1234 // const too large for byte
*/
//
//
// #define SOME_CONST_4 8) // after some empty lines
import "C"
// #warning another warning
import "C"
// Make sure that errors for the following lines won't change with future
@@ -21,7 +27,7 @@ import "C"
//line errors.go:100
var (
// constant too large
_ C.uint8_t = 2 << 10
_ C.char = 2 << 10
// z member does not exist
_ C.point_t = C.point_t{z: 3}
@@ -30,4 +36,6 @@ var (
_ = C.SOME_CONST_1
_ byte = C.SOME_CONST_3
_ = C.SOME_CONST_4
)
+42 -25
View File
@@ -1,13 +1,16 @@
// CGo errors:
// testdata/errors.go:4:2: warning: some warning
// testdata/errors.go:11:9: error: unknown type name 'someType'
// testdata/errors.go:13:23: unexpected token )
// testdata/errors.go:22:5: warning: another warning
// testdata/errors.go:13:23: unexpected token ), expected end of expression
// testdata/errors.go:19:26: unexpected token ), expected end of expression
// Type checking errors after CGo processing:
// testdata/errors.go:102: cannot use 2 << 10 (untyped int constant 2048) as uint8 value in variable declaration (overflows)
// testdata/errors.go:102: cannot use 2 << 10 (untyped int constant 2048) as C.char value in variable declaration (overflows)
// testdata/errors.go:105: unknown field z in struct literal
// testdata/errors.go:108: undeclared name: C.SOME_CONST_1
// testdata/errors.go:108: undefined: C.SOME_CONST_1
// testdata/errors.go:110: cannot use C.SOME_CONST_3 (untyped int constant 1234) as byte value in variable declaration (overflows)
// testdata/errors.go:112: undefined: C.SOME_CONST_4
package main
@@ -15,29 +18,43 @@ import "unsafe"
var _ unsafe.Pointer
const C.SOME_CONST_3 = 1234
//go:linkname C.CString runtime.cgo_CString
func C.CString(string) *C.char
type C.int16_t = int16
type C.int32_t = int32
type C.int64_t = int64
type C.int8_t = int8
type C.uint16_t = uint16
type C.uint32_t = uint32
type C.uint64_t = uint64
type C.uint8_t = uint8
type C.uintptr_t = uintptr
type C.char uint8
type C.int int32
type C.long int32
type C.longlong int64
type C.schar int8
type C.short int16
type C.uchar uint8
type C.uint uint32
type C.ulong uint32
type C.ulonglong uint64
type C.ushort uint16
type C.point_t = struct {
//go:linkname C.GoString runtime.cgo_GoString
func C.GoString(*C.char) string
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func C.__GoStringN(*C.char, uintptr) string
func C.GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
type (
C.char uint8
C.schar int8
C.uchar uint8
C.short int16
C.ushort uint16
C.int int32
C.uint uint32
C.long int32
C.ulong uint32
C.longlong int64
C.ulonglong uint64
)
type C.struct_point_t struct {
x C.int
y C.int
}
type C.point_t = C.struct_point_t
const C.SOME_CONST_3 = 1234
+34 -21
View File
@@ -9,26 +9,39 @@ import "unsafe"
var _ unsafe.Pointer
//go:linkname C.CString runtime.cgo_CString
func C.CString(string) *C.char
//go:linkname C.GoString runtime.cgo_GoString
func C.GoString(*C.char) string
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func C.__GoStringN(*C.char, uintptr) string
func C.GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
type (
C.char uint8
C.schar int8
C.uchar uint8
C.short int16
C.ushort uint16
C.int int32
C.uint uint32
C.long int32
C.ulong uint32
C.longlong int64
C.ulonglong uint64
)
const C.BAR = 3
const C.FOO_H = 1
type C.int16_t = int16
type C.int32_t = int32
type C.int64_t = int64
type C.int8_t = int8
type C.uint16_t = uint16
type C.uint32_t = uint32
type C.uint64_t = uint64
type C.uint8_t = uint8
type C.uintptr_t = uintptr
type C.char uint8
type C.int int32
type C.long int32
type C.longlong int64
type C.schar int8
type C.short int16
type C.uchar uint8
type C.uint uint32
type C.ulong uint32
type C.ulonglong uint64
type C.ushort uint16
+25
View File
@@ -0,0 +1,25 @@
package main
/*
// Function signatures.
int foo(int a, int b);
void variadic0();
void variadic2(int x, int y, ...);
static void staticfunc(int x);
// Global variable signatures.
extern int someValue;
*/
import "C"
// Test function signatures.
func accessFunctions() {
C.foo(3, 4)
C.variadic0()
C.variadic2(3, 5)
C.staticfunc(3)
}
func accessGlobals() {
_ = C.someValue
}
+64
View File
@@ -0,0 +1,64 @@
package main
import "unsafe"
var _ unsafe.Pointer
//go:linkname C.CString runtime.cgo_CString
func C.CString(string) *C.char
//go:linkname C.GoString runtime.cgo_GoString
func C.GoString(*C.char) string
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func C.__GoStringN(*C.char, uintptr) string
func C.GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
type (
C.char uint8
C.schar int8
C.uchar uint8
C.short int16
C.ushort uint16
C.int int32
C.uint uint32
C.long int32
C.ulong uint32
C.longlong int64
C.ulonglong uint64
)
//export foo
func C.foo(a C.int, b C.int) C.int
var C.foo$funcaddr unsafe.Pointer
//export variadic0
//go:variadic
func C.variadic0()
var C.variadic0$funcaddr unsafe.Pointer
//export variadic2
//go:variadic
func C.variadic2(x C.int, y C.int)
var C.variadic2$funcaddr unsafe.Pointer
//export _Cgo_static_173c95a79b6df1980521_staticfunc
func C.staticfunc!symbols.go(x C.int)
var C.staticfunc!symbols.go$funcaddr unsafe.Pointer
//go:extern someValue
var C.someValue C.int
+8 -10
View File
@@ -104,14 +104,18 @@ typedef struct {
unsigned char e : 3;
// Note that C++ allows bitfields bigger than the underlying type.
} bitfield_t;
// Function signatures.
void variadic0();
void variadic2(int x, int y, ...);
*/
import "C"
// // Test that we can refer from this CGo fragment to the fragment above.
// typedef myint myint2;
import "C"
var (
// aliases
_ C.float
_ C.double
// Simple typedefs.
_ C.myint
@@ -167,9 +171,3 @@ func accessUnion() {
var _ *C.int = union2d.unionfield_i()
var _ *[2]float64 = union2d.unionfield_d()
}
// Test function signatures.
func accessFunctions() {
C.variadic0()
C.variadic2(3, 5)
}
+113 -116
View File
@@ -4,147 +4,144 @@ import "unsafe"
var _ unsafe.Pointer
func C.variadic0() //go:variadic
func C.variadic2(x C.int, y C.int) //go:variadic
var C.variadic0$funcaddr unsafe.Pointer
var C.variadic2$funcaddr unsafe.Pointer
//go:linkname C.CString runtime.cgo_CString
func C.CString(string) *C.char
const C.option2A = 20
const C.optionA = 0
const C.optionB = 1
const C.optionC = -5
const C.optionD = -4
const C.optionE = 10
const C.optionF = 11
const C.optionG = 12
const C.unused1 = 5
//go:linkname C.GoString runtime.cgo_GoString
func C.GoString(*C.char) string
type C.int16_t = int16
type C.int32_t = int32
type C.int64_t = int64
type C.int8_t = int8
type C.uint16_t = uint16
type C.uint32_t = uint32
type C.uint64_t = uint64
type C.uint8_t = uint8
type C.uintptr_t = uintptr
type C.char uint8
type C.int int32
type C.long int32
type C.longlong int64
type C.schar int8
type C.short int16
type C.uchar uint8
type C.uint uint32
type C.ulong uint32
type C.ulonglong uint64
type C.ushort uint16
type C.bitfield_t = C.struct_4
type C.myIntArray = [10]C.int
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func C.__GoStringN(*C.char, uintptr) string
func C.GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
type (
C.char uint8
C.schar int8
C.uchar uint8
C.short int16
C.ushort uint16
C.int int32
C.uint uint32
C.long int32
C.ulong uint32
C.longlong int64
C.ulonglong uint64
)
type C.myint = C.int
type C.option2_t = C.uint
type C.option_t = C.enum_option
type C.point2d_t = struct {
type C.struct_point2d_t struct {
x C.int
y C.int
}
type C.point3d_t = C.struct_point3d
type C.struct_nested_t = struct {
begin C.point2d_t
end C.point2d_t
tag C.int
coord C.union_2
}
type C.types_t = struct {
f float32
d float64
ptr *C.int
}
type C.union1_t = struct{ i C.int }
type C.union2d_t = C.union_union2d
type C.union3_t = C.union_1
type C.union_nested_t = C.union_3
type C.unionarray_t = struct{ arr [10]C.uchar }
func (s *C.struct_4) bitfield_a() C.uchar {
return s.__bitfield_1 & 0x1f
}
func (s *C.struct_4) set_bitfield_a(value C.uchar) {
s.__bitfield_1 = s.__bitfield_1&^0x1f | value&0x1f<<0
}
func (s *C.struct_4) bitfield_b() C.uchar {
return s.__bitfield_1 >> 5 & 0x1
}
func (s *C.struct_4) set_bitfield_b(value C.uchar) {
s.__bitfield_1 = s.__bitfield_1&^0x20 | value&0x1<<5
}
func (s *C.struct_4) bitfield_c() C.uchar {
return s.__bitfield_1 >> 6
}
func (s *C.struct_4) set_bitfield_c(value C.uchar,
) { s.__bitfield_1 = s.__bitfield_1&0x3f | value<<6 }
type C.struct_4 struct {
start C.uchar
__bitfield_1 C.uchar
d C.uchar
e C.uchar
}
type C.point2d_t = C.struct_point2d_t
type C.struct_point3d struct {
x C.int
y C.int
z C.int
}
type C.point3d_t = C.struct_point3d
type C.struct_type1 struct {
_type C.int
__type C.int
___type C.int
}
type C.struct_type2 struct{ _type C.int }
type C.union_union1_t struct{ i C.int }
type C.union1_t = C.union_union1_t
type C.union_union3_t struct{ $union uint64 }
func (union *C.union_1) unionfield_i() *C.int {
return (*C.int)(unsafe.Pointer(&union.$union))
}
func (union *C.union_1) unionfield_d() *float64 {
func (union *C.union_union3_t) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
func (union *C.union_union3_t) unionfield_d() *float64 {
return (*float64)(unsafe.Pointer(&union.$union))
}
func (union *C.union_1) unionfield_s() *C.short {
func (union *C.union_union3_t) unionfield_s() *C.short {
return (*C.short)(unsafe.Pointer(&union.$union))
}
type C.union_1 struct{ $union uint64 }
type C.union3_t = C.union_union3_t
type C.union_union2d struct{ $union [2]uint64 }
func (union *C.union_2) unionfield_area() *C.point2d_t {
return (*C.point2d_t)(unsafe.Pointer(&union.$union))
}
func (union *C.union_2) unionfield_solid() *C.point3d_t {
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
}
type C.union_2 struct{ $union [3]uint32 }
func (union *C.union_3) unionfield_point() *C.point3d_t {
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
}
func (union *C.union_3) unionfield_array() *C.unionarray_t {
return (*C.unionarray_t)(unsafe.Pointer(&union.$union))
}
func (union *C.union_3) unionfield_thing() *C.union3_t {
return (*C.union3_t)(unsafe.Pointer(&union.$union))
}
type C.union_3 struct{ $union [2]uint64 }
func (union *C.union_union2d) unionfield_i() *C.int {
return (*C.int)(unsafe.Pointer(&union.$union))
}
func (union *C.union_union2d) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
func (union *C.union_union2d) unionfield_d() *[2]float64 {
return (*[2]float64)(unsafe.Pointer(&union.$union))
}
type C.union_union2d struct{ $union [2]uint64 }
type C.enum_option C.int
type C.enum_unused C.uint
type C.union2d_t = C.union_union2d
type C.union_unionarray_t struct{ arr [10]C.uchar }
type C.unionarray_t = C.union_unionarray_t
type C._Ctype_union___0 struct{ $union [3]uint32 }
func (union *C._Ctype_union___0) unionfield_area() *C.point2d_t {
return (*C.point2d_t)(unsafe.Pointer(&union.$union))
}
func (union *C._Ctype_union___0) unionfield_solid() *C.point3d_t {
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
}
type C.struct_struct_nested_t struct {
begin C.point2d_t
end C.point2d_t
tag C.int
coord C._Ctype_union___0
}
type C.struct_nested_t = C.struct_struct_nested_t
type C.union_union_nested_t struct{ $union [2]uint64 }
func (union *C.union_union_nested_t) unionfield_point() *C.point3d_t {
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
}
func (union *C.union_union_nested_t) unionfield_array() *C.unionarray_t {
return (*C.unionarray_t)(unsafe.Pointer(&union.$union))
}
func (union *C.union_union_nested_t) unionfield_thing() *C.union3_t {
return (*C.union3_t)(unsafe.Pointer(&union.$union))
}
type C.union_nested_t = C.union_union_nested_t
type C.enum_option = C.int
type C.option_t = C.enum_option
type C.enum_option2_t = C.uint
type C.option2_t = C.enum_option2_t
type C.struct_types_t struct {
f float32
d float64
ptr *C.int
}
type C.types_t = C.struct_types_t
type C.myIntArray = [10]C.int
type C.struct_bitfield_t struct {
start C.uchar
__bitfield_1 C.uchar
d C.uchar
e C.uchar
}
func (s *C.struct_bitfield_t) bitfield_a() C.uchar { return s.__bitfield_1 & 0x1f }
func (s *C.struct_bitfield_t) set_bitfield_a(value C.uchar) {
s.__bitfield_1 = s.__bitfield_1&^0x1f | value&0x1f<<0
}
func (s *C.struct_bitfield_t) bitfield_b() C.uchar {
return s.__bitfield_1 >> 5 & 0x1
}
func (s *C.struct_bitfield_t) set_bitfield_b(value C.uchar) {
s.__bitfield_1 = s.__bitfield_1&^0x20 | value&0x1<<5
}
func (s *C.struct_bitfield_t) bitfield_c() C.uchar {
return s.__bitfield_1 >> 6
}
func (s *C.struct_bitfield_t) set_bitfield_c(value C.uchar,
) { s.__bitfield_1 = s.__bitfield_1&0x3f | value<<6 }
type C.bitfield_t = C.struct_bitfield_t
+318 -73
View File
@@ -5,10 +5,12 @@ package compileopts
import (
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/google/shlex"
"github.com/tinygo-org/tinygo/goenv"
)
@@ -17,11 +19,10 @@ type Config struct {
Options *Options
Target *TargetSpec
GoMinorVersion int
ClangHeaders string // Clang built-in header include path
TestConfig TestConfig
}
// Triple returns the LLVM target triple, like armv6m-none-eabi.
// Triple returns the LLVM target triple, like armv6m-unknown-unknown-eabi.
func (c *Config) Triple() string {
return c.Target.Triple
}
@@ -33,10 +34,22 @@ func (c *Config) CPU() string {
}
// Features returns a list of features this CPU supports. For example, for a
// RISC-V processor, that could be ["+a", "+c", "+m"]. For many targets, an
// empty list will be returned.
func (c *Config) Features() []string {
return c.Target.Features
// RISC-V processor, that could be "+a,+c,+m". For many targets, an empty list
// will be returned.
func (c *Config) Features() string {
if c.Target.Features == "" {
return c.Options.LLVMFeatures
}
if c.Options.LLVMFeatures == "" {
return c.Target.Features
}
return c.Target.Features + "," + c.Options.LLVMFeatures
}
// ABI returns the -mabi= flag for this target (like -mabi=lp64). A zero-length
// string is returned if the target doesn't specify an ABI.
func (c *Config) ABI() string {
return c.Target.ABI
}
// GOOS returns the GOOS of the target. This might not always be the actual OS:
@@ -53,26 +66,30 @@ func (c *Config) GOARCH() string {
return c.Target.GOARCH
}
// GOARM will return the GOARM environment variable given to the compiler when
// building a program.
func (c *Config) GOARM() string {
return c.Options.GOARM
}
// BuildTags returns the complete list of build tags used during this build.
func (c *Config) BuildTags() []string {
tags := append(c.Target.BuildTags, []string{"tinygo", "gc." + c.GC(), "scheduler." + c.Scheduler()}...)
tags := append([]string(nil), c.Target.BuildTags...) // copy slice (avoid a race)
tags = append(tags, []string{
"tinygo", // that's the compiler
"purego", // to get various crypto packages to work
"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
for i := 1; i <= c.GoMinorVersion; i++ {
tags = append(tags, fmt.Sprintf("go1.%d", i))
}
if extraTags := strings.Fields(c.Options.Tags); len(extraTags) != 0 {
tags = append(tags, extraTags...)
}
tags = append(tags, c.Options.Tags...)
return tags
}
// CgoEnabled returns true if (and only if) CGo is enabled. It is true by
// default and false if CGO_ENABLED is set to "0".
func (c *Config) CgoEnabled() bool {
return goenv.Get("CGO_ENABLED") == "1"
}
// GC returns the garbage collection strategy in use on this platform. Valid
// values are "none", "leaking", "extalloc", and "conservative".
// values are "none", "leaking", "conservative" and "precise".
func (c *Config) GC() string {
if c.Options.GC != "" {
return c.Options.GC
@@ -80,21 +97,16 @@ func (c *Config) GC() string {
if c.Target.GC != "" {
return c.Target.GC
}
for _, tag := range c.Target.BuildTags {
if tag == "baremetal" || tag == "wasm" {
return "conservative"
}
}
return "extalloc"
return "conservative"
}
// NeedsStackObjects returns true if the compiler should insert stack objects
// that can be traced by the garbage collector.
func (c *Config) NeedsStackObjects() bool {
switch c.GC() {
case "conservative", "extalloc":
case "conservative", "custom", "precise":
for _, tag := range c.BuildTags() {
if tag == "wasm" {
if tag == "tinygo.wasm" {
return true
}
}
@@ -106,7 +118,7 @@ func (c *Config) NeedsStackObjects() bool {
}
// Scheduler returns the scheduler implementation. Valid values are "none",
//"coroutines" and "tasks".
// "asyncify" and "tasks".
func (c *Config) Scheduler() string {
if c.Options.Scheduler != "" {
return c.Options.Scheduler
@@ -114,32 +126,40 @@ func (c *Config) Scheduler() string {
if c.Target.Scheduler != "" {
return c.Target.Scheduler
}
// Fall back to coroutines, which are supported everywhere.
return "coroutines"
// Fall back to none.
return "none"
}
// FuncImplementation picks an appropriate func value implementation for the
// target.
func (c *Config) FuncImplementation() string {
switch c.Scheduler() {
case "tasks":
// A func value is implemented as a pair of pointers:
// {context, function pointer}
// where the context may be a pointer to a heap-allocated struct
// containing the free variables, or it may be undef if the function
// being pointed to doesn't need a context. The function pointer is a
// regular function pointer.
return "doubleword"
case "none", "coroutines":
// As "doubleword", but with the function pointer replaced by a unique
// ID per function signature. Function values are called by using a
// switch statement and choosing which function to call.
// Pick the switch implementation with the coroutines scheduler, as it
// allows the use of blocking inside a function that is used as a func
// value.
return "switch"
// Serial returns the serial implementation for this build configuration: uart,
// usb (meaning USB-CDC), or none.
func (c *Config) Serial() string {
if c.Options.Serial != "" {
return c.Options.Serial
}
if c.Target.Serial != "" {
return c.Target.Serial
}
return "none"
}
// OptLevels returns the optimization level (0-2), size level (0-2), and inliner
// threshold as used in the LLVM optimization pipeline.
func (c *Config) OptLevel() (level string, speedLevel, sizeLevel int) {
switch c.Options.Opt {
case "none", "0":
return "O0", 0, 0
case "1":
return "O1", 1, 0
case "2":
return "O2", 2, 0
case "s":
return "Os", 2, 1
case "z":
return "Oz", 2, 2 // default
default:
panic("unknown scheduler type")
// This is not shown to the user: valid choices are already checked as
// part of Options.Verify(). It is here as a sanity check.
panic("unknown optimization level: -opt=" + c.Options.Opt)
}
}
@@ -160,20 +180,181 @@ func (c *Config) AutomaticStackSize() bool {
return false
}
// StackSize returns the default stack size to be used for goroutines, if the
// stack size could not be determined automatically at compile time.
func (c *Config) StackSize() uint64 {
if c.Options.StackSize != 0 {
return c.Options.StackSize
}
return c.Target.DefaultStackSize
}
// MaxStackAlloc returns the size of the maximum allocation to put on the stack vs heap.
func (c *Config) MaxStackAlloc() uint64 {
if c.StackSize() > 32*1024 {
return 1024
}
return 256
}
// RP2040BootPatch returns whether the RP2040 boot patch should be applied that
// calculates and patches in the checksum for the 2nd stage bootloader.
func (c *Config) RP2040BootPatch() bool {
if c.Target.RP2040BootPatch != nil {
return *c.Target.RP2040BootPatch
}
return false
}
// MuslArchitecture returns the architecture name as used in musl libc. It is
// usually the same as the first part of the LLVM triple, but not always.
func MuslArchitecture(triple string) string {
arch := strings.Split(triple, "-")[0]
if strings.HasPrefix(arch, "arm") || strings.HasPrefix(arch, "thumb") {
arch = "arm"
}
return arch
}
// 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) {
archname := c.Triple()
if c.CPU() != "" {
archname += "-" + c.CPU()
}
if c.ABI() != "" {
archname += "-" + c.ABI()
}
// 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
}
// 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
}
// DefaultBinaryExtension returns the default extension for binaries, such as
// .exe, .wasm, or no extension (depending on the target).
func (c *Config) DefaultBinaryExtension() string {
parts := strings.Split(c.Triple(), "-")
if parts[0] == "wasm32" {
// WebAssembly files always have the .wasm file extension.
return ".wasm"
}
if len(parts) >= 3 && parts[2] == "windows" {
// Windows uses .exe.
return ".exe"
}
if len(parts) >= 3 && parts[2] == "unknown" {
// There appears to be a convention to use the .elf file extension for
// ELF files intended for microcontrollers. I'm not aware of the origin
// of this, it's just something that is used by many projects.
// I think it's a good tradition, so let's keep it.
return ".elf"
}
// Linux, MacOS, etc, don't use a file extension. Use it as a fallback.
return ""
}
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo
// preprocessing.
func (c *Config) CFlags() []string {
cflags := append([]string{}, c.Options.CFlags...)
func (c *Config) CFlags(libclang bool) []string {
var cflags []string
for _, flag := range c.Target.CFlags {
cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT")))
}
if c.Target.Libc == "picolibc" {
root := goenv.Get("TINYGOROOT")
cflags = append(cflags, "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "picolibc", "newlib", "libc", "include"))
cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include"))
resourceDir := goenv.ClangResourceDir(libclang)
if resourceDir != "" {
// The resource directory contains the built-in clang headers like
// stdbool.h, stdint.h, float.h, etc.
// It is left empty if we're using an external compiler (that already
// knows these headers).
cflags = append(cflags,
"-resource-dir="+resourceDir,
)
}
if c.Debug() {
cflags = append(cflags, "-g")
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"),
)
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", "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)
}
// Always emit debug information. It is optionally stripped at link time.
cflags = append(cflags, "-gdwarf-4")
// Use the same optimization level as TinyGo.
cflags = append(cflags, "-O"+c.Options.Opt)
// Set the LLVM target triple.
cflags = append(cflags, "--target="+c.Triple())
// Set the -mcpu (or similar) flag.
if c.Target.CPU != "" {
if c.GOARCH() == "amd64" || c.GOARCH() == "386" {
// x86 prefers the -march flag (-mcpu is deprecated there).
cflags = append(cflags, "-march="+c.Target.CPU)
} else if strings.HasPrefix(c.Triple(), "avr") {
// AVR MCUs use -mmcu instead of -mcpu.
cflags = append(cflags, "-mmcu="+c.Target.CPU)
} else {
// The rest just uses -mcpu.
cflags = append(cflags, "-mcpu="+c.Target.CPU)
}
}
// Set the -mabi flag, if needed.
if c.ABI() != "" {
cflags = append(cflags, "-mabi="+c.ABI())
}
return cflags
}
@@ -184,7 +365,7 @@ func (c *Config) CFlags() []string {
func (c *Config) LDFlags() []string {
root := goenv.Get("TINYGOROOT")
// Merge and adjust LDFlags.
ldflags := append([]string{}, c.Options.LDFlags...)
var ldflags []string
for _, flag := range c.Target.LDFlags {
ldflags = append(ldflags, strings.ReplaceAll(flag, "{root}", root))
}
@@ -213,8 +394,9 @@ func (c *Config) VerifyIR() bool {
return c.Options.VerifyIR
}
// Debug returns whether to add debug symbols to the IR, for debugging with GDB
// and similar.
// Debug returns whether debug (DWARF) information should be retained by the
// linker. By default, debug information is retained, but it can be removed
// with the -no-debug flag.
func (c *Config) Debug() bool {
return c.Options.Debug
}
@@ -229,6 +411,13 @@ func (c *Config) BinaryFormat(ext string) string {
return c.Target.BinaryFormat
}
return "bin"
case ".img":
// Image file. Only defined for the ESP32 at the moment, where it is a
// full (runnable) image that can be used in the Espressif QEMU fork.
if c.Target.BinaryFormat != "" {
return c.Target.BinaryFormat + "-img"
}
return "bin"
case ".hex":
// Similar to bin, but includes the start address and is thus usually a
// better format.
@@ -238,6 +427,11 @@ func (c *Config) BinaryFormat(ext string) string {
// More information:
// https://github.com/Microsoft/uf2
return "uf2"
case ".zip":
if c.Target.BinaryFormat != "" {
return c.Target.BinaryFormat
}
return "zip"
default:
// Use the ELF format for unrecognized file formats.
return "elf"
@@ -255,6 +449,9 @@ func (c *Config) Programmer() (method, openocdInterface string) {
case "openocd", "msd", "command":
// The -programmer flag only specifies the flash method.
return c.Options.Programmer, c.Target.OpenOCDInterface
case "bmp":
// The -programmer flag only specifies the flash method.
return c.Options.Programmer, ""
default:
// The -programmer flag specifies something else, assume it specifies
// the OpenOCD interface name.
@@ -270,26 +467,33 @@ func (c *Config) OpenOCDConfiguration() (args []string, err error) {
if openocdInterface == "" {
return nil, errors.New("OpenOCD programmer not set")
}
if !regexp.MustCompile("^[\\p{L}0-9_-]+$").MatchString(openocdInterface) {
if !regexp.MustCompile(`^[\p{L}0-9_-]+$`).MatchString(openocdInterface) {
return nil, fmt.Errorf("OpenOCD programmer has an invalid name: %#v", openocdInterface)
}
if c.Target.OpenOCDTarget == "" {
return nil, errors.New("OpenOCD chip not set")
}
if !regexp.MustCompile("^[\\p{L}0-9_-]+$").MatchString(c.Target.OpenOCDTarget) {
if !regexp.MustCompile(`^[\p{L}0-9_-]+$`).MatchString(c.Target.OpenOCDTarget) {
return nil, fmt.Errorf("OpenOCD target has an invalid name: %#v", c.Target.OpenOCDTarget)
}
if c.Target.OpenOCDTransport != "" && c.Target.OpenOCDTransport != "swd" {
return nil, fmt.Errorf("unknown OpenOCD transport: %#v", c.Target.OpenOCDTransport)
}
args = []string{"-f", "interface/" + openocdInterface + ".cfg"}
if c.Target.OpenOCDTransport != "" {
transport := c.Target.OpenOCDTransport
if transport == "swd" {
switch openocdInterface {
case "stlink-dap":
transport = "dapdirect_swd"
}
}
args = append(args, "-c", "transport select "+transport)
}
args = append(args, "-f", "target/"+c.Target.OpenOCDTarget+".cfg")
for _, cmd := range c.Target.OpenOCDCommands {
args = append(args, "-c", cmd)
}
if c.Target.OpenOCDTransport != "" {
args = append(args, "-c", "transport select "+c.Target.OpenOCDTransport)
}
args = append(args, "-f", "target/"+c.Target.OpenOCDTarget+".cfg")
return args, nil
}
@@ -312,16 +516,57 @@ func (c *Config) RelocationModel() string {
return "static"
}
// WasmAbi returns the WASM ABI which is specified in the target JSON file, and
// the value is overridden by `-wasm-abi` flag if it is provided
func (c *Config) WasmAbi() string {
if c.Options.WasmAbi != "" {
return c.Options.WasmAbi
// EmulatorName is a shorthand to get the command for this emulator, something
// like qemu-system-arm or simavr.
func (c *Config) EmulatorName() string {
parts := strings.SplitN(c.Target.Emulator, " ", 2)
if len(parts) > 1 {
return parts[0]
}
return c.Target.WasmAbi
return ""
}
// EmulatorFormat returns the binary format for the emulator and the associated
// file extension. An empty string means to pass directly whatever the linker
// produces directly without conversion (usually ELF format).
func (c *Config) EmulatorFormat() (format, fileExt string) {
switch {
case strings.Contains(c.Target.Emulator, "{img}"):
return "img", ".img"
default:
return "", ""
}
}
// Emulator returns a ready-to-run command to run the given binary in an
// emulator. Give it the format (returned by EmulatorFormat()) and the path to
// the compiled binary.
func (c *Config) Emulator(format, binary string) ([]string, error) {
parts, err := shlex.Split(c.Target.Emulator)
if err != nil {
return nil, fmt.Errorf("could not parse emulator command: %w", err)
}
var emulator []string
for _, s := range parts {
s = strings.ReplaceAll(s, "{root}", goenv.Get("TINYGOROOT"))
// Allow replacement of what's usually /tmp except notably Windows.
s = strings.ReplaceAll(s, "{tmpDir}", os.TempDir())
s = strings.ReplaceAll(s, "{"+format+"}", binary)
emulator = append(emulator, s)
}
return emulator, nil
}
type TestConfig struct {
CompileTestBinary bool
// TODO: Filter the test functions to run, include verbose flag, etc
CompileOnly bool
Verbose bool
Short bool
RunRegexp string
SkipRegexp string
Count *int
BenchRegexp string
BenchTime string
BenchMem bool
Shuffle string
}
+56 -21
View File
@@ -2,37 +2,57 @@ package compileopts
import (
"fmt"
"regexp"
"strings"
"time"
)
var (
validGCOptions = []string{"none", "leaking", "extalloc", "conservative"}
validSchedulerOptions = []string{"none", "tasks", "coroutines"}
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
validSerialOptions = []string{"none", "uart", "usb", "rtt"}
validPrintSizeOptions = []string{"none", "short", "full"}
validPanicStrategyOptions = []string{"print", "trap"}
validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
)
// Options contains extra options to give to the compiler. These options are
// usually passed from the command line.
// usually passed from the command line, but can also be passed in environment
// variables for example.
type Options struct {
Target string
Opt string
GC string
PanicStrategy string
Scheduler string
PrintIR bool
DumpSSA bool
VerifyIR bool
PrintCommands bool
Debug bool
PrintSizes string
PrintStacks bool
CFlags []string
LDFlags []string
Tags string
WasmAbi string
TestConfig TestConfig
Programmer string
GOOS string // environment variable
GOARCH string // environment variable
GOARM string // environment variable (only used with GOARCH=arm)
Directory string // working dir, leave it unset to use the current working dir
Target string
Opt string
GC string
PanicStrategy string
Scheduler string
StackSize uint64 // goroutine stack size (if none could be automatically determined)
Serial string
Work bool // -work flag to print temporary build directory
InterpTimeout time.Duration
PrintIR bool
DumpSSA bool
VerifyIR bool
SkipDWARF bool
PrintCommands func(cmd string, args ...string) `json:"-"`
Semaphore chan struct{} `json:"-"` // -p flag controls cap
Debug bool
PrintSizes string
PrintAllocs *regexp.Regexp // regexp string
PrintStacks bool
Tags []string
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
TestConfig TestConfig
Programmer string
OpenOCDCommands []string
LLVMFeatures string
PrintJSON bool
Monitor bool
BaudRate int
Timeout time.Duration
}
// Verify performs a validation on the given options, raising an error if options are not valid.
@@ -55,6 +75,15 @@ func (o *Options) Verify() error {
}
}
if o.Serial != "" {
valid := isInArray(validSerialOptions, o.Serial)
if !valid {
return fmt.Errorf(`invalid serial option '%s': valid values are %s`,
o.Serial,
strings.Join(validSerialOptions, ", "))
}
}
if o.PrintSizes != "" {
valid := isInArray(validPrintSizeOptions, o.PrintSizes)
if !valid {
@@ -73,6 +102,12 @@ func (o *Options) Verify() error {
}
}
if o.Opt != "" {
if !isInArray(validOptOptions, o.Opt) {
return fmt.Errorf("invalid -opt=%s: valid values are %s", o.Opt, strings.Join(validOptOptions, ", "))
}
}
return nil
}
+8 -14
View File
@@ -9,8 +9,8 @@ import (
func TestVerifyOptions(t *testing.T) {
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, extalloc, conservative`)
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, coroutines`)
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`)
expectedPrintSizeError := errors.New(`invalid size option 'incorrect': valid values are none, short, full`)
expectedPanicStrategyError := errors.New(`invalid panic option 'incorrect': valid values are print, trap`)
@@ -42,18 +42,18 @@ func TestVerifyOptions(t *testing.T) {
GC: "leaking",
},
},
{
name: "GCOptionExtalloc",
opts: compileopts.Options{
GC: "extalloc",
},
},
{
name: "GCOptionConservative",
opts: compileopts.Options{
GC: "conservative",
},
},
{
name: "GCOptionCustom",
opts: compileopts.Options{
GC: "custom",
},
},
{
name: "InvalidSchedulerOption",
opts: compileopts.Options{
@@ -73,12 +73,6 @@ func TestVerifyOptions(t *testing.T) {
Scheduler: "tasks",
},
},
{
name: "SchedulerOptionCoroutines",
opts: compileopts.Options{
Scheduler: "coroutines",
},
},
{
name: "InvalidPrintSizeOption",
opts: compileopts.Options{
+308 -140
View File
@@ -5,6 +5,7 @@ package compileopts
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
"os/exec"
@@ -22,46 +23,49 @@ import (
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.TargetOptions.html
// https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
type TargetSpec struct {
Inherits []string `json:"inherits"`
Triple string `json:"llvm-target"`
CPU string `json:"cpu"`
Features []string `json:"features"`
GOOS string `json:"goos"`
GOARCH string `json:"goarch"`
BuildTags []string `json:"build-tags"`
GC string `json:"gc"`
Scheduler string `json:"scheduler"`
Compiler string `json:"compiler"`
Linker string `json:"linker"`
RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt)
Libc string `json:"libc"`
AutoStackSize *bool `json:"automatic-stack-size"` // Determine stack size automatically at compile time.
DefaultStackSize uint64 `json:"default-stack-size"` // Default stack size if the size couldn't be determined at compile time.
CFlags []string `json:"cflags"`
LDFlags []string `json:"ldflags"`
LinkerScript string `json:"linkerscript"`
ExtraFiles []string `json:"extra-files"`
Emulator []string `json:"emulator" override:"copy"` // inherited Emulator must not be append
FlashCommand string `json:"flash-command"`
GDB []string `json:"gdb"`
PortReset string `json:"flash-1200-bps-reset"`
FlashMethod string `json:"flash-method"`
FlashVolume string `json:"msd-volume-name"`
FlashFilename string `json:"msd-firmware-name"`
UF2FamilyID string `json:"uf2-family-id"`
BinaryFormat string `json:"binary-format"`
OpenOCDInterface string `json:"openocd-interface"`
OpenOCDTarget string `json:"openocd-target"`
OpenOCDTransport string `json:"openocd-transport"`
OpenOCDCommands []string `json:"openocd-commands"`
JLinkDevice string `json:"jlink-device"`
CodeModel string `json:"code-model"`
RelocationModel string `json:"relocation-model"`
WasmAbi string `json:"wasm-abi"`
Inherits []string `json:"inherits,omitempty"`
Triple string `json:"llvm-target,omitempty"`
CPU string `json:"cpu,omitempty"`
ABI string `json:"target-abi,omitempty"` // roughly equivalent to -mabi= flag
Features string `json:"features,omitempty"`
GOOS string `json:"goos,omitempty"`
GOARCH string `json:"goarch,omitempty"`
BuildTags []string `json:"build-tags,omitempty"`
GC string `json:"gc,omitempty"`
Scheduler string `json:"scheduler,omitempty"`
Serial string `json:"serial,omitempty"` // which serial output to use (uart, usb, none)
Linker string `json:"linker,omitempty"`
RTLib string `json:"rtlib,omitempty"` // compiler runtime library (libgcc, compiler-rt)
Libc string `json:"libc,omitempty"`
AutoStackSize *bool `json:"automatic-stack-size,omitempty"` // Determine stack size automatically at compile time.
DefaultStackSize uint64 `json:"default-stack-size,omitempty"` // Default stack size if the size couldn't be determined at compile time.
CFlags []string `json:"cflags,omitempty"`
LDFlags []string `json:"ldflags,omitempty"`
LinkerScript string `json:"linkerscript,omitempty"`
ExtraFiles []string `json:"extra-files,omitempty"`
RP2040BootPatch *bool `json:"rp2040-boot-patch,omitempty"` // Patch RP2040 2nd stage bootloader checksum
Emulator string `json:"emulator,omitempty"`
FlashCommand string `json:"flash-command,omitempty"`
GDB []string `json:"gdb,omitempty"`
PortReset string `json:"flash-1200-bps-reset,omitempty"`
SerialPort []string `json:"serial-port,omitempty"` // serial port IDs in the form "vid:pid"
FlashMethod string `json:"flash-method,omitempty"`
FlashVolume []string `json:"msd-volume-name,omitempty"`
FlashFilename string `json:"msd-firmware-name,omitempty"`
UF2FamilyID string `json:"uf2-family-id,omitempty"`
BinaryFormat string `json:"binary-format,omitempty"`
OpenOCDInterface string `json:"openocd-interface,omitempty"`
OpenOCDTarget string `json:"openocd-target,omitempty"`
OpenOCDTransport string `json:"openocd-transport,omitempty"`
OpenOCDCommands []string `json:"openocd-commands,omitempty"`
OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd
JLinkDevice string `json:"jlink-device,omitempty"`
CodeModel string `json:"code-model,omitempty"`
RelocationModel string `json:"relocation-model,omitempty"`
}
// overrideProperties overrides all properties that are set in child into itself using reflection.
func (spec *TargetSpec) overrideProperties(child *TargetSpec) {
func (spec *TargetSpec) overrideProperties(child *TargetSpec) error {
specType := reflect.TypeOf(spec).Elem()
specValue := reflect.ValueOf(spec).Elem()
childValue := reflect.ValueOf(child).Elem()
@@ -84,23 +88,22 @@ func (spec *TargetSpec) overrideProperties(child *TargetSpec) {
if !src.IsNil() {
dst.Set(src)
}
case reflect.Slice: // for slices...
if src.Len() > 0 { // ... if not empty ...
switch tag := field.Tag.Get("override"); tag {
case "copy":
// copy the field of child to spec
dst.Set(src)
case "append", "":
// or append the field of child to spec
dst.Set(reflect.AppendSlice(src, dst))
default:
panic("override mode must be 'copy' or 'append' (default). I don't know how to '" + tag + "'.")
case reflect.Slice: // for slices, append the field and check for duplicates
dst.Set(reflect.AppendSlice(dst, src))
for i := 0; i < dst.Len(); i++ {
v := dst.Index(i).String()
for j := i + 1; j < dst.Len(); j++ {
w := dst.Index(j).String()
if v == w {
return fmt.Errorf("duplicate value '%s' in field %s", v, field.Name)
}
}
}
default:
panic("unknown field type : " + kind.String())
return fmt.Errorf("unknown field type: %s", kind)
}
}
return nil
}
// load reads a target specification from the JSON in the given io.Reader. It
@@ -115,10 +118,10 @@ func (spec *TargetSpec) load(r io.Reader) error {
}
// loadFromGivenStr loads the TargetSpec from the given string that could be:
// - targets/ directory inside the compiler sources
// - a relative or absolute path to custom (project specific) target specification .json file;
// the Inherits[] could contain the files from target folder (ex. stm32f4disco)
// as well as path to custom files (ex. myAwesomeProject.json)
// - targets/ directory inside the compiler sources
// - a relative or absolute path to custom (project specific) target specification .json file;
// the Inherits[] could contain the files from target folder (ex. stm32f4disco)
// as well as path to custom files (ex. myAwesomeProject.json)
func (spec *TargetSpec) loadFromGivenStr(str string) error {
path := ""
if strings.HasSuffix(str, ".json") {
@@ -148,132 +151,297 @@ func (spec *TargetSpec) resolveInherits() error {
if err != nil {
return err
}
newSpec.overrideProperties(subtarget)
err = newSpec.overrideProperties(subtarget)
if err != nil {
return err
}
}
// When all properties are loaded, make sure they are properly inherited.
newSpec.overrideProperties(spec)
err := newSpec.overrideProperties(spec)
if err != nil {
return err
}
*spec = *newSpec
return nil
}
// Load a target specification.
func LoadTarget(target string) (*TargetSpec, error) {
if target == "" {
func LoadTarget(options *Options) (*TargetSpec, error) {
if options.Target == "" {
// Configure based on GOOS/GOARCH environment variables (falling back to
// runtime.GOOS/runtime.GOARCH), and generate a LLVM target based on it.
goos := goenv.Get("GOOS")
goarch := goenv.Get("GOARCH")
llvmos := goos
llvmarch := map[string]string{
"386": "i386",
"amd64": "x86_64",
"arm64": "aarch64",
}[goarch]
if llvmarch == "" {
llvmarch = goarch
var llvmarch string
switch options.GOARCH {
case "386":
llvmarch = "i386"
case "amd64":
llvmarch = "x86_64"
case "arm64":
llvmarch = "aarch64"
case "arm":
switch options.GOARM {
case "5":
llvmarch = "armv5"
case "6":
llvmarch = "armv6"
case "7":
llvmarch = "armv7"
default:
return nil, fmt.Errorf("invalid GOARM=%s, must be 5, 6, or 7", options.GOARM)
}
case "wasm":
llvmarch = "wasm32"
default:
llvmarch = options.GOARCH
}
target = llvmarch + "--" + llvmos
if goarch == "arm" {
llvmvendor := "unknown"
llvmos := options.GOOS
switch llvmos {
case "darwin":
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer
// to iOS!
llvmos = "macosx10.12.0"
if llvmarch == "aarch64" {
// Looks like Apple prefers to call this architecture ARM64
// instead of AArch64.
llvmarch = "arm64"
llvmos = "macosx11.0.0"
}
llvmvendor = "apple"
case "wasip1":
llvmos = "wasi"
}
// Target triples (which actually have four components, but are called
// triples for historical reasons) have the form:
// arch-vendor-os-environment
target := llvmarch + "-" + llvmvendor + "-" + llvmos
if options.GOOS == "windows" {
target += "-gnu"
} else if options.GOARCH == "arm" {
target += "-gnueabihf"
}
return defaultTarget(goos, goarch, target)
return defaultTarget(options.GOOS, options.GOARCH, target)
}
// See whether there is a target specification for this target (e.g.
// Arduino).
spec := &TargetSpec{}
err := spec.loadFromGivenStr(target)
if err == nil {
// Successfully loaded this target from a built-in .json file. Make sure
// it includes all parents as specified in the "inherits" key.
err = spec.resolveInherits()
if err != nil {
return nil, err
}
return spec, nil
} else if !os.IsNotExist(err) {
// Expected a 'file not found' error, got something else. Report it as
// an error.
err := spec.loadFromGivenStr(options.Target)
if err != nil {
return nil, err
} else {
// Load target from given triple, ignore GOOS/GOARCH environment
// variables.
tripleSplit := strings.Split(target, "-")
if len(tripleSplit) < 3 {
return nil, errors.New("expected a full LLVM target or a custom target in -target flag")
}
if tripleSplit[0] == "arm" {
// LLVM and Clang have a different idea of what "arm" means, so
// upgrade to a slightly more modern ARM. In fact, when you pass
// --target=arm--linux-gnueabihf to Clang, it will convert that
// internally to armv7-unknown-linux-gnueabihf. Changing the
// architecture to armv7 will keep things consistent.
tripleSplit[0] = "armv7"
}
goos := tripleSplit[2]
if strings.HasPrefix(goos, "darwin") {
goos = "darwin"
}
goarch := map[string]string{ // map from LLVM arch to Go arch
"i386": "386",
"i686": "386",
"x86_64": "amd64",
"aarch64": "arm64",
"armv7": "arm",
}[tripleSplit[0]]
if goarch == "" {
goarch = tripleSplit[0]
}
return defaultTarget(goos, goarch, strings.Join(tripleSplit, "-"))
}
// Successfully loaded this target from a built-in .json file. Make sure
// it includes all parents as specified in the "inherits" key.
err = spec.resolveInherits()
if err != nil {
return nil, fmt.Errorf("%s : %w", options.Target, err)
}
if spec.Scheduler == "asyncify" {
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_asyncify_wasm.S")
}
return spec, nil
}
// WindowsBuildNotSupportedErr is being thrown, when goos is windows and no target has been specified.
var WindowsBuildNotSupportedErr = errors.New("Building Windows binaries is currently not supported. Try specifying a different target")
// GetTargetSpecs retrieves target specifications from the TINYGOROOT targets
// directory. Only valid target JSON files are considered, and the function
// returns a map of target names to their respective TargetSpec.
func GetTargetSpecs() (map[string]*TargetSpec, error) {
dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
entries, err := os.ReadDir(dir)
if err != nil {
return nil, fmt.Errorf("could not list targets: %w", err)
}
maps := map[string]*TargetSpec{}
for _, entry := range entries {
entryInfo, err := entry.Info()
if err != nil {
return nil, fmt.Errorf("could not get entry info: %w", err)
}
if !entryInfo.Mode().IsRegular() || !strings.HasSuffix(entry.Name(), ".json") {
// Only inspect JSON files.
continue
}
path := filepath.Join(dir, entry.Name())
spec, err := LoadTarget(&Options{Target: path})
if err != nil {
return nil, fmt.Errorf("could not list target: %w", err)
}
if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" {
// This doesn't look like a regular target file, but rather like
// a parent target (such as targets/cortex-m.json).
continue
}
name := entry.Name()
name = name[:len(name)-5]
maps[name] = spec
}
return maps, nil
}
func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
if goos == "windows" {
return nil, WindowsBuildNotSupportedErr
}
// No target spec available. Use the default one, useful on most systems
// with a regular OS.
spec := TargetSpec{
Triple: triple,
GOOS: goos,
GOARCH: goarch,
BuildTags: []string{goos, goarch},
Compiler: "clang",
Linker: "cc",
CFlags: []string{"--target=" + triple},
GDB: []string{"gdb"},
PortReset: "false",
Triple: triple,
GOOS: goos,
GOARCH: goarch,
BuildTags: []string{goos, goarch},
GC: "precise",
Scheduler: "tasks",
Linker: "cc",
DefaultStackSize: 1024 * 64, // 64kB
GDB: []string{"gdb"},
PortReset: "false",
}
switch goarch {
case "386":
spec.CPU = "pentium4"
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
case "amd64":
spec.CPU = "x86-64"
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
case "arm":
spec.CPU = "generic"
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
switch strings.Split(triple, "-")[0] {
case "armv5":
spec.Features = "+armv5t,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
case "armv6":
spec.Features = "+armv6,+dsp,+fp64,+strict-align,+vfp2,+vfp2sp,-aes,-d32,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-neon,-sha2,-thumb-mode,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
case "armv7":
spec.Features = "+armv7-a,+d32,+dsp,+fp64,+neon,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-aes,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-sha2,-thumb-mode,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
}
case "arm64":
spec.CPU = "generic"
if goos == "darwin" {
spec.Features = "+fp-armv8,+neon"
} else if goos == "windows" {
spec.Features = "+fp-armv8,+neon,-fmv"
} else { // linux
spec.Features = "+fp-armv8,+neon,-fmv,-outline-atomics"
}
case "wasm":
spec.CPU = "generic"
spec.Features = "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext"
spec.BuildTags = append(spec.BuildTags, "tinygo.wasm")
spec.CFlags = append(spec.CFlags,
"-mbulk-memory",
"-mnontrapping-fptoint",
"-msign-ext",
)
}
if goos == "darwin" {
spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip")
spec.Linker = "ld.lld"
spec.Libc = "darwin-libSystem"
arch := strings.Split(triple, "-")[0]
platformVersion := strings.TrimPrefix(strings.Split(triple, "-")[2], "macosx")
spec.LDFlags = append(spec.LDFlags,
"-flavor", "darwin",
"-dead_strip",
"-arch", arch,
"-platform_version", "macos", platformVersion, platformVersion,
)
} else if goos == "linux" {
spec.Linker = "ld.lld"
spec.RTLib = "compiler-rt"
spec.Libc = "musl"
spec.LDFlags = append(spec.LDFlags, "--gc-sections")
if goarch == "arm64" {
// Disable outline atomics. For details, see:
// https://cpufun.substack.com/p/atomics-in-aarch64
// A better way would be to fully support outline atomics, which
// makes atomics slightly more efficient on systems with many cores.
// But the instructions are only supported on newer aarch64 CPUs, so
// this feature is normally put in a system library which does
// feature detection for you.
// We take the lazy way out and simply disable this feature, instead
// of enabling it in compiler-rt (which is a bit more complicated).
// We don't really need this feature anyway as we don't even support
// proper threading.
spec.CFlags = append(spec.CFlags, "-mno-outline-atomics")
}
} else if goos == "windows" {
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 goarch {
case "amd64":
spec.LDFlags = append(spec.LDFlags,
"-m", "i386pep",
"--image-base", "0x400000",
)
case "arm64":
spec.LDFlags = append(spec.LDFlags,
"-m", "arm64pe",
)
}
spec.LDFlags = append(spec.LDFlags,
"-Bdynamic",
"--gc-sections",
"--no-insert-timestamp",
"--no-dynamicbase",
)
} else if goos == "wasip1" {
spec.GC = "" // use default GC
spec.Scheduler = "asyncify"
spec.Linker = "wasm-ld"
spec.RTLib = "compiler-rt"
spec.Libc = "wasi-libc"
spec.DefaultStackSize = 1024 * 64 // 64kB
spec.LDFlags = append(spec.LDFlags,
"--stack-first",
"--no-demangle",
)
spec.Emulator = "wasmtime --dir={tmpDir}::/tmp {}"
spec.ExtraFiles = append(spec.ExtraFiles,
"src/runtime/asm_tinygowasm.S",
"src/internal/task/task_asyncify_wasm.S",
)
} else {
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
}
if goarch != "wasm" {
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/gc_"+goarch+".S")
suffix := ""
if goos == "windows" && goarch == "amd64" {
// Windows uses a different calling convention on amd64 from other
// operating systems so we need separate assembly files.
suffix = "_windows"
}
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/asm_"+goarch+suffix+".S")
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_stack_"+goarch+suffix+".S")
}
if goarch != runtime.GOARCH {
// Some educated guesses as to how to invoke helper programs.
spec.GDB = []string{"gdb-multiarch"}
if goarch == "arm" && goos == "linux" {
spec.CFlags = append(spec.CFlags, "--sysroot=/usr/arm-linux-gnueabihf")
spec.Linker = "arm-linux-gnueabihf-gcc"
spec.Emulator = []string{"qemu-arm", "-L", "/usr/arm-linux-gnueabihf"}
if goos == "linux" {
switch goarch {
case "386":
// amd64 can _usually_ run 32-bit programs, so skip the emulator in that case.
if runtime.GOARCH != "amd64" {
spec.Emulator = "qemu-i386 {}"
}
case "amd64":
spec.Emulator = "qemu-x86_64 {}"
case "arm":
spec.Emulator = "qemu-arm {}"
case "arm64":
spec.Emulator = "qemu-aarch64 {}"
}
}
if goarch == "arm64" && goos == "linux" {
spec.CFlags = append(spec.CFlags, "--sysroot=/usr/aarch64-linux-gnu")
spec.Linker = "aarch64-linux-gnu-gcc"
spec.Emulator = []string{"qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"}
}
if goarch == "386" && runtime.GOARCH == "amd64" {
spec.CFlags = append(spec.CFlags, "-m32")
spec.LDFlags = append(spec.LDFlags, "-m32")
}
if goos != runtime.GOOS {
if goos == "windows" {
spec.Emulator = "wine {}"
}
}
return &spec, nil
+9 -12
View File
@@ -1,22 +1,24 @@
package compileopts
import (
"errors"
"io/fs"
"reflect"
"testing"
)
func TestLoadTarget(t *testing.T) {
_, err := LoadTarget("arduino")
_, err := LoadTarget(&Options{Target: "arduino"})
if err != nil {
t.Error("LoadTarget test failed:", err)
}
_, err = LoadTarget("notexist")
_, err = LoadTarget(&Options{Target: "notexist"})
if err == nil {
t.Error("LoadTarget should have failed with non existing target")
}
if err.Error() != "expected a full LLVM target or a custom target in -target flag" {
if !errors.Is(err, fs.ErrNotExist) {
t.Error("LoadTarget failed for wrong reason:", err)
}
}
@@ -26,9 +28,8 @@ func TestOverrideProperties(t *testing.T) {
base := &TargetSpec{
GOOS: "baseGoos",
CPU: "baseCpu",
Features: []string{"bf1", "bf2"},
CFlags: []string{"-base-foo", "-base-bar"},
BuildTags: []string{"bt1", "bt2"},
Emulator: []string{"be1", "be2"},
DefaultStackSize: 42,
AutoStackSize: &baseAutoStackSize,
}
@@ -36,8 +37,7 @@ func TestOverrideProperties(t *testing.T) {
child := &TargetSpec{
GOOS: "",
CPU: "chlidCpu",
Features: []string{"cf1", "cf2"},
Emulator: []string{"ce1", "ce2"},
CFlags: []string{"-child-foo", "-child-bar"},
AutoStackSize: &childAutoStackSize,
DefaultStackSize: 64,
}
@@ -50,15 +50,12 @@ func TestOverrideProperties(t *testing.T) {
if base.CPU != "chlidCpu" {
t.Errorf("Overriding failed : got %v", base.CPU)
}
if !reflect.DeepEqual(base.Features, []string{"cf1", "cf2", "bf1", "bf2"}) {
t.Errorf("Overriding failed : got %v", base.Features)
if !reflect.DeepEqual(base.CFlags, []string{"-base-foo", "-base-bar", "-child-foo", "-child-bar"}) {
t.Errorf("Overriding failed : got %v", base.CFlags)
}
if !reflect.DeepEqual(base.BuildTags, []string{"bt1", "bt2"}) {
t.Errorf("Overriding failed : got %v", base.BuildTags)
}
if !reflect.DeepEqual(base.Emulator, []string{"ce1", "ce2"}) {
t.Errorf("Overriding failed : got %v", base.Emulator)
}
if *base.AutoStackSize != false {
t.Errorf("Overriding failed : got %v", base.AutoStackSize)
}
+65
View File
@@ -0,0 +1,65 @@
package compiler
// This file defines alias functions for functions that are normally defined in
// Go assembly.
//
// The Go toolchain defines many performance critical functions in assembly
// instead of plain Go. This is a problem for TinyGo as it currently (as of
// august 2021) is not able to compile these assembly files and even if it
// could, it would not be able to make use of them for many targets that are
// supported by TinyGo (baremetal RISC-V, AVR, etc). Therefore, many of these
// functions are aliased to their generic Go implementation.
// This results in slower than possible implementations, but at least they are
// usable.
import "tinygo.org/x/go-llvm"
var stdlibAliases = map[string]string{
// crypto packages
"crypto/ed25519/internal/edwards25519/field.feMul": "crypto/ed25519/internal/edwards25519/field.feMulGeneric",
"crypto/internal/edwards25519/field.feSquare": "crypto/ed25519/internal/edwards25519/field.feSquareGeneric",
"crypto/md5.block": "crypto/md5.blockGeneric",
"crypto/sha1.block": "crypto/sha1.blockGeneric",
"crypto/sha1.blockAMD64": "crypto/sha1.blockGeneric",
"crypto/sha256.block": "crypto/sha256.blockGeneric",
"crypto/sha512.blockAMD64": "crypto/sha512.blockGeneric",
// AES
"crypto/aes.decryptBlockAsm": "crypto/aes.decryptBlock",
"crypto/aes.encryptBlockAsm": "crypto/aes.encryptBlock",
// math package
"math.archHypot": "math.hypot",
"math.archMax": "math.max",
"math.archMin": "math.min",
"math.archModf": "math.modf",
}
// createAlias implements the function (in the builder) as a call to the alias
// function.
func (b *builder) createAlias(alias llvm.Value) {
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
b.llvmFn.SetUnnamedAddr(true)
if b.Debug {
if b.fn.Syntax() != nil {
// Create debug info file if present.
b.difunc = b.attachDebugInfo(b.fn)
}
pos := b.program.Fset.Position(b.fn.Pos())
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
}
entryBlock := b.ctx.AddBasicBlock(b.llvmFn, "entry")
b.SetInsertPointAtEnd(entryBlock)
if b.llvmFn.Type() != alias.Type() {
b.addError(b.fn.Pos(), "alias function should have the same type as aliasee "+alias.Name())
b.CreateUnreachable()
return
}
result := b.CreateCall(alias.GlobalValueType(), alias, b.llvmFn.Params(), "")
if result.Type().TypeKind() == llvm.VoidTypeKind {
b.CreateRetVoid()
} else {
b.CreateRet(result)
}
}
+92 -48
View File
@@ -15,22 +15,16 @@ import (
// createLookupBoundsCheck emits a bounds check before doing a lookup into a
// slice. This is required by the Go language spec: an index out of bounds must
// cause a panic.
func (b *builder) createLookupBoundsCheck(arrayLen, index llvm.Value, indexType types.Type) {
// The caller should make sure that index is at least as big as arrayLen.
func (b *builder) createLookupBoundsCheck(arrayLen, index llvm.Value) {
if b.info.nobounds {
// The //go:nobounds pragma was added to the function to avoid bounds
// checking.
return
}
if index.Type().IntTypeWidth() < arrayLen.Type().IntTypeWidth() {
// Sometimes, the index can be e.g. an uint8 or int8, and we have to
// correctly extend that type.
if indexType.Underlying().(*types.Basic).Info()&types.IsUnsigned == 0 {
index = b.CreateZExt(index, arrayLen.Type(), "")
} else {
index = b.CreateSExt(index, arrayLen.Type(), "")
}
} else if index.Type().IntTypeWidth() > arrayLen.Type().IntTypeWidth() {
// Extend arrayLen if it's too small.
if index.Type().IntTypeWidth() > arrayLen.Type().IntTypeWidth() {
// The index is bigger than the array length type, so extend it.
arrayLen = b.CreateZExt(arrayLen, index.Type(), "")
}
@@ -70,27 +64,9 @@ func (b *builder) createSliceBoundsCheck(capacity, low, high, max llvm.Value, lo
}
// Extend low and high to be the same size as capacity.
if low.Type().IntTypeWidth() < capacityType.IntTypeWidth() {
if lowType.Info()&types.IsUnsigned != 0 {
low = b.CreateZExt(low, capacityType, "")
} else {
low = b.CreateSExt(low, capacityType, "")
}
}
if high.Type().IntTypeWidth() < capacityType.IntTypeWidth() {
if highType.Info()&types.IsUnsigned != 0 {
high = b.CreateZExt(high, capacityType, "")
} else {
high = b.CreateSExt(high, capacityType, "")
}
}
if max.Type().IntTypeWidth() < capacityType.IntTypeWidth() {
if maxType.Info()&types.IsUnsigned != 0 {
max = b.CreateZExt(max, capacityType, "")
} else {
max = b.CreateSExt(max, capacityType, "")
}
}
low = b.extendInteger(low, lowType, capacityType)
high = b.extendInteger(high, highType, capacityType)
max = b.extendInteger(max, maxType, capacityType)
// Now do the bounds check: low > high || high > capacity
outOfBounds1 := b.CreateICmp(llvm.IntUGT, low, high, "slice.lowhigh")
@@ -101,6 +77,50 @@ func (b *builder) createSliceBoundsCheck(capacity, low, high, max llvm.Value, lo
b.createRuntimeAssert(outOfBounds, "slice", "slicePanic")
}
// createSliceToArrayPointerCheck adds a check for slice-to-array pointer
// conversions. This conversion was added in Go 1.17. For details, see:
// https://tip.golang.org/ref/spec#Conversions_from_slice_to_array_pointer
func (b *builder) createSliceToArrayPointerCheck(sliceLen llvm.Value, arrayLen int64) {
// From the spec:
// > If the length of the slice is less than the length of the array, a
// > run-time panic occurs.
arrayLenValue := llvm.ConstInt(b.uintptrType, uint64(arrayLen), false)
isLess := b.CreateICmp(llvm.IntULT, sliceLen, arrayLenValue, "")
b.createRuntimeAssert(isLess, "slicetoarray", "sliceToArrayPointerPanic")
}
// createUnsafeSliceStringCheck inserts a runtime check used for unsafe.Slice
// and unsafe.String. This function must panic if the ptr/len parameters are
// invalid.
func (b *builder) createUnsafeSliceStringCheck(name string, ptr, len llvm.Value, elementType llvm.Type, lenType *types.Basic) {
// From the documentation of unsafe.Slice and unsafe.String:
// > At run time, if len is negative, or if ptr is nil and len is not
// > zero, a run-time panic occurs.
// However, in practice, it is also necessary to check that the length is
// not too big that a GEP wouldn't be possible without wrapping the pointer.
// These two checks (non-negative and not too big) can be merged into one
// using an unsiged greater than.
// Make sure the len value is at least as big as a uintptr.
len = b.extendInteger(len, lenType, b.uintptrType)
// Determine the maximum slice size, and therefore the maximum value of the
// len parameter.
maxSize := b.maxSliceSize(elementType)
maxSizeValue := llvm.ConstInt(len.Type(), maxSize, false)
// Do the check. By using unsigned greater than for the length check, signed
// negative values are also checked (which are very large numbers when
// interpreted as signed values).
zero := llvm.ConstInt(len.Type(), 0, false)
lenOutOfBounds := b.CreateICmp(llvm.IntUGT, len, maxSizeValue, "")
ptrIsNil := b.CreateICmp(llvm.IntEQ, ptr, llvm.ConstNull(ptr.Type()), "")
lenIsNotZero := b.CreateICmp(llvm.IntNE, len, zero, "")
assert := b.CreateAnd(ptrIsNil, lenIsNotZero, "")
assert = b.CreateOr(assert, lenOutOfBounds, "")
b.createRuntimeAssert(assert, name, "unsafeSlicePanic")
}
// createChanBoundsCheck creates a bounds check before creating a new channel to
// check that the value is not too big for runtime.chanMake.
func (b *builder) createChanBoundsCheck(elementSize uint64, bufSize llvm.Value, bufSizeType *types.Basic, pos token.Pos) {
@@ -110,23 +130,12 @@ func (b *builder) createChanBoundsCheck(elementSize uint64, bufSize llvm.Value,
return
}
// Check whether the bufSize parameter must be cast to a wider integer for
// comparison.
if bufSize.Type().IntTypeWidth() < b.uintptrType.IntTypeWidth() {
if bufSizeType.Info()&types.IsUnsigned != 0 {
// Unsigned, so zero-extend to uint type.
bufSizeType = types.Typ[types.Uint]
bufSize = b.CreateZExt(bufSize, b.intType, "")
} else {
// Signed, so sign-extend to int type.
bufSizeType = types.Typ[types.Int]
bufSize = b.CreateSExt(bufSize, b.intType, "")
}
}
// Make sure bufSize is at least as big as maxBufSize (an uintptr).
bufSize = b.extendInteger(bufSize, bufSizeType, b.uintptrType)
// Calculate (^uintptr(0)) >> 1, which is the max value that fits in an
// uintptr if uintptrs were signed.
maxBufSize := llvm.ConstLShr(llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)), llvm.ConstInt(b.uintptrType, 1, false))
maxBufSize := b.CreateLShr(llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)), llvm.ConstInt(b.uintptrType, 1, false), "")
if elementSize > maxBufSize.ZExtValue() {
b.addError(pos, fmt.Sprintf("channel element type is too big (%v bytes)", elementSize))
return
@@ -137,11 +146,11 @@ func (b *builder) createChanBoundsCheck(elementSize uint64, bufSize llvm.Value,
}
// Make the maxBufSize actually the maximum allowed value (in number of
// elements in the channel buffer).
maxBufSize = llvm.ConstUDiv(maxBufSize, llvm.ConstInt(b.uintptrType, elementSize, false))
maxBufSize = b.CreateUDiv(maxBufSize, llvm.ConstInt(b.uintptrType, elementSize, false), "")
// Make sure maxBufSize has the same type as bufSize.
if maxBufSize.Type() != bufSize.Type() {
maxBufSize = llvm.ConstZExt(maxBufSize, bufSize.Type())
maxBufSize = b.CreateZExt(maxBufSize, bufSize.Type(), "")
}
// Do the check for a too large (or negative) buffer size.
@@ -162,6 +171,10 @@ func (b *builder) createNilCheck(inst ssa.Value, ptr llvm.Value, blockPrefix str
case *ssa.Alloc:
// An alloc is never nil.
return
case *ssa.FreeVar:
// A free variable is allocated in a parent function and is thus never
// nil.
return
case *ssa.IndexAddr:
// This pointer is the result of an index operation into a slice or
// array. Such slices/arrays are already bounds checked so the pointer
@@ -202,6 +215,19 @@ func (b *builder) createNegativeShiftCheck(shift llvm.Value) {
b.createRuntimeAssert(isNegative, "shift", "negativeShiftPanic")
}
// createDivideByZeroCheck asserts that y is not zero. If it is, a runtime panic
// will be emitted. This follows the Go specification which says that a divide
// by zero must cause a run time panic.
func (b *builder) createDivideByZeroCheck(y llvm.Value) {
if b.info.nobounds {
return
}
// isZero = y == 0
isZero := b.CreateICmp(llvm.IntEQ, y, llvm.ConstInt(y.Type(), 0, false), "")
b.createRuntimeAssert(isZero, "divbyzero", "divideByZeroPanic")
}
// createRuntimeAssert is a common function to create a new branch on an assert
// bool, calling an assert func if the assert value is true (1).
func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc string) {
@@ -215,8 +241,10 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
}
}
// Put the fault block at the end of the function and the next block at the
// current insert position.
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
nextBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".next")
nextBlock := b.insertBasicBlock(blockPrefix + ".next")
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
// Now branch to the out-of-bounds or the regular block.
@@ -230,3 +258,19 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
// Ok: assert didn't trigger so continue normally.
b.SetInsertPointAtEnd(nextBlock)
}
// extendInteger extends the value to at least targetType using a zero or sign
// extend. The resulting value is not truncated: it may still be bigger than
// targetType.
func (b *builder) extendInteger(value llvm.Value, valueType types.Type, targetType llvm.Type) llvm.Value {
if value.Type().IntTypeWidth() < targetType.IntTypeWidth() {
if valueType.Underlying().(*types.Basic).Info()&types.IsUnsigned != 0 {
// Unsigned, so zero-extend to the target type.
value = b.CreateZExt(value, targetType, "")
} else {
// Signed, so sign-extend to the target type.
value = b.CreateSExt(value, targetType, "")
}
}
return value
}
+37 -57
View File
@@ -1,84 +1,64 @@
package compiler
import (
"fmt"
"strings"
"golang.org/x/tools/go/ssa"
"tinygo.org/x/go-llvm"
)
// createAtomicOp lowers an atomic library call by lowering it as an LLVM atomic
// operation. It returns the result of the operation and true if the call could
// be lowered inline, and false otherwise.
func (b *builder) createAtomicOp(call *ssa.CallCommon) (llvm.Value, bool) {
name := call.Value.(*ssa.Function).Name()
// createAtomicOp lowers a sync/atomic function by lowering it as an LLVM atomic
// operation. It returns the result of the operation, or a zero llvm.Value if
// the result is void.
func (b *builder) createAtomicOp(name string) llvm.Value {
switch name {
case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
ptr := b.getValue(call.Args[0])
val := b.getValue(call.Args[1])
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
val := b.getValue(b.fn.Params[1], getPos(b.fn))
if strings.HasPrefix(b.Triple, "avr") {
// AtomicRMW does not work on AVR as intended:
// - There are some register allocation issues (fixed by https://reviews.llvm.org/D97127 which is not yet in a usable LLVM release)
// - The result is the new value instead of the old value
vType := val.Type()
name := fmt.Sprintf("__sync_fetch_and_add_%d", vType.IntTypeWidth()/8)
fn := b.mod.NamedFunction(name)
if fn.IsNil() {
fn = llvm.AddFunction(b.mod, name, llvm.FunctionType(vType, []llvm.Type{ptr.Type(), vType}, false))
}
oldVal := b.createCall(fn.GlobalValueType(), fn, []llvm.Value{ptr, val}, "")
// Return the new value, not the original value returned.
return b.CreateAdd(oldVal, val, "")
}
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAdd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
// Return the new value, not the original value returned by atomicrmw.
return b.CreateAdd(oldVal, val, ""), true
return b.CreateAdd(oldVal, val, "")
case "SwapInt32", "SwapInt64", "SwapUint32", "SwapUint64", "SwapUintptr", "SwapPointer":
ptr := b.getValue(call.Args[0])
val := b.getValue(call.Args[1])
isPointer := val.Type().TypeKind() == llvm.PointerTypeKind
if isPointer {
// atomicrmw only supports integers, so cast to an integer.
val = b.CreatePtrToInt(val, b.uintptrType, "")
ptr = b.CreateBitCast(ptr, llvm.PointerType(val.Type(), 0), "")
}
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
val := b.getValue(b.fn.Params[1], getPos(b.fn))
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpXchg, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
if isPointer {
oldVal = b.CreateIntToPtr(oldVal, b.i8ptrType, "")
}
return oldVal, true
return oldVal
case "CompareAndSwapInt32", "CompareAndSwapInt64", "CompareAndSwapUint32", "CompareAndSwapUint64", "CompareAndSwapUintptr", "CompareAndSwapPointer":
ptr := b.getValue(call.Args[0])
old := b.getValue(call.Args[1])
newVal := b.getValue(call.Args[2])
if strings.HasSuffix(name, "64") {
arch := strings.Split(b.Triple, "-")[0]
if strings.HasPrefix(arch, "arm") && strings.HasSuffix(arch, "m") {
// Work around a bug in LLVM, at least LLVM 11:
// https://reviews.llvm.org/D95891
// Check for armv6m, armv7, armv7em, and perhaps others.
// See also: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html
compareAndSwap := b.mod.NamedFunction("__sync_val_compare_and_swap_8")
if compareAndSwap.IsNil() {
// Declare the function if it isn't already declared.
i64Type := b.ctx.Int64Type()
fnType := llvm.FunctionType(i64Type, []llvm.Type{llvm.PointerType(i64Type, 0), i64Type, i64Type}, false)
compareAndSwap = llvm.AddFunction(b.mod, "__sync_val_compare_and_swap_8", fnType)
}
actualOldValue := b.CreateCall(compareAndSwap, []llvm.Value{ptr, old, newVal}, "")
// The __sync_val_compare_and_swap_8 function returns the old
// value. However, we shouldn't return the old value, we should
// return whether the compare/exchange was successful. This is
// easily done by comparing the returned (actual) old value with
// the expected old value passed to
// __sync_val_compare_and_swap_8.
swapped := b.CreateICmp(llvm.IntEQ, old, actualOldValue, "")
return swapped, true
}
}
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
old := b.getValue(b.fn.Params[1], getPos(b.fn))
newVal := b.getValue(b.fn.Params[2], getPos(b.fn))
tuple := b.CreateAtomicCmpXchg(ptr, old, newVal, llvm.AtomicOrderingSequentiallyConsistent, llvm.AtomicOrderingSequentiallyConsistent, true)
swapped := b.CreateExtractValue(tuple, 1, "")
return swapped, true
return swapped
case "LoadInt32", "LoadInt64", "LoadUint32", "LoadUint64", "LoadUintptr", "LoadPointer":
ptr := b.getValue(call.Args[0])
val := b.CreateLoad(ptr, "")
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
val := b.CreateLoad(b.getLLVMType(b.fn.Signature.Results().At(0).Type()), ptr, "")
val.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
val.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
return val, true
return val
case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer":
ptr := b.getValue(call.Args[0])
val := b.getValue(call.Args[1])
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
val := b.getValue(b.fn.Params[1], getPos(b.fn))
store := b.CreateStore(val, ptr)
store.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
store.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
return store, true
return llvm.Value{}
default:
return llvm.Value{}, false
b.addError(b.fn.Pos(), "unknown atomic operation: "+b.fn.Name())
return llvm.Value{}
}
}
+67 -46
View File
@@ -20,7 +20,7 @@ const maxFieldsPerParam = 3
type paramInfo struct {
llvmType llvm.Type
name string // name, possibly with suffixes for e.g. struct fields
flags paramFlags
elemSize uint64 // size of pointer element type, or 0 if this isn't a pointer
}
// paramFlags identifies parameter attributes for flags. Most importantly, it
@@ -33,27 +33,58 @@ const (
paramIsDeferenceableOrNull = 1 << iota
)
// createCall creates a new call to runtime.<fnName> with the given arguments.
func (b *builder) createRuntimeCall(fnName string, args []llvm.Value, name string) llvm.Value {
fn := b.program.ImportedPackage("runtime").Members[fnName].(*ssa.Function)
llvmFn := b.getFunction(fn)
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
// createRuntimeInvoke instead.
func (b *builder) createRuntimeCallCommon(fnName string, args []llvm.Value, name string, isInvoke bool) llvm.Value {
member := b.program.ImportedPackage("runtime").Members[fnName]
if member == nil {
panic("unknown runtime call: " + fnName)
}
fn := member.(*ssa.Function)
fnType, llvmFn := b.getFunction(fn)
if llvmFn.IsNil() {
panic("trying to call non-existent function: " + fn.RelString(nil))
}
args = append(args, llvm.Undef(b.i8ptrType)) // unused context parameter
args = append(args, llvm.ConstPointerNull(b.i8ptrType)) // coroutine handle
return b.createCall(llvmFn, args, name)
args = append(args, llvm.Undef(b.dataPtrType)) // unused context parameter
if isInvoke {
return b.createInvoke(fnType, llvmFn, args, name)
}
return b.createCall(fnType, llvmFn, args, name)
}
// createRuntimeCall creates a new call to runtime.<fnName> with the given
// arguments.
func (b *builder) createRuntimeCall(fnName string, args []llvm.Value, name string) llvm.Value {
return b.createRuntimeCallCommon(fnName, args, name, false)
}
// createRuntimeInvoke creates a new call to runtime.<fnName> with the given
// arguments. If the runtime call panics, control flow is diverted to the
// landing pad block.
// Note that "invoke" here is meant in the LLVM sense (a call that can
// panic/throw), not in the Go sense (an interface method call).
func (b *builder) createRuntimeInvoke(fnName string, args []llvm.Value, name string) llvm.Value {
return b.createRuntimeCallCommon(fnName, args, name, true)
}
// createCall creates a call to the given function with the arguments possibly
// expanded.
func (b *builder) createCall(fn llvm.Value, args []llvm.Value, name string) llvm.Value {
func (b *builder) createCall(fnType llvm.Type, fn llvm.Value, args []llvm.Value, name string) llvm.Value {
expanded := make([]llvm.Value, 0, len(args))
for _, arg := range args {
fragments := b.expandFormalParam(arg)
expanded = append(expanded, fragments...)
}
return b.CreateCall(fn, expanded, name)
return b.CreateCall(fnType, fn, expanded, name)
}
// createInvoke is like createCall but continues execution at the landing pad if
// the call resulted in a panic.
func (b *builder) createInvoke(fnType llvm.Type, fn llvm.Value, args []llvm.Value, name string) llvm.Value {
if b.hasDeferFrame() {
b.createInvokeCheckpoint()
}
return b.createCall(fnType, fn, args, name)
}
// Expand an argument type to a list that can be used in a function call
@@ -63,19 +94,13 @@ func (c *compilerContext) expandFormalParamType(t llvm.Type, name string, goType
case llvm.StructTypeKind:
fieldInfos := c.flattenAggregateType(t, name, goType)
if len(fieldInfos) <= maxFieldsPerParam {
// managed to expand this parameter
return fieldInfos
} else {
// failed to lower
}
// failed to expand this parameter: too many fields
}
// TODO: split small arrays
return []paramInfo{
{
llvmType: t,
name: name,
flags: getTypeFlags(goType),
},
}
return []paramInfo{c.getParamInfo(t, name, goType)}
}
// expandFormalParamOffsets returns a list of offsets from the start of an
@@ -125,7 +150,6 @@ func (b *builder) expandFormalParam(v llvm.Value) []llvm.Value {
// Try to flatten a struct type to a list of types. Returns a 1-element slice
// with the passed in type if this is not possible.
func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType types.Type) []paramInfo {
typeFlags := getTypeFlags(goType)
switch t.TypeKind() {
case llvm.StructTypeKind:
var paramInfos []paramInfo
@@ -156,40 +180,37 @@ func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType
}
}
subInfos := c.flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i))
for i := range subInfos {
subInfos[i].flags |= typeFlags
}
paramInfos = append(paramInfos, subInfos...)
}
return paramInfos
default:
return []paramInfo{
{
llvmType: t,
name: name,
flags: typeFlags,
},
}
return []paramInfo{c.getParamInfo(t, name, goType)}
}
}
// getTypeFlags returns the type flags for a given type. It will not recurse
// into sub-types (such as in structs).
func getTypeFlags(t types.Type) paramFlags {
if t == nil {
return 0
// getParamInfo collects information about a parameter. For example, if this
// parameter is pointer-like, it will also store the element type for the
// dereferenceable_or_null attribute.
func (c *compilerContext) getParamInfo(t llvm.Type, name string, goType types.Type) paramInfo {
info := paramInfo{
llvmType: t,
name: name,
}
switch t.Underlying().(type) {
case *types.Pointer:
// Pointers in Go must either point to an object or be nil.
return paramIsDeferenceableOrNull
case *types.Chan, *types.Map:
// Channels and maps are implemented as pointers pointing to some
// object, and follow the same rules as *types.Pointer.
return paramIsDeferenceableOrNull
default:
return 0
if goType != nil {
switch underlying := goType.Underlying().(type) {
case *types.Pointer:
// Pointers in Go must either point to an object or be nil.
info.elemSize = c.targetData.TypeAllocSize(c.getLLVMType(underlying.Elem()))
case *types.Chan:
// Channels are implemented simply as a *runtime.channel.
info.elemSize = c.targetData.TypeAllocSize(c.getLLVMRuntimeType("channel"))
case *types.Map:
// Maps are similar to channels: they are implemented as a
// *runtime.hashmap.
info.elemSize = c.targetData.TypeAllocSize(c.getLLVMRuntimeType("hashmap"))
}
}
return info
}
// extractSubfield extracts a field from a struct, or returns null if this is
@@ -212,7 +233,7 @@ func extractSubfield(t types.Type, field int) types.Type {
}
}
// flattenAggregateTypeOffset returns the offsets from the start of an object of
// flattenAggregateTypeOffsets returns the offsets from the start of an object of
// type t if this object were flattened like in flattenAggregate. Used together
// with flattenAggregate to know the start indices of each value in the
// non-flattened object.
+55 -40
View File
@@ -14,7 +14,7 @@ import (
func (b *builder) createMakeChan(expr *ssa.MakeChan) llvm.Value {
elementSize := b.targetData.TypeAllocSize(b.getLLVMType(expr.Type().Underlying().(*types.Chan).Elem()))
elementSizeValue := llvm.ConstInt(b.uintptrType, elementSize, false)
bufSize := b.getValue(expr.Size)
bufSize := b.getValue(expr.Size, getPos(expr))
b.createChanBoundsCheck(elementSize, bufSize, expr.Size.Type().Underlying().(*types.Basic), expr.Pos())
if bufSize.Type().IntTypeWidth() < b.uintptrType.IntTypeWidth() {
bufSize = b.CreateZExt(bufSize, b.uintptrType, "")
@@ -27,46 +27,65 @@ func (b *builder) createMakeChan(expr *ssa.MakeChan) llvm.Value {
// createChanSend emits a pseudo chan send operation. It is lowered to the
// actual channel send operation during goroutine lowering.
func (b *builder) createChanSend(instr *ssa.Send) {
ch := b.getValue(instr.Chan)
chanValue := b.getValue(instr.X)
ch := b.getValue(instr.Chan, getPos(instr))
chanValue := b.getValue(instr.X, getPos(instr))
// store value-to-send
valueType := b.getLLVMType(instr.X.Type())
valueAlloca, valueAllocaCast, valueAllocaSize := b.createTemporaryAlloca(valueType, "chan.value")
b.CreateStore(chanValue, valueAlloca)
isZeroSize := b.targetData.TypeAllocSize(valueType) == 0
var valueAlloca, valueAllocaSize llvm.Value
if isZeroSize {
valueAlloca = llvm.ConstNull(b.dataPtrType)
} else {
valueAlloca, valueAllocaSize = b.createTemporaryAlloca(valueType, "chan.value")
b.CreateStore(chanValue, valueAlloca)
}
// Allocate blockedlist buffer.
channelBlockedList := b.mod.GetTypeByName("runtime.channelBlockedList")
channelBlockedListAlloca, channelBlockedListAllocaCast, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
channelBlockedList := b.getLLVMRuntimeType("channelBlockedList")
channelBlockedListAlloca, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
// Do the send.
b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAllocaCast, channelBlockedListAlloca}, "")
b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAlloca, channelBlockedListAlloca}, "")
// End the lifetime of the allocas.
// This also works around a bug in CoroSplit, at least in LLVM 8:
// https://bugs.llvm.org/show_bug.cgi?id=41742
b.emitLifetimeEnd(channelBlockedListAllocaCast, channelBlockedListAllocaSize)
b.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
b.emitLifetimeEnd(channelBlockedListAlloca, channelBlockedListAllocaSize)
if !isZeroSize {
b.emitLifetimeEnd(valueAlloca, valueAllocaSize)
}
}
// createChanRecv emits a pseudo chan receive operation. It is lowered to the
// actual channel receive operation during goroutine lowering.
func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value {
valueType := b.getLLVMType(unop.X.Type().Underlying().(*types.Chan).Elem())
ch := b.getValue(unop.X)
ch := b.getValue(unop.X, getPos(unop))
// Allocate memory to receive into.
valueAlloca, valueAllocaCast, valueAllocaSize := b.createTemporaryAlloca(valueType, "chan.value")
isZeroSize := b.targetData.TypeAllocSize(valueType) == 0
var valueAlloca, valueAllocaSize llvm.Value
if isZeroSize {
valueAlloca = llvm.ConstNull(b.dataPtrType)
} else {
valueAlloca, valueAllocaSize = b.createTemporaryAlloca(valueType, "chan.value")
}
// Allocate blockedlist buffer.
channelBlockedList := b.mod.GetTypeByName("runtime.channelBlockedList")
channelBlockedListAlloca, channelBlockedListAllocaCast, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
channelBlockedList := b.getLLVMRuntimeType("channelBlockedList")
channelBlockedListAlloca, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
// Do the receive.
commaOk := b.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAllocaCast, channelBlockedListAlloca}, "")
received := b.CreateLoad(valueAlloca, "chan.received")
b.emitLifetimeEnd(channelBlockedListAllocaCast, channelBlockedListAllocaSize)
b.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
commaOk := b.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAlloca, channelBlockedListAlloca}, "")
var received llvm.Value
if isZeroSize {
received = llvm.ConstNull(valueType)
} else {
received = b.CreateLoad(valueType, valueAlloca, "chan.received")
b.emitLifetimeEnd(valueAlloca, valueAllocaSize)
}
b.emitLifetimeEnd(channelBlockedListAlloca, channelBlockedListAllocaSize)
if unop.CommaOk {
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{valueType, b.ctx.Int1Type()}, false))
@@ -116,11 +135,10 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
// determine the receive buffer size and alignment.
recvbufSize := uint64(0)
recvbufAlign := 0
hasReceives := false
var selectStates []llvm.Value
chanSelectStateType := b.getLLVMRuntimeType("chanSelectState")
for _, state := range expr.States {
ch := b.getValue(state.Chan)
ch := b.getValue(state.Chan, state.Pos)
selectState := llvm.ConstNull(chanSelectStateType)
selectState = b.CreateInsertValue(selectState, ch, 0, "")
switch state.Dir {
@@ -133,15 +151,13 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
if align := b.targetData.ABITypeAlignment(llvmType); align > recvbufAlign {
recvbufAlign = align
}
hasReceives = true
case types.SendOnly:
// Store this value in an alloca and put a pointer to this alloca
// in the send state.
sendValue := b.getValue(state.Send)
sendValue := b.getValue(state.Send, state.Pos)
alloca := llvmutil.CreateEntryBlockAlloca(b.Builder, sendValue.Type(), "select.send.value")
b.CreateStore(sendValue, alloca)
ptr := b.CreateBitCast(alloca, b.i8ptrType, "")
selectState = b.CreateInsertValue(selectState, ptr, 1, "")
selectState = b.CreateInsertValue(selectState, alloca, 1, "")
default:
panic("unreachable")
}
@@ -149,12 +165,12 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
}
// Create a receive buffer, where the received value will be stored.
recvbuf := llvm.Undef(b.i8ptrType)
if hasReceives {
recvbuf := llvm.Undef(b.dataPtrType)
if recvbufSize != 0 {
allocaType := llvm.ArrayType(b.ctx.Int8Type(), int(recvbufSize))
recvbufAlloca, _, _ := b.createTemporaryAlloca(allocaType, "select.recvbuf.alloca")
recvbufAlloca, _ := b.createTemporaryAlloca(allocaType, "select.recvbuf.alloca")
recvbufAlloca.SetAlignment(recvbufAlign)
recvbuf = b.CreateGEP(recvbufAlloca, []llvm.Value{
recvbuf = b.CreateGEP(allocaType, recvbufAlloca, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
}, "select.recvbuf")
@@ -162,16 +178,16 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
// Create the states slice (allocated on the stack).
statesAllocaType := llvm.ArrayType(chanSelectStateType, len(selectStates))
statesAlloca, statesI8, statesSize := b.createTemporaryAlloca(statesAllocaType, "select.states.alloca")
statesAlloca, statesSize := b.createTemporaryAlloca(statesAllocaType, "select.states.alloca")
for i, state := range selectStates {
// Set each slice element to the appropriate channel.
gep := b.CreateGEP(statesAlloca, []llvm.Value{
gep := b.CreateGEP(statesAllocaType, statesAlloca, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false),
}, "")
b.CreateStore(state, gep)
}
statesPtr := b.CreateGEP(statesAlloca, []llvm.Value{
statesPtr := b.CreateGEP(statesAllocaType, statesAlloca, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
}, "select.states")
@@ -183,9 +199,9 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
// Stack-allocate operation structures.
// If these were simply created as a slice, they would heap-allocate.
chBlockAllocaType := llvm.ArrayType(b.getLLVMRuntimeType("channelBlockedList"), len(selectStates))
chBlockAlloca, chBlockAllocaPtr, chBlockSize := b.createTemporaryAlloca(chBlockAllocaType, "select.block.alloca")
chBlockAlloca, chBlockSize := b.createTemporaryAlloca(chBlockAllocaType, "select.block.alloca")
chBlockLen := llvm.ConstInt(b.uintptrType, uint64(len(selectStates)), false)
chBlockPtr := b.CreateGEP(chBlockAlloca, []llvm.Value{
chBlockPtr := b.CreateGEP(chBlockAllocaType, chBlockAlloca, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
}, "select.block")
@@ -197,7 +213,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
}, "select.result")
// Terminate the lifetime of the operation structures.
b.emitLifetimeEnd(chBlockAllocaPtr, chBlockSize)
b.emitLifetimeEnd(chBlockAlloca, chBlockSize)
} else {
results = b.createRuntimeCall("tryChanSelect", []llvm.Value{
recvbuf,
@@ -206,7 +222,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
}
// Terminate the lifetime of the states alloca.
b.emitLifetimeEnd(statesI8, statesSize)
b.emitLifetimeEnd(statesAlloca, statesSize)
// The result value does not include all the possible received values,
// because we can't load them in advance. Instead, the *ssa.Extract
@@ -228,7 +244,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
func (b *builder) getChanSelectResult(expr *ssa.Extract) llvm.Value {
if expr.Index == 0 {
// index
value := b.getValue(expr.Tuple)
value := b.getValue(expr.Tuple, getPos(expr))
index := b.CreateExtractValue(value, expr.Index, "")
if index.Type().IntTypeWidth() < b.intType.IntTypeWidth() {
index = b.CreateSExt(index, b.intType, "")
@@ -236,7 +252,7 @@ func (b *builder) getChanSelectResult(expr *ssa.Extract) llvm.Value {
return index
} else if expr.Index == 1 {
// comma-ok
value := b.getValue(expr.Tuple)
value := b.getValue(expr.Tuple, getPos(expr))
return b.CreateExtractValue(value, expr.Index, "")
} else {
// Select statements are (index, ok, ...) where ... is a number of
@@ -245,8 +261,7 @@ func (b *builder) getChanSelectResult(expr *ssa.Extract) llvm.Value {
// receive can proceed at a time) so we'll get that alloca, bitcast
// it to the correct type, and dereference it.
recvbuf := b.selectRecvBuf[expr.Tuple.(*ssa.Select)]
typ := llvm.PointerType(b.getLLVMType(expr.Type()), 0)
ptr := b.CreateBitCast(recvbuf, typ, "")
return b.CreateLoad(ptr, "")
typ := b.getLLVMType(expr.Type())
return b.CreateLoad(typ, recvbuf, "")
}
}
+1064 -417
View File
File diff suppressed because it is too large Load Diff
+165 -65
View File
@@ -3,12 +3,13 @@ package compiler
import (
"flag"
"go/types"
"io/ioutil"
"os"
"strconv"
"strings"
"testing"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
"github.com/tinygo-org/tinygo/loader"
"tinygo.org/x/go-llvm"
)
@@ -16,101 +17,106 @@ import (
// Pass -update to go test to update the output of the test files.
var flagUpdate = flag.Bool("update", false, "update tests based on test output")
type testCase struct {
file string
target string
scheduler string
}
// Basic tests for the compiler. Build some Go files and compare the output with
// the expected LLVM IR for regression testing.
func TestCompiler(t *testing.T) {
// Check LLVM version.
llvmMajor, err := strconv.Atoi(strings.SplitN(llvm.Version, ".", 2)[0])
t.Parallel()
// Determine Go minor version (e.g. 16 in go1.16.3).
_, goMinor, err := goenv.GetGorootVersion()
if err != nil {
t.Fatal("could not parse LLVM version:", llvm.Version)
}
if llvmMajor < 11 {
// It is likely this version needs to be bumped in the future.
// The goal is to at least test the LLVM version that's used by default
// in TinyGo and (if possible without too many workarounds) also some
// previous versions.
t.Skip("compiler tests require LLVM 11 or above, got LLVM ", llvm.Version)
t.Fatal("could not read Go version:", err)
}
target, err := compileopts.LoadTarget("i686--linux")
if err != nil {
t.Fatal("failed to load target:", err)
// Determine which tests to run, depending on the Go and LLVM versions.
tests := []testCase{
{"basic.go", "", ""},
{"pointer.go", "", ""},
{"slice.go", "", ""},
{"string.go", "", ""},
{"float.go", "", ""},
{"interface.go", "", ""},
{"func.go", "", ""},
{"defer.go", "cortex-m-qemu", ""},
{"pragma.go", "", ""},
{"goroutine.go", "wasm", "asyncify"},
{"goroutine.go", "cortex-m-qemu", "tasks"},
{"channel.go", "", ""},
{"gc.go", "", ""},
{"zeromap.go", "", ""},
}
config := &compileopts.Config{
Options: &compileopts.Options{},
Target: target,
if goMinor >= 20 {
tests = append(tests, testCase{"go1.20.go", "", ""})
}
compilerConfig := &Config{
Triple: config.Triple(),
GOOS: config.GOOS(),
GOARCH: config.GOARCH(),
CodeModel: config.CodeModel(),
RelocationModel: config.RelocationModel(),
Scheduler: config.Scheduler(),
FuncImplementation: config.FuncImplementation(),
AutomaticStackSize: config.AutomaticStackSize(),
}
machine, err := NewTargetMachine(compilerConfig)
if err != nil {
t.Fatal("failed to create target machine:", err)
if goMinor >= 21 {
tests = append(tests, testCase{"go1.21.go", "", ""})
}
tests := []string{
"basic.go",
"pointer.go",
"slice.go",
"string.go",
"float.go",
"interface.go",
}
for _, tc := range tests {
name := tc.file
targetString := "wasm"
if tc.target != "" {
targetString = tc.target
name += "-" + tc.target
}
if tc.scheduler != "" {
name += "-" + tc.scheduler
}
for _, testCase := range tests {
t.Run(testCase, func(t *testing.T) {
// Load entire program AST into memory.
lprogram, err := loader.Load(config, []string{"./testdata/" + testCase}, config.ClangHeaders, types.Config{
Sizes: Sizes(machine),
})
if err != nil {
t.Fatal("failed to create target machine:", err)
t.Run(name, func(t *testing.T) {
options := &compileopts.Options{
Target: targetString,
}
err = lprogram.Parse()
if err != nil {
t.Fatalf("could not parse test case %s: %s", testCase, err)
if tc.scheduler != "" {
options.Scheduler = tc.scheduler
}
// Compile AST to IR.
program := lprogram.LoadSSA()
pkg := lprogram.MainPkg()
mod, errs := CompilePackage(testCase, pkg, program.Package(pkg.Pkg), machine, compilerConfig, false)
mod, errs := testCompilePackage(t, options, tc.file)
if errs != nil {
for _, err := range errs {
t.Log("error:", err)
t.Error(err)
}
return
}
// Optimize IR a little.
funcPasses := llvm.NewFunctionPassManagerForModule(mod)
defer funcPasses.Dispose()
funcPasses.AddInstructionCombiningPass()
funcPasses.InitializeFunc()
for fn := mod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
funcPasses.RunFunc(fn)
err := llvm.VerifyModule(mod, llvm.PrintMessageAction)
if err != nil {
t.Error(err)
}
funcPasses.FinalizeFunc()
outfile := "./testdata/" + testCase[:len(testCase)-3] + ".ll"
// Optimize IR a little.
passOptions := llvm.NewPassBuilderOptions()
defer passOptions.Dispose()
err = mod.RunPasses("instcombine", llvm.TargetMachine{}, passOptions)
if err != nil {
t.Error(err)
}
outFilePrefix := tc.file[:len(tc.file)-3]
if tc.target != "" {
outFilePrefix += "-" + tc.target
}
if tc.scheduler != "" {
outFilePrefix += "-" + tc.scheduler
}
outPath := "./testdata/" + outFilePrefix + ".ll"
// Update test if needed. Do not check the result.
if *flagUpdate {
err := ioutil.WriteFile(outfile, []byte(mod.String()), 0666)
err := os.WriteFile(outPath, []byte(mod.String()), 0666)
if err != nil {
t.Error("failed to write updated output file:", err)
}
return
}
expected, err := ioutil.ReadFile(outfile)
expected, err := os.ReadFile(outPath)
if err != nil {
t.Fatal("failed to read golden file:", err)
}
@@ -146,6 +152,12 @@ func fuzzyEqualIR(s1, s2 string) bool {
// stripped out.
func filterIrrelevantIRLines(lines []string) []string {
var out []string
llvmVersion, err := strconv.Atoi(strings.Split(llvm.Version, ".")[0])
if err != nil {
// Note: this should never happen and if it does, it will always happen
// for a particular build because llvm.Version is a constant.
panic(err)
}
for _, line := range lines {
line = strings.Split(line, ";")[0] // strip out comments/info
line = strings.TrimRight(line, "\r ") // drop '\r' on Windows and remove trailing spaces from comments
@@ -155,7 +167,95 @@ func filterIrrelevantIRLines(lines []string) []string {
if strings.HasPrefix(line, "source_filename = ") {
continue
}
if llvmVersion < 15 && strings.HasPrefix(line, "target datalayout = ") {
// The datalayout string may vary betewen LLVM versions.
// Right now test outputs are for LLVM 15 and higher.
continue
}
out = append(out, line)
}
return out
}
func TestCompilerErrors(t *testing.T) {
t.Parallel()
// Read expected errors from the test file.
var expectedErrors []string
errorsFile, err := os.ReadFile("testdata/errors.go")
if err != nil {
t.Error(err)
}
errorsFileString := strings.ReplaceAll(string(errorsFile), "\r\n", "\n")
for _, line := range strings.Split(errorsFileString, "\n") {
if strings.HasPrefix(line, "// ERROR: ") {
expectedErrors = append(expectedErrors, strings.TrimPrefix(line, "// ERROR: "))
}
}
// Compile the Go file with errors.
options := &compileopts.Options{
Target: "wasm",
}
_, errs := testCompilePackage(t, options, "errors.go")
// Check whether the actual errors match the expected errors.
expectedErrorsIdx := 0
for _, err := range errs {
err := err.(types.Error)
position := err.Fset.Position(err.Pos)
position.Filename = "errors.go" // don't use a full path
if expectedErrorsIdx >= len(expectedErrors) || expectedErrors[expectedErrorsIdx] != err.Msg {
t.Errorf("unexpected compiler error: %s: %s", position.String(), err.Msg)
continue
}
expectedErrorsIdx++
}
}
// Build a package given a number of compiler options and a file.
func testCompilePackage(t *testing.T, options *compileopts.Options, file string) (llvm.Module, []error) {
target, err := compileopts.LoadTarget(options)
if err != nil {
t.Fatal("failed to load target:", err)
}
config := &compileopts.Config{
Options: options,
Target: target,
}
compilerConfig := &Config{
Triple: config.Triple(),
Features: config.Features(),
ABI: config.ABI(),
GOOS: config.GOOS(),
GOARCH: config.GOARCH(),
CodeModel: config.CodeModel(),
RelocationModel: config.RelocationModel(),
Scheduler: config.Scheduler(),
AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.StackSize(),
NeedsStackObjects: config.NeedsStackObjects(),
}
machine, err := NewTargetMachine(compilerConfig)
if err != nil {
t.Fatal("failed to create target machine:", err)
}
defer machine.Dispose()
// Load entire program AST into memory.
lprogram, err := loader.Load(config, "./testdata/"+file, types.Config{
Sizes: Sizes(machine),
})
if err != nil {
t.Fatal("failed to create target machine:", err)
}
err = lprogram.Parse()
if err != nil {
t.Fatalf("could not parse test case %s: %s", file, err)
}
// Compile AST to IR.
program := lprogram.LoadSSA()
pkg := lprogram.MainPkg()
return CompilePackage(file, pkg, program.Package(pkg.Pkg), machine, compilerConfig, false)
}
+244 -80
View File
@@ -15,12 +15,39 @@ package compiler
import (
"go/types"
"strconv"
"github.com/tinygo-org/tinygo/compiler/llvmutil"
"golang.org/x/tools/go/ssa"
"tinygo.org/x/go-llvm"
)
// supportsRecover returns whether the compiler supports the recover() builtin
// for the current architecture.
func (b *builder) supportsRecover() bool {
switch b.archFamily() {
case "wasm32":
// Probably needs to be implemented using the exception handling
// proposal of WebAssembly:
// https://github.com/WebAssembly/exception-handling
return false
case "riscv64", "xtensa":
// TODO: add support for these architectures
return false
default:
return true
}
}
// hasDeferFrame returns whether the current function needs to catch panics and
// run defers.
func (b *builder) hasDeferFrame() bool {
if b.fn.Recover == nil {
return false
}
return b.supportsRecover()
}
// deferInitFunc sets up this function for future deferred calls. It must be
// called from within the entry block when this function contains deferred
// calls.
@@ -33,9 +60,153 @@ func (b *builder) deferInitFunc() {
b.deferBuiltinFuncs = make(map[ssa.Value]deferBuiltin)
// Create defer list pointer.
deferType := llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)
b.deferPtr = b.CreateAlloca(deferType, "deferPtr")
b.CreateStore(llvm.ConstPointerNull(deferType), b.deferPtr)
b.deferPtr = b.CreateAlloca(b.dataPtrType, "deferPtr")
b.CreateStore(llvm.ConstPointerNull(b.dataPtrType), b.deferPtr)
if b.hasDeferFrame() {
// Set up the defer frame with the current stack pointer.
// This assumes that the stack pointer doesn't move outside of the
// function prologue/epilogue (an invariant maintained by TinyGo but
// possibly broken by the C alloca function).
// The frame pointer is _not_ saved, because it is marked as clobbered
// in the setjmp-like inline assembly.
deferFrameType := b.getLLVMRuntimeType("deferFrame")
b.deferFrame = b.CreateAlloca(deferFrameType, "deferframe.buf")
stackPointer := b.readStackPointer()
b.createRuntimeCall("setupDeferFrame", []llvm.Value{b.deferFrame, stackPointer}, "")
// Create the landing pad block, which is where control transfers after
// a panic.
b.landingpad = b.ctx.AddBasicBlock(b.llvmFn, "lpad")
}
}
// createLandingPad fills in the landing pad block. This block runs the deferred
// functions and returns (by jumping to the recover block). If the function is
// still panicking after the defers are run, the panic will be re-raised in
// destroyDeferFrame.
func (b *builder) createLandingPad() {
b.SetInsertPointAtEnd(b.landingpad)
// Add debug info, if needed.
// The location used is the closing bracket of the function.
if b.Debug {
pos := b.program.Fset.Position(b.fn.Syntax().End())
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
}
b.createRunDefers()
// Continue at the 'recover' block, which returns to the parent in an
// appropriate way.
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() {
// Construct inline assembly equivalents of setjmp.
// The assembly works as follows:
// * All registers (both callee-saved and caller saved) are clobbered
// after the inline assembly returns.
// * The assembly stores the address just past the end of the assembly
// into the jump buffer.
// * The return value (eax, rax, r0, etc) is set to zero in the inline
// assembly but set to an unspecified non-zero value when jumping using
// a longjmp.
var asmString, constraints string
resultType := b.uintptrType
switch b.archFamily() {
case "i386":
asmString = `
xorl %eax, %eax
movl $$1f, 4(%ebx)
1:`
constraints = "={eax},{ebx},~{ebx},~{ecx},~{edx},~{esi},~{edi},~{ebp},~{xmm0},~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{fpsr},~{fpcr},~{flags},~{dirflag},~{memory}"
// This doesn't include the floating point stack because TinyGo uses
// newer floating point instructions.
case "x86_64":
asmString = `
leaq 1f(%rip), %rax
movq %rax, 8(%rbx)
xorq %rax, %rax
1:`
constraints = "={rax},{rbx},~{rbx},~{rcx},~{rdx},~{rsi},~{rdi},~{rbp},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{xmm0},~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{fpsr},~{fpcr},~{flags},~{dirflag},~{memory}"
// This list doesn't include AVX/AVX512 registers because TinyGo
// doesn't currently enable support for AVX instructions.
case "arm":
// Note: the following assembly takes into account that the PC is
// always 4 bytes ahead on ARM. The PC that is stored always points
// to the instruction just after the assembly fragment so that
// tinygo_longjmp lands at the correct instruction.
if b.isThumb() {
// Instructions are 2 bytes in size.
asmString = `
movs r0, #0
mov r2, pc
str r2, [r1, #4]`
} else {
// Instructions are 4 bytes in size.
asmString = `
str pc, [r1, #4]
movs r0, #0`
}
constraints = "={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}"
case "aarch64":
asmString = `
adr x2, 1f
str x2, [x1, #8]
mov x0, #0
1:
`
constraints = "={x0},{x1},~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{lr},~{q0},~{q1},~{q2},~{q3},~{q4},~{q5},~{q6},~{q7},~{q8},~{q9},~{q10},~{q11},~{q12},~{q13},~{q14},~{q15},~{q16},~{q17},~{q18},~{q19},~{q20},~{q21},~{q22},~{q23},~{q24},~{q25},~{q26},~{q27},~{q28},~{q29},~{q30},~{nzcv},~{ffr},~{vg},~{memory}"
if b.GOOS != "darwin" && b.GOOS != "windows" {
// These registers cause the following warning when compiling for
// MacOS and Windows:
// warning: inline asm clobber list contains reserved registers:
// X18, FP
// Reserved registers on the clobber list may not be preserved
// across the asm statement, and clobbering them may lead to
// undefined behaviour.
constraints += ",~{x18},~{fp}"
}
// TODO: SVE registers, which we don't use in TinyGo at the moment.
case "avr":
// Note: the Y register (R28:R29) is a fixed register and therefore
// needs to be saved manually. TODO: do this only once per function with
// a defer frame, not for every call.
resultType = b.ctx.Int8Type()
asmString = `
ldi r24, pm_lo8(1f)
ldi r25, pm_hi8(1f)
std z+2, r24
std z+3, r25
std z+4, r28
std z+5, r29
ldi r24, 0
1:`
constraints = "={r24},z,~{r0},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{r16},~{r17},~{r18},~{r19},~{r20},~{r21},~{r22},~{r23},~{r25},~{r26},~{r27}"
case "riscv32":
asmString = `
la a2, 1f
sw a2, 4(a1)
li a0, 0
1:`
constraints = "={a0},{a1},~{a1},~{a2},~{a3},~{a4},~{a5},~{a6},~{a7},~{s0},~{s1},~{s2},~{s3},~{s4},~{s5},~{s6},~{s7},~{s8},~{s9},~{s10},~{s11},~{t0},~{t1},~{t2},~{t3},~{t4},~{t5},~{t6},~{ra},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f8},~{f9},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f18},~{f19},~{f20},~{f21},~{f22},~{f23},~{f24},~{f25},~{f26},~{f27},~{f28},~{f29},~{f30},~{f31},~{memory}"
default:
// 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)
asm := llvm.InlineAsm(asmType, asmString, constraints, false, false, 0, false)
result := b.CreateCall(asmType, asm, []llvm.Value{b.deferFrame}, "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")
continueBB := b.insertBasicBlock("")
b.CreateCondBr(isZero, continueBB, b.landingpad)
b.SetInsertPointAtEnd(continueBB)
b.blockExits[b.currentBlock] = continueBB
}
// isInLoop checks if there is a path from a basic block to itself.
@@ -77,7 +248,7 @@ func isInLoop(start *ssa.BasicBlock) bool {
func (b *builder) createDefer(instr *ssa.Defer) {
// The pointer to the previous defer struct, which we will replace to
// make a linked list.
next := b.CreateLoad(b.deferPtr, "defer.next")
next := b.CreateLoad(b.dataPtrType, b.deferPtr, "defer.next")
var values []llvm.Value
valueTypes := []llvm.Type{b.uintptrType, next.Type()}
@@ -94,13 +265,13 @@ func (b *builder) createDefer(instr *ssa.Defer) {
// Collect all values to be put in the struct (starting with
// runtime._defer fields, followed by the call parameters).
itf := b.getValue(instr.Call.Value) // interface
itf := b.getValue(instr.Call.Value, getPos(instr)) // interface
typecode := b.CreateExtractValue(itf, 0, "invoke.func.typecode")
receiverValue := b.CreateExtractValue(itf, 1, "invoke.func.receiver")
values = []llvm.Value{callback, next, typecode, receiverValue}
valueTypes = append(valueTypes, b.uintptrType, b.i8ptrType)
valueTypes = append(valueTypes, b.dataPtrType, b.dataPtrType)
for _, arg := range instr.Call.Args {
val := b.getValue(arg)
val := b.getValue(arg, getPos(instr))
values = append(values, val)
valueTypes = append(valueTypes, val.Type())
}
@@ -117,7 +288,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
// runtime._defer fields).
values = []llvm.Value{callback, next}
for _, param := range instr.Call.Args {
llvmParam := b.getValue(param)
llvmParam := b.getValue(param, getPos(instr))
values = append(values, llvmParam)
valueTypes = append(valueTypes, llvmParam.Type())
}
@@ -129,7 +300,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
// pointer.
// TODO: ignore this closure entirely and put pointers to the free
// variables directly in the defer struct, avoiding a memory allocation.
closure := b.getValue(instr.Call.Value)
closure := b.getValue(instr.Call.Value, getPos(instr))
context := b.CreateExtractValue(closure, 0, "")
// Get the callback number.
@@ -145,7 +316,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
// context pointer).
values = []llvm.Value{callback, next}
for _, param := range instr.Call.Args {
llvmParam := b.getValue(param)
llvmParam := b.getValue(param, getPos(instr))
values = append(values, llvmParam)
valueTypes = append(valueTypes, llvmParam.Type())
}
@@ -157,7 +328,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
var argValues []llvm.Value
for _, arg := range instr.Call.Args {
argTypes = append(argTypes, arg.Type())
argValues = append(argValues, b.getValue(arg))
argValues = append(argValues, b.getValue(arg, getPos(instr)))
}
if _, ok := b.deferBuiltinFuncs[instr.Call.Value]; !ok {
@@ -180,7 +351,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
}
} else {
funcValue := b.getValue(instr.Call.Value)
funcValue := b.getValue(instr.Call.Value, getPos(instr))
if _, ok := b.deferExprFuncs[instr.Call.Value]; !ok {
b.deferExprFuncs[instr.Call.Value] = len(b.allDeferFuncs)
@@ -195,43 +366,45 @@ func (b *builder) createDefer(instr *ssa.Defer) {
values = []llvm.Value{callback, next, funcValue}
valueTypes = append(valueTypes, funcValue.Type())
for _, param := range instr.Call.Args {
llvmParam := b.getValue(param)
llvmParam := b.getValue(param, getPos(instr))
values = append(values, llvmParam)
valueTypes = append(valueTypes, llvmParam.Type())
}
}
// Make a struct out of the collected values to put in the defer frame.
deferFrameType := b.ctx.StructType(valueTypes, false)
deferFrame := llvm.ConstNull(deferFrameType)
// Make a struct out of the collected values to put in the deferred call
// struct.
deferredCallType := b.ctx.StructType(valueTypes, false)
deferredCall := llvm.ConstNull(deferredCallType)
for i, value := range values {
deferFrame = b.CreateInsertValue(deferFrame, value, i, "")
deferredCall = b.CreateInsertValue(deferredCall, value, i, "")
}
// Put this struct in an allocation.
var alloca llvm.Value
if !isInLoop(instr.Block()) {
// This can safely use a stack allocation.
alloca = llvmutil.CreateEntryBlockAlloca(b.Builder, deferFrameType, "defer.alloca")
alloca = llvmutil.CreateEntryBlockAlloca(b.Builder, deferredCallType, "defer.alloca")
} else {
// This may be hit a variable number of times, so use a heap allocation.
size := b.targetData.TypeAllocSize(deferFrameType)
size := b.targetData.TypeAllocSize(deferredCallType)
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
allocCall := b.createRuntimeCall("alloc", []llvm.Value{sizeValue}, "defer.alloc.call")
alloca = b.CreateBitCast(allocCall, llvm.PointerType(deferFrameType, 0), "defer.alloc")
nilPtr := llvm.ConstNull(b.dataPtrType)
alloca = b.createRuntimeCall("alloc", []llvm.Value{sizeValue, nilPtr}, "defer.alloc.call")
}
if b.NeedsStackObjects {
b.trackPointer(alloca)
}
b.CreateStore(deferFrame, alloca)
b.CreateStore(deferredCall, alloca)
// Push it on top of the linked list by replacing deferPtr.
allocaCast := b.CreateBitCast(alloca, next.Type(), "defer.alloca.cast")
b.CreateStore(allocaCast, b.deferPtr)
b.CreateStore(alloca, b.deferPtr)
}
// createRunDefers emits code to run all deferred functions.
func (b *builder) createRunDefers() {
deferType := b.getLLVMRuntimeType("_defer")
// Add a loop like the following:
// for stack != nil {
// _stack := stack
@@ -247,17 +420,17 @@ func (b *builder) createRunDefers() {
// }
// }
// Create loop.
loophead := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.loophead")
loop := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.loop")
unreachable := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.default")
end := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.end")
// Create loop, in the order: loophead, loop, callback0, callback1, ..., unreachable, end.
end := b.insertBasicBlock("rundefers.end")
unreachable := b.ctx.InsertBasicBlock(end, "rundefers.default")
loop := b.ctx.InsertBasicBlock(unreachable, "rundefers.loop")
loophead := b.ctx.InsertBasicBlock(loop, "rundefers.loophead")
b.CreateBr(loophead)
// Create loop head:
// for stack != nil {
b.SetInsertPointAtEnd(loophead)
deferData := b.CreateLoad(b.deferPtr, "")
deferData := b.CreateLoad(b.dataPtrType, b.deferPtr, "")
stackIsNil := b.CreateICmp(llvm.IntEQ, deferData, llvm.ConstPointerNull(deferData.Type()), "stackIsNil")
b.CreateCondBr(stackIsNil, end, loop)
@@ -266,24 +439,24 @@ func (b *builder) createRunDefers() {
// stack = stack.next
// switch stack.callback {
b.SetInsertPointAtEnd(loop)
nextStackGEP := b.CreateInBoundsGEP(deferData, []llvm.Value{
nextStackGEP := b.CreateInBoundsGEP(deferType, deferData, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), 1, false), // .next field
}, "stack.next.gep")
nextStack := b.CreateLoad(nextStackGEP, "stack.next")
nextStack := b.CreateLoad(b.dataPtrType, nextStackGEP, "stack.next")
b.CreateStore(nextStack, b.deferPtr)
gep := b.CreateInBoundsGEP(deferData, []llvm.Value{
gep := b.CreateInBoundsGEP(deferType, deferData, []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), 0, false), // .callback field
}, "callback.gep")
callback := b.CreateLoad(gep, "callback")
callback := b.CreateLoad(b.uintptrType, gep, "callback")
sw := b.CreateSwitch(callback, unreachable, len(b.allDeferFuncs))
for i, callback := range b.allDeferFuncs {
// Create switch case, for example:
// case 0:
// // run first deferred call
block := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.callback")
block := b.insertBasicBlock("rundefers.callback" + strconv.Itoa(i))
sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), block)
b.SetInsertPointAtEnd(block)
switch callback := callback.(type) {
@@ -291,33 +464,32 @@ func (b *builder) createRunDefers() {
// Call on an value or interface value.
// Get the real defer struct type and cast to it.
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
valueTypes := []llvm.Type{b.uintptrType, b.dataPtrType}
if !callback.IsInvoke() {
//Expect funcValue to be passed through the defer frame.
//Expect funcValue to be passed through the deferred call.
valueTypes = append(valueTypes, b.getFuncType(callback.Signature()))
} else {
//Expect typecode
valueTypes = append(valueTypes, b.uintptrType, b.i8ptrType)
valueTypes = append(valueTypes, b.dataPtrType, b.dataPtrType)
}
for _, arg := range callback.Args {
valueTypes = append(valueTypes, b.getLLVMType(arg.Type()))
}
deferFrameType := b.ctx.StructType(valueTypes, false)
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
// Extract the params from the struct (including receiver).
forwardParams := []llvm.Value{}
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
deferredCallType := b.ctx.StructType(valueTypes, false)
for i := 2; i < len(valueTypes); i++ {
gep := b.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "gep")
forwardParam := b.CreateLoad(gep, "param")
gep := b.CreateInBoundsGEP(deferredCallType, deferData, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "gep")
forwardParam := b.CreateLoad(valueTypes[i], gep, "param")
forwardParams = append(forwardParams, forwardParam)
}
var fnPtr llvm.Value
var fnType llvm.Type
if !callback.IsInvoke() {
// Isolate the func value.
@@ -325,93 +497,86 @@ func (b *builder) createRunDefers() {
forwardParams = forwardParams[1:]
//Get function pointer and context
fp, context := b.decodeFuncValue(funcValue, callback.Signature())
fnPtr = fp
var context llvm.Value
fnPtr, context = b.decodeFuncValue(funcValue)
fnType = b.getLLVMFunctionType(callback.Signature())
//Pass context
forwardParams = append(forwardParams, context)
} else {
// Isolate the typecode.
typecode := forwardParams[0]
forwardParams = forwardParams[1:]
fnPtr = b.getInvokePtr(callback, typecode)
// Move typecode from the start to the end of the list of
// parameters.
forwardParams = append(forwardParams[1:], forwardParams[0])
fnPtr = b.getInvokeFunction(callback)
fnType = fnPtr.GlobalValueType()
// Add the context parameter. An interface call cannot also be a
// closure but we have to supply the parameter anyway for platforms
// with a strict calling convention.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
forwardParams = append(forwardParams, llvm.Undef(b.dataPtrType))
}
// Parent coroutine handle.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
b.createCall(fnPtr, forwardParams, "")
b.createCall(fnType, fnPtr, forwardParams, "")
case *ssa.Function:
// Direct call.
// Get the real defer struct type and cast to it.
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
valueTypes := []llvm.Type{b.uintptrType, b.dataPtrType}
for _, param := range getParams(callback.Signature) {
valueTypes = append(valueTypes, b.getLLVMType(param.Type()))
}
deferFrameType := b.ctx.StructType(valueTypes, false)
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
deferredCallType := b.ctx.StructType(valueTypes, false)
// Extract the params from the struct.
forwardParams := []llvm.Value{}
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
for i := range getParams(callback.Signature) {
gep := b.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
forwardParam := b.CreateLoad(gep, "param")
gep := b.CreateInBoundsGEP(deferredCallType, deferData, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
forwardParam := b.CreateLoad(valueTypes[i+2], gep, "param")
forwardParams = append(forwardParams, forwardParam)
}
// Plain TinyGo functions add some extra parameters to implement async functionality and function recievers.
// Plain TinyGo functions add some extra parameters to implement async functionality and function receivers.
// These parameters should not be supplied when calling into an external C/ASM function.
if !b.getFunctionInfo(callback).exported {
// Add the context parameter. We know it is ignored by the receiving
// function, but we have to pass one anyway.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
// Parent coroutine handle.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
forwardParams = append(forwardParams, llvm.Undef(b.dataPtrType))
}
// Call real function.
b.createCall(b.getFunction(callback), forwardParams, "")
fnType, fn := b.getFunction(callback)
b.createInvoke(fnType, fn, forwardParams, "")
case *ssa.MakeClosure:
// Get the real defer struct type and cast to it.
fn := callback.Fn.(*ssa.Function)
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
valueTypes := []llvm.Type{b.uintptrType, b.dataPtrType}
params := fn.Signature.Params()
for i := 0; i < params.Len(); i++ {
valueTypes = append(valueTypes, b.getLLVMType(params.At(i).Type()))
}
valueTypes = append(valueTypes, b.i8ptrType) // closure
deferFrameType := b.ctx.StructType(valueTypes, false)
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
valueTypes = append(valueTypes, b.dataPtrType) // closure
deferredCallType := b.ctx.StructType(valueTypes, false)
// Extract the params from the struct.
forwardParams := []llvm.Value{}
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
for i := 2; i < len(valueTypes); i++ {
gep := b.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "")
forwardParam := b.CreateLoad(gep, "param")
gep := b.CreateInBoundsGEP(deferredCallType, deferData, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "")
forwardParam := b.CreateLoad(valueTypes[i], gep, "param")
forwardParams = append(forwardParams, forwardParam)
}
// Parent coroutine handle.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
// Call deferred function.
b.createCall(b.getFunction(fn), forwardParams, "")
fnType, llvmFn := b.getFunction(fn)
b.createCall(fnType, llvmFn, forwardParams, "")
case *ssa.Builtin:
db := b.deferBuiltinFuncs[callback]
//Get parameter types
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
valueTypes := []llvm.Type{b.uintptrType, b.dataPtrType}
//Get signature from call results
params := callback.Type().Underlying().(*types.Signature).Params()
@@ -419,15 +584,14 @@ func (b *builder) createRunDefers() {
valueTypes = append(valueTypes, b.getLLVMType(params.At(i).Type()))
}
deferFrameType := b.ctx.StructType(valueTypes, false)
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
deferredCallType := b.ctx.StructType(valueTypes, false)
// Extract the params from the struct.
var argValues []llvm.Value
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
for i := 0; i < params.Len(); i++ {
gep := b.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
forwardParam := b.CreateLoad(gep, "param")
gep := b.CreateInBoundsGEP(deferredCallType, deferData, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
forwardParam := b.CreateLoad(valueTypes[i+2], gep, "param")
argValues = append(argValues, forwardParam)
}
+1 -11
View File
@@ -3,7 +3,6 @@ package compiler
// This file contains some utility functions related to error handling.
import (
"go/scanner"
"go/token"
"go/types"
"path/filepath"
@@ -20,20 +19,11 @@ func (c *compilerContext) makeError(pos token.Pos, msg string) types.Error {
}
}
// addError adds a new compiler diagnostic with the given location and message.
func (c *compilerContext) addError(pos token.Pos, msg string) {
c.diagnostics = append(c.diagnostics, c.makeError(pos, msg))
}
// errorAt returns an error value at the location of the instruction.
// The location information may not be complete as it depends on debug
// information in the IR.
func errorAt(inst llvm.Value, msg string) scanner.Error {
return scanner.Error{
Pos: getPosition(inst),
Msg: msg,
}
}
// getPosition returns the position information for the given value, as far as
// it is available.
func getPosition(val llvm.Value) token.Position {
+16 -63
View File
@@ -13,40 +13,11 @@ import (
// createFuncValue creates a function value from a raw function pointer with no
// context.
func (b *builder) createFuncValue(funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
return b.compilerContext.createFuncValue(b.Builder, funcPtr, context, sig)
}
// createFuncValue creates a function value from a raw function pointer with no
// context.
func (c *compilerContext) createFuncValue(builder llvm.Builder, funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
var funcValueScalar llvm.Value
switch c.FuncImplementation {
case "doubleword":
// Closure is: {context, function pointer}
funcValueScalar = funcPtr
case "switch":
sigGlobal := c.getTypeCode(sig)
funcValueWithSignatureGlobalName := funcPtr.Name() + "$withSignature"
funcValueWithSignatureGlobal := c.mod.NamedGlobal(funcValueWithSignatureGlobalName)
if funcValueWithSignatureGlobal.IsNil() {
funcValueWithSignatureType := c.getLLVMRuntimeType("funcValueWithSignature")
funcValueWithSignature := llvm.ConstNamedStruct(funcValueWithSignatureType, []llvm.Value{
llvm.ConstPtrToInt(funcPtr, c.uintptrType),
sigGlobal,
})
funcValueWithSignatureGlobal = llvm.AddGlobal(c.mod, funcValueWithSignatureType, funcValueWithSignatureGlobalName)
funcValueWithSignatureGlobal.SetInitializer(funcValueWithSignature)
funcValueWithSignatureGlobal.SetGlobalConstant(true)
funcValueWithSignatureGlobal.SetLinkage(llvm.LinkOnceODRLinkage)
}
funcValueScalar = llvm.ConstPtrToInt(funcValueWithSignatureGlobal, c.uintptrType)
default:
panic("unimplemented func value variant")
}
funcValueType := c.getFuncType(sig)
// Closure is: {context, function pointer}
funcValueType := b.getFuncType(sig)
funcValue := llvm.Undef(funcValueType)
funcValue = builder.CreateInsertValue(funcValue, context, 0, "")
funcValue = builder.CreateInsertValue(funcValue, funcValueScalar, 1, "")
funcValue = b.CreateInsertValue(funcValue, context, 0, "")
funcValue = b.CreateInsertValue(funcValue, funcPtr, 1, "")
return funcValue
}
@@ -63,38 +34,20 @@ func (b *builder) extractFuncContext(funcValue llvm.Value) llvm.Value {
}
// decodeFuncValue extracts the context and the function pointer from this func
// value. This may be an expensive operation.
func (b *builder) decodeFuncValue(funcValue llvm.Value, sig *types.Signature) (funcPtr, context llvm.Value) {
// value.
func (b *builder) decodeFuncValue(funcValue llvm.Value) (funcPtr, context llvm.Value) {
context = b.CreateExtractValue(funcValue, 0, "")
switch b.FuncImplementation {
case "doubleword":
funcPtr = b.CreateExtractValue(funcValue, 1, "")
case "switch":
llvmSig := b.getRawFuncType(sig)
sigGlobal := b.getTypeCode(sig)
funcPtr = b.createRuntimeCall("getFuncPtr", []llvm.Value{funcValue, sigGlobal}, "")
funcPtr = b.CreateIntToPtr(funcPtr, llvmSig, "")
default:
panic("unimplemented func value variant")
}
funcPtr = b.CreateExtractValue(funcValue, 1, "")
return
}
// getFuncType returns the type of a func value given a signature.
func (c *compilerContext) getFuncType(typ *types.Signature) llvm.Type {
switch c.FuncImplementation {
case "doubleword":
rawPtr := c.getRawFuncType(typ)
return c.ctx.StructType([]llvm.Type{c.i8ptrType, rawPtr}, false)
case "switch":
return c.getLLVMRuntimeType("funcValue")
default:
panic("unimplemented func value variant")
}
return c.ctx.StructType([]llvm.Type{c.dataPtrType, c.funcPtrType}, false)
}
// getRawFuncType returns a LLVM function pointer type for a given signature.
func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
// getLLVMFunctionType returns a LLVM function type for a given signature.
func (c *compilerContext) getLLVMFunctionType(typ *types.Signature) llvm.Type {
// Get the return type.
var returnType llvm.Type
switch typ.Results().Len() {
@@ -122,7 +75,7 @@ func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
if recv.StructName() == "runtime._interface" {
// This is a call on an interface, not a concrete type.
// The receiver is not an interface, but a i8* type.
recv = c.i8ptrType
recv = c.dataPtrType
}
for _, info := range c.expandFormalParamType(recv, "", nil) {
paramTypes = append(paramTypes, info.llvmType)
@@ -135,11 +88,10 @@ func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
}
}
// All functions take these parameters at the end.
paramTypes = append(paramTypes, c.i8ptrType) // context
paramTypes = append(paramTypes, c.i8ptrType) // parent coroutine
paramTypes = append(paramTypes, c.dataPtrType) // context
// Make a func type out of the signature.
return llvm.PointerType(llvm.FunctionType(returnType, paramTypes, false), c.funcPtrAddrSpace)
return llvm.FunctionType(returnType, paramTypes, false)
}
// parseMakeClosure makes a function value (with context) from the given
@@ -154,7 +106,7 @@ func (b *builder) parseMakeClosure(expr *ssa.MakeClosure) (llvm.Value, error) {
boundVars := make([]llvm.Value, len(expr.Bindings))
for i, binding := range expr.Bindings {
// The context stores the bound variables.
llvmBoundVar := b.getValue(binding)
llvmBoundVar := b.getValue(binding, getPos(expr))
boundVars[i] = llvmBoundVar
}
@@ -163,5 +115,6 @@ func (b *builder) parseMakeClosure(expr *ssa.MakeClosure) (llvm.Value, error) {
context := b.emitPointerPack(boundVars)
// Create the closure.
return b.createFuncValue(b.getFunction(f), context, f.Signature), nil
_, fn := b.getFunction(f)
return b.createFuncValue(fn, context, f.Signature), nil
}
+1 -4
View File
@@ -81,10 +81,7 @@ func (b *builder) trackValue(value llvm.Value) {
// trackPointer creates a call to runtime.trackPointer, bitcasting the poitner
// first if needed. The input value must be of LLVM pointer type.
func (b *builder) trackPointer(value llvm.Value) {
if value.Type() != b.i8ptrType {
value = b.CreateBitCast(value, b.i8ptrType, "")
}
b.createRuntimeCall("trackPointer", []llvm.Value{value}, "")
b.createRuntimeCall("trackPointer", []llvm.Value{value, b.stackChainAlloca}, "")
}
// typeHasPointers returns whether this type is a pointer or contains pointers.
+173 -68
View File
@@ -5,73 +5,157 @@ package compiler
import (
"go/token"
"go/types"
"github.com/tinygo-org/tinygo/compiler/llvmutil"
"golang.org/x/tools/go/ssa"
"tinygo.org/x/go-llvm"
)
// createGoInstruction starts a new goroutine with the provided function pointer
// and parameters.
// In general, you should pass all regular parameters plus the context parameter.
// There is one exception: the task-based scheduler needs to have the function
// pointer passed in as a parameter too in addition to the context.
//
// Because a go statement doesn't return anything, return undef.
func (b *builder) createGoInstruction(funcPtr llvm.Value, params []llvm.Value, prefix string, pos token.Pos) llvm.Value {
paramBundle := b.emitPointerPack(params)
var callee, stackSize llvm.Value
switch b.Scheduler {
case "none", "tasks":
callee = b.createGoroutineStartWrapper(funcPtr, prefix, pos)
if b.AutomaticStackSize {
// The stack size is not known until after linking. Call a dummy
// function that will be replaced with a load from a special ELF
// section that contains the stack size (and is modified after
// linking).
stackSizeFn := b.getFunction(b.program.ImportedPackage("internal/task").Members["getGoroutineStackSize"].(*ssa.Function))
stackSize = b.createCall(stackSizeFn, []llvm.Value{callee, llvm.Undef(b.i8ptrType), llvm.Undef(b.i8ptrType)}, "stacksize")
} else {
// The stack size is fixed at compile time. By emitting it here as a
// constant, it can be optimized.
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
}
case "coroutines":
callee = b.CreatePtrToInt(funcPtr, b.uintptrType, "")
// There is no goroutine stack size: coroutines are used instead of
// stacks.
stackSize = llvm.Undef(b.uintptrType)
default:
panic("unreachable")
// createGo emits code to start a new goroutine.
func (b *builder) createGo(instr *ssa.Go) {
// Get all function parameters to pass to the goroutine.
var params []llvm.Value
for _, param := range instr.Call.Args {
params = append(params, b.getValue(param, getPos(instr)))
}
start := b.getFunction(b.program.ImportedPackage("internal/task").Members["start"].(*ssa.Function))
b.createCall(start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.i8ptrType), llvm.ConstPointerNull(b.i8ptrType)}, "")
return llvm.Undef(funcPtr.Type().ElementType().ReturnType())
var prefix string
var funcPtr llvm.Value
var funcType llvm.Type
hasContext := false
if callee := instr.Call.StaticCallee(); callee != nil {
// Static callee is known. This makes it easier to start a new
// goroutine.
var context llvm.Value
switch value := instr.Call.Value.(type) {
case *ssa.Function:
// Goroutine call is regular function call. No context is necessary.
case *ssa.MakeClosure:
// A goroutine call on a func value, but the callee is trivial to find. For
// example: immediately applied functions.
funcValue := b.getValue(value, getPos(instr))
context = b.extractFuncContext(funcValue)
default:
panic("StaticCallee returned an unexpected value")
}
if !context.IsNil() {
params = append(params, context) // context parameter
hasContext = true
}
funcType, funcPtr = b.getFunction(callee)
} else if builtin, ok := instr.Call.Value.(*ssa.Builtin); ok {
// We cheat. None of the builtins do any long or blocking operation, so
// we might as well run these builtins right away without the program
// noticing the difference.
// Possible exceptions:
// - copy: this is a possibly long operation, but not a blocking
// operation. Semantically it makes no difference to run it right
// away (not in a goroutine). However, in practice it makes no sense
// to run copy in a goroutine as there is no way to (safely) know
// when it is finished.
// - panic: the error message would appear in the parent goroutine.
// But because `go panic("err")` would halt the program anyway
// (there is no recover), panicking right away would give the same
// behavior as creating a goroutine, switching the scheduler to that
// goroutine, and panicking there. So this optimization seems
// correct.
// - recover: because it runs in a new goroutine, it is never a
// deferred function. Thus this is a no-op.
if builtin.Name() == "recover" {
// This is a no-op, even in a deferred function:
// go recover()
return
}
var argTypes []types.Type
var argValues []llvm.Value
for _, arg := range instr.Call.Args {
argTypes = append(argTypes, arg.Type())
argValues = append(argValues, b.getValue(arg, getPos(instr)))
}
b.createBuiltin(argTypes, argValues, builtin.Name(), instr.Pos())
return
} else if instr.Call.IsInvoke() {
// This is a method call on an interface value.
itf := b.getValue(instr.Call.Value, getPos(instr))
itfTypeCode := b.CreateExtractValue(itf, 0, "")
itfValue := b.CreateExtractValue(itf, 1, "")
funcPtr = b.getInvokeFunction(&instr.Call)
funcType = funcPtr.GlobalValueType()
params = append([]llvm.Value{itfValue}, params...) // start with receiver
params = append(params, itfTypeCode) // end with typecode
} else {
// This is a function pointer.
// At the moment, two extra params are passed to the newly started
// goroutine:
// * The function context, for closures.
// * The function pointer (for tasks).
var context llvm.Value
funcPtr, context = b.decodeFuncValue(b.getValue(instr.Call.Value, getPos(instr)))
funcType = b.getLLVMFunctionType(instr.Call.Value.Type().Underlying().(*types.Signature))
params = append(params, context, funcPtr)
hasContext = true
prefix = b.fn.RelString(nil)
}
paramBundle := b.emitPointerPack(params)
var stackSize llvm.Value
callee := b.createGoroutineStartWrapper(funcType, funcPtr, prefix, hasContext, instr.Pos())
if b.AutomaticStackSize {
// The stack size is not known until after linking. Call a dummy
// function that will be replaced with a load from a special ELF
// section that contains the stack size (and is modified after
// linking).
stackSizeFnType, stackSizeFn := b.getFunction(b.program.ImportedPackage("internal/task").Members["getGoroutineStackSize"].(*ssa.Function))
stackSize = b.createCall(stackSizeFnType, stackSizeFn, []llvm.Value{callee, llvm.Undef(b.dataPtrType)}, "stacksize")
} else {
// The stack size is fixed at compile time. By emitting it here as a
// constant, it can be optimized.
if (b.Scheduler == "tasks" || b.Scheduler == "asyncify") && b.DefaultStackSize == 0 {
b.addError(instr.Pos(), "default stack size for goroutines is not set")
}
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
}
fnType, start := b.getFunction(b.program.ImportedPackage("internal/task").Members["start"].(*ssa.Function))
b.createCall(fnType, start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.dataPtrType)}, "")
}
// createGoroutineStartWrapper creates a wrapper for the task-based
// implementation of goroutines. For example, to call a function like this:
//
// func add(x, y int) int { ... }
// func add(x, y int) int { ... }
//
// It creates a wrapper like this:
//
// func add$gowrapper(ptr *unsafe.Pointer) {
// args := (*struct{
// x, y int
// })(ptr)
// add(args.x, args.y)
// }
// func add$gowrapper(ptr *unsafe.Pointer) {
// args := (*struct{
// x, y int
// })(ptr)
// add(args.x, args.y)
// }
//
// This is useful because the task-based goroutine start implementation only
// allows a single (pointer) argument to the newly started goroutine. Also, it
// ignores the return value because newly started goroutines do not have a
// return value.
func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix string, pos token.Pos) llvm.Value {
//
// The hasContext parameter indicates whether the context parameter (the second
// to last parameter of the function) is used for this wrapper. If hasContext is
// false, the parameter bundle is assumed to have no context parameter and undef
// is passed instead.
func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.Value, prefix string, hasContext bool, pos token.Pos) llvm.Value {
var wrapper llvm.Value
builder := c.ctx.NewBuilder()
defer builder.Dispose()
b := &builder{
compilerContext: c,
Builder: c.ctx.NewBuilder(),
}
defer b.Dispose()
var deadlock llvm.Value
var deadlockType llvm.Type
if c.Scheduler == "asyncify" {
deadlockType, deadlock = c.getFunction(c.program.ImportedPackage("runtime").Members["deadlock"].(*ssa.Function))
}
if !fn.IsAFunction().IsNil() {
// See whether this wrapper has already been created. If so, return it.
@@ -82,13 +166,14 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
}
// Create the wrapper.
wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType}, false)
wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.dataPtrType}, false)
wrapper = llvm.AddFunction(c.mod, name+"$gowrapper", wrapperType)
c.addStandardAttributes(wrapper)
wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
wrapper.SetUnnamedAddr(true)
wrapper.AddAttributeAtIndex(-1, c.ctx.CreateStringAttribute("tinygo-gowrapper", name))
entry := c.ctx.AddBasicBlock(wrapper, "entry")
builder.SetInsertPointAtEnd(entry)
b.SetInsertPointAtEnd(entry)
if c.Debug {
pos := c.program.Fset.Position(pos)
@@ -109,16 +194,27 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
Optimized: true,
})
wrapper.SetSubprogram(difunc)
builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
}
// Create the list of params for the call.
paramTypes := fn.Type().ElementType().ParamTypes()
params := llvmutil.EmitPointerUnpack(builder, c.mod, wrapper.Param(0), paramTypes[:len(paramTypes)-1])
params = append(params, llvm.Undef(c.i8ptrType))
paramTypes := fnType.ParamTypes()
if !hasContext {
paramTypes = paramTypes[:len(paramTypes)-1] // strip context parameter
}
params := b.emitPointerUnpack(wrapper.Param(0), paramTypes)
if !hasContext {
params = append(params, llvm.Undef(c.dataPtrType)) // add dummy context parameter
}
// Create the call.
builder.CreateCall(fn, params, "")
b.CreateCall(fnType, fn, params, "")
if c.Scheduler == "asyncify" {
b.CreateCall(deadlockType, deadlock, []llvm.Value{
llvm.Undef(c.dataPtrType),
}, "")
}
} else {
// For a function pointer like this:
@@ -139,13 +235,14 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
// merged into one.
// Create the wrapper.
wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType}, false)
wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.dataPtrType}, false)
wrapper = llvm.AddFunction(c.mod, prefix+".gowrapper", wrapperType)
c.addStandardAttributes(wrapper)
wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
wrapper.SetUnnamedAddr(true)
wrapper.AddAttributeAtIndex(-1, c.ctx.CreateStringAttribute("tinygo-gowrapper", ""))
entry := c.ctx.AddBasicBlock(wrapper, "entry")
builder.SetInsertPointAtEnd(entry)
b.SetInsertPointAtEnd(entry)
if c.Debug {
pos := c.program.Fset.Position(pos)
@@ -166,29 +263,37 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
Optimized: true,
})
wrapper.SetSubprogram(difunc)
builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
}
// Get the list of parameters, with the extra parameters at the end.
paramTypes := fn.Type().ElementType().ParamTypes()
paramTypes[len(paramTypes)-1] = fn.Type() // the last element is the function pointer
params := llvmutil.EmitPointerUnpack(builder, c.mod, wrapper.Param(0), paramTypes)
paramTypes := fnType.ParamTypes()
paramTypes = append(paramTypes, fn.Type()) // the last element is the function pointer
params := b.emitPointerUnpack(wrapper.Param(0), paramTypes)
// Get the function pointer.
fnPtr := params[len(params)-1]
// Ignore the last param, which isn't used anymore.
// TODO: avoid this extra "parent handle" parameter in most functions.
params[len(params)-1] = llvm.Undef(c.i8ptrType)
params = params[:len(params)-1]
// Create the call.
builder.CreateCall(fnPtr, params, "")
b.CreateCall(fnType, fnPtr, params, "")
if c.Scheduler == "asyncify" {
b.CreateCall(deadlockType, deadlock, []llvm.Value{
llvm.Undef(c.dataPtrType),
}, "")
}
}
// Finish the function. Every basic block must end in a terminator, and
// because goroutines never return a value we can simply return void.
builder.CreateRetVoid()
if c.Scheduler == "asyncify" {
// The goroutine was terminated via deadlock.
b.CreateUnreachable()
} else {
// Finish the function. Every basic block must end in a terminator, and
// because goroutines never return a value we can simply return void.
b.CreateRetVoid()
}
// Return a ptrtoint of the wrapper, not the function itself.
return builder.CreatePtrToInt(wrapper, c.uintptrType, "")
return b.CreatePtrToInt(wrapper, c.uintptrType, "")
}
+50 -46
View File
@@ -5,6 +5,7 @@ package compiler
import (
"fmt"
"go/constant"
"go/token"
"regexp"
"strconv"
"strings"
@@ -17,31 +18,31 @@ import (
// operands or return values. It is useful for trivial instructions, like wfi in
// ARM or sleep in AVR.
//
// func Asm(asm string)
// func Asm(asm string)
//
// The provided assembly must be a constant.
func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
// Magic function: insert inline assembly instead of calling it.
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{}, false)
asm := constant.StringVal(args[0].(*ssa.Const).Value)
target := llvm.InlineAsm(fnType, asm, "", true, false, 0)
return b.CreateCall(target, nil, ""), nil
target := llvm.InlineAsm(fnType, asm, "", true, false, 0, false)
return b.CreateCall(fnType, target, nil, ""), nil
}
// This is a compiler builtin, which allows assembly to be called in a flexible
// way.
//
// func AsmFull(asm string, regs map[string]interface{}) uintptr
// func AsmFull(asm string, regs map[string]interface{}) uintptr
//
// The asm parameter must be a constant string. The regs parameter must be
// provided immediately. For example:
//
// arm.AsmFull(
// "str {value}, {result}",
// map[string]interface{}{
// "value": 1
// "result": &dest,
// })
// arm.AsmFull(
// "str {value}, {result}",
// map[string]interface{}{
// "value": 1
// "result": &dest,
// })
func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error) {
asmString := constant.StringVal(instr.Args[0].(*ssa.Const).Value)
registers := map[string]llvm.Value{}
@@ -55,7 +56,7 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
return llvm.Value{}, b.makeError(instr.Pos(), "register value map must be created in the same basic block")
}
key := constant.StringVal(r.Key.(*ssa.Const).Value)
registers[key] = b.getValue(r.Value.(*ssa.MakeInterface).X)
registers[key] = b.getValue(r.Value.(*ssa.MakeInterface).X, getPos(instr))
case *ssa.Call:
if r.Common() == instr {
break
@@ -72,7 +73,7 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
args := []llvm.Value{}
constraints := []string{}
hasOutput := false
asmString = regexp.MustCompile("\\{\\}").ReplaceAllStringFunc(asmString, func(s string) string {
asmString = regexp.MustCompile(`\{\}`).ReplaceAllStringFunc(asmString, func(s string) string {
hasOutput = true
return "$0"
})
@@ -80,7 +81,7 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
constraints = append(constraints, "=&r")
registerNumbers[""] = 0
}
asmString = regexp.MustCompile("\\{[a-zA-Z]+\\}").ReplaceAllStringFunc(asmString, func(s string) string {
asmString = regexp.MustCompile(`\{[a-zA-Z]+\}`).ReplaceAllStringFunc(asmString, func(s string) string {
// TODO: skip strings like {r4} etc. that look like ARM push/pop
// instructions.
name := s[1 : len(s)-1]
@@ -98,7 +99,10 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
case llvm.IntegerTypeKind:
constraints = append(constraints, "r")
case llvm.PointerTypeKind:
constraints = append(constraints, "*m")
// Memory references require a type starting with LLVM 14,
// probably as a preparation for opaque pointers.
err = b.makeError(instr.Pos(), "support for pointer operands was dropped in TinyGo 0.23")
return s
default:
err = b.makeError(instr.Pos(), "unknown type in inline assembly for value: "+name)
return s
@@ -116,8 +120,8 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
outputType = b.ctx.VoidType()
}
fnType := llvm.FunctionType(outputType, argTypes, false)
target := llvm.InlineAsm(fnType, asmString, strings.Join(constraints, ","), true, false, 0)
result := b.CreateCall(target, args, "")
target := llvm.InlineAsm(fnType, asmString, strings.Join(constraints, ","), true, false, 0, false)
result := b.CreateCall(fnType, target, args, "")
if hasOutput {
return result, nil
} else {
@@ -129,15 +133,15 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
// This is a compiler builtin which emits an inline SVCall instruction. It can
// be one of:
//
// func SVCall0(num uintptr) uintptr
// func SVCall1(num uintptr, a1 interface{}) uintptr
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
// func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
// func SVCall0(num uintptr) uintptr
// func SVCall1(num uintptr, a1 interface{}) uintptr
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
// func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
//
// The num parameter must be a constant. All other parameters may be any scalar
// value supported by LLVM inline assembly.
func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
func (b *builder) emitSVCall(args []ssa.Value, pos token.Pos) (llvm.Value, error) {
num, _ := constant.Uint64Val(args[0].(*ssa.Const).Value)
llvmArgs := []llvm.Value{}
argTypes := []llvm.Type{}
@@ -150,7 +154,7 @@ func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
} else {
constraints += ",{r" + strconv.Itoa(i) + "}"
}
llvmValue := b.getValue(arg)
llvmValue := b.getValue(arg, pos)
llvmArgs = append(llvmArgs, llvmValue)
argTypes = append(argTypes, llvmValue.Type())
}
@@ -159,23 +163,23 @@ func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
// marked as clobbered.
constraints += ",~{r1},~{r2},~{r3}"
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0)
return b.CreateCall(target, llvmArgs, ""), nil
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0, false)
return b.CreateCall(fnType, target, llvmArgs, ""), nil
}
// This is a compiler builtin which emits an inline SVCall instruction. It can
// be one of:
//
// func SVCall0(num uintptr) uintptr
// func SVCall1(num uintptr, a1 interface{}) uintptr
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
// func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
// func SVCall0(num uintptr) uintptr
// func SVCall1(num uintptr, a1 interface{}) uintptr
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
// func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
//
// The num parameter must be a constant. All other parameters may be any scalar
// value supported by LLVM inline assembly.
// Same as emitSVCall but for AArch64
func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
func (b *builder) emitSV64Call(args []ssa.Value, pos token.Pos) (llvm.Value, error) {
num, _ := constant.Uint64Val(args[0].(*ssa.Const).Value)
llvmArgs := []llvm.Value{}
argTypes := []llvm.Type{}
@@ -188,7 +192,7 @@ func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
} else {
constraints += ",{x" + strconv.Itoa(i) + "}"
}
llvmValue := b.getValue(arg)
llvmValue := b.getValue(arg, pos)
llvmArgs = append(llvmArgs, llvmValue)
argTypes = append(argTypes, llvmValue.Type())
}
@@ -197,16 +201,16 @@ func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
// marked as clobbered.
constraints += ",~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7}"
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0)
return b.CreateCall(target, llvmArgs, ""), nil
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0, false)
return b.CreateCall(fnType, target, llvmArgs, ""), nil
}
// This is a compiler builtin which emits CSR instructions. It can be one of:
//
// func (csr CSR) Get() uintptr
// func (csr CSR) Set(uintptr)
// func (csr CSR) SetBits(uintptr) uintptr
// func (csr CSR) ClearBits(uintptr) uintptr
// func (csr CSR) Get() uintptr
// func (csr CSR) Set(uintptr)
// func (csr CSR) SetBits(uintptr) uintptr
// func (csr CSR) ClearBits(uintptr) uintptr
//
// The csr parameter (method receiver) must be a constant. Other parameter can
// be any value.
@@ -222,25 +226,25 @@ func (b *builder) emitCSROperation(call *ssa.CallCommon) (llvm.Value, error) {
// marked as such.
fnType := llvm.FunctionType(b.uintptrType, nil, false)
asm := fmt.Sprintf("csrr $0, %d", csr)
target := llvm.InlineAsm(fnType, asm, "=r", true, false, 0)
return b.CreateCall(target, nil, ""), nil
target := llvm.InlineAsm(fnType, asm, "=r", true, false, 0, false)
return b.CreateCall(fnType, target, nil, ""), nil
case "Set":
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.uintptrType}, false)
asm := fmt.Sprintf("csrw %d, $0", csr)
target := llvm.InlineAsm(fnType, asm, "r", true, false, 0)
return b.CreateCall(target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
target := llvm.InlineAsm(fnType, asm, "r", true, false, 0, false)
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1], getPos(call))}, ""), nil
case "SetBits":
// Note: it may be possible to optimize this to csrrsi in many cases.
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType}, false)
asm := fmt.Sprintf("csrrs $0, %d, $1", csr)
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0)
return b.CreateCall(target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0, false)
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1], getPos(call))}, ""), nil
case "ClearBits":
// Note: it may be possible to optimize this to csrrci in many cases.
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType}, false)
asm := fmt.Sprintf("csrrc $0, %d, $1", csr)
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0)
return b.CreateCall(target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0, false)
return b.CreateCall(fnType, target, []llvm.Value{b.getValue(call.Args[1], getPos(call))}, ""), nil
default:
return llvm.Value{}, b.makeError(call.Pos(), "unknown CSR operation: "+name)
}
+698 -265
View File
File diff suppressed because it is too large Load Diff
+10 -8
View File
@@ -24,7 +24,7 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
// Note that bound functions are allowed if the function has a pointer
// receiver and is a global. This is rather strict but still allows for
// idiomatic Go code.
funcValue := b.getValue(instr.Args[1])
funcValue := b.getValue(instr.Args[1], getPos(instr))
if funcValue.IsAConstant().IsNil() {
// Try to determine the cause of the non-constantness for a nice error
// message.
@@ -36,22 +36,24 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
// Fall back to a generic error.
return llvm.Value{}, b.makeError(instr.Pos(), "interrupt function must be constant")
}
funcRawPtr, funcContext := b.decodeFuncValue(funcValue)
funcPtr := llvm.ConstPtrToInt(funcRawPtr, b.uintptrType)
// Create a new global of type runtime/interrupt.handle. Globals of this
// type are lowered in the interrupt lowering pass.
globalType := b.program.ImportedPackage("runtime/interrupt").Type("handle").Type()
globalLLVMType := b.getLLVMType(globalType)
globalName := "runtime/interrupt.$interrupt" + strconv.FormatInt(id.Int64(), 10)
if global := b.mod.NamedGlobal(globalName); !global.IsNil() {
return llvm.Value{}, b.makeError(instr.Pos(), "interrupt redeclared in this program")
}
globalName := b.fn.Package().Pkg.Path() + "$interrupt" + strconv.FormatInt(id.Int64(), 10)
global := llvm.AddGlobal(b.mod, globalLLVMType, globalName)
global.SetVisibility(llvm.HiddenVisibility)
global.SetGlobalConstant(true)
global.SetUnnamedAddr(true)
initializer := llvm.ConstNull(globalLLVMType)
initializer = llvm.ConstInsertValue(initializer, funcValue, []uint32{0})
initializer = llvm.ConstInsertValue(initializer, llvm.ConstInt(b.intType, uint64(id.Int64()), true), []uint32{1, 0})
initializer = b.CreateInsertValue(initializer, funcContext, 0, "")
initializer = b.CreateInsertValue(initializer, funcPtr, 1, "")
initializer = b.CreateInsertValue(initializer, llvm.ConstNamedStruct(globalLLVMType.StructElementTypes()[2], []llvm.Value{
llvm.ConstInt(b.intType, uint64(id.Int64()), true),
}), 2, "")
global.SetInitializer(initializer)
// Add debug info to the interrupt global.
@@ -85,7 +87,7 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
useFnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{interrupt.Type()}, false)
useFn = llvm.AddFunction(b.mod, "runtime/interrupt.use", useFnType)
}
b.CreateCall(useFn, []llvm.Value{interrupt}, "")
b.CreateCall(useFn.GlobalValueType(), useFn, []llvm.Value{interrupt}, "")
}
return interrupt, nil
+251 -21
View File
@@ -3,48 +3,278 @@ package compiler
// This file contains helper functions to create calls to LLVM intrinsics.
import (
"go/token"
"strconv"
"strings"
"golang.org/x/tools/go/ssa"
"tinygo.org/x/go-llvm"
)
// createMemoryCopyCall creates a call to a builtin LLVM memcpy or memmove
// Define unimplemented intrinsic functions.
//
// Some functions are either normally implemented in Go assembly (like
// sync/atomic functions) or intentionally left undefined to be implemented
// directly in the compiler (like runtime/volatile functions). Either way, look
// for these and implement them if this is the case.
func (b *builder) defineIntrinsicFunction() {
name := b.fn.RelString(nil)
switch {
case name == "runtime.memcpy" || name == "runtime.memmove":
b.createMemoryCopyImpl()
case name == "runtime.memzero":
b.createMemoryZeroImpl()
case name == "runtime.stacksave":
b.createStackSaveImpl()
case name == "runtime.KeepAlive":
b.createKeepAliveImpl()
case strings.HasPrefix(name, "runtime/volatile.Load"):
b.createVolatileLoad()
case strings.HasPrefix(name, "runtime/volatile.Store"):
b.createVolatileStore()
case strings.HasPrefix(name, "sync/atomic.") && token.IsExported(b.fn.Name()):
b.createFunctionStart(true)
returnValue := b.createAtomicOp(b.fn.Name())
if !returnValue.IsNil() {
b.CreateRet(returnValue)
} else {
b.CreateRetVoid()
}
}
}
// createMemoryCopyImpl creates a call to a builtin LLVM memcpy or memmove
// function, declaring this function if needed. These calls are treated
// specially by optimization passes possibly resulting in better generated code,
// and will otherwise be lowered to regular libc memcpy/memmove calls.
func (b *builder) createMemoryCopyCall(fn *ssa.Function, args []ssa.Value) (llvm.Value, error) {
fnName := "llvm." + fn.Name() + ".p0i8.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
func (b *builder) createMemoryCopyImpl() {
b.createFunctionStart(true)
fnName := "llvm." + b.fn.Name() + ".p0.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
llvmFn := b.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.i8ptrType, b.uintptrType, b.ctx.Int1Type()}, false)
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.dataPtrType, b.dataPtrType, b.uintptrType, b.ctx.Int1Type()}, false)
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
}
var params []llvm.Value
for _, param := range args {
params = append(params, b.getValue(param))
for _, param := range b.fn.Params {
params = append(params, b.getValue(param, getPos(b.fn)))
}
params = append(params, llvm.ConstInt(b.ctx.Int1Type(), 0, false))
b.CreateCall(llvmFn, params, "")
return llvm.Value{}, nil
b.CreateCall(llvmFn.GlobalValueType(), llvmFn, params, "")
b.CreateRetVoid()
}
// createMemoryZeroCall creates calls to llvm.memset.* to zero a block of
// createMemoryZeroImpl creates calls to llvm.memset.* to zero a block of
// memory, declaring the function if needed. These calls will be lowered to
// regular libc memset calls if they aren't optimized out in a different way.
func (b *builder) createMemoryZeroCall(args []ssa.Value) (llvm.Value, error) {
fnName := "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
llvmFn := b.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.ctx.Int8Type(), b.uintptrType, b.ctx.Int1Type()}, false)
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
}
func (b *builder) createMemoryZeroImpl() {
b.createFunctionStart(true)
llvmFn := b.getMemsetFunc()
params := []llvm.Value{
b.getValue(args[0]),
b.getValue(b.fn.Params[0], getPos(b.fn)),
llvm.ConstInt(b.ctx.Int8Type(), 0, false),
b.getValue(args[1]),
b.getValue(b.fn.Params[1], getPos(b.fn)),
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
}
b.CreateCall(llvmFn, params, "")
return llvm.Value{}, nil
b.CreateCall(llvmFn.GlobalValueType(), llvmFn, params, "")
b.CreateRetVoid()
}
// createStackSaveImpl creates a call to llvm.stacksave.p0 to read the current
// stack pointer.
func (b *builder) createStackSaveImpl() {
b.createFunctionStart(true)
sp := b.readStackPointer()
b.CreateRet(sp)
}
// Return the llvm.memset.p0.i8 function declaration.
func (c *compilerContext) getMemsetFunc() llvm.Value {
fnName := "llvm.memset.p0.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
llvmFn := c.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
fnType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.dataPtrType, c.ctx.Int8Type(), c.uintptrType, c.ctx.Int1Type()}, false)
llvmFn = llvm.AddFunction(c.mod, fnName, fnType)
}
return llvmFn
}
// createKeepAlive creates the runtime.KeepAlive function. It is implemented
// using inline assembly.
func (b *builder) createKeepAliveImpl() {
b.createFunctionStart(true)
// Get the underlying value of the interface value.
interfaceValue := b.getValue(b.fn.Params[0], getPos(b.fn))
pointerValue := b.CreateExtractValue(interfaceValue, 1, "")
// 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.ctx.VoidType(), []llvm.Type{b.dataPtrType}, false)
asmFn := llvm.InlineAsm(asmType, "", "r", true, false, 0, false)
b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
b.CreateRetVoid()
}
var mathToLLVMMapping = map[string]string{
"math.Ceil": "llvm.ceil.f64",
"math.Exp": "llvm.exp.f64",
"math.Exp2": "llvm.exp2.f64",
"math.Floor": "llvm.floor.f64",
"math.Log": "llvm.log.f64",
"math.Sqrt": "llvm.sqrt.f64",
"math.Trunc": "llvm.trunc.f64",
}
// defineMathOp defines a math function body as a call to a LLVM intrinsic,
// instead of the regular Go implementation. This allows LLVM to reason about
// the math operation and (depending on the architecture) allows it to lower the
// operation to very fast floating point instructions. If this is not possible,
// LLVM will emit a call to a libm function that implements the same operation.
//
// One example of an optimization that LLVM can do is to convert
// float32(math.Sqrt(float64(v))) to a 32-bit floating point operation, which is
// beneficial on architectures where 64-bit floating point operations are (much)
// more expensive than 32-bit ones.
func (b *builder) defineMathOp() {
b.createFunctionStart(true)
llvmName := mathToLLVMMapping[b.fn.RelString(nil)]
if llvmName == "" {
panic("unreachable: unknown math operation") // sanity check
}
llvmFn := b.mod.NamedFunction(llvmName)
if llvmFn.IsNil() {
// The intrinsic doesn't exist yet, so declare it.
// At the moment, all supported intrinsics have the form "double
// foo(double %x)" so we can hardcode the signature here.
llvmType := llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType()}, false)
llvmFn = llvm.AddFunction(b.mod, llvmName, llvmType)
}
// Create a call to the intrinsic.
args := make([]llvm.Value, len(b.fn.Params))
for i, param := range b.fn.Params {
args[i] = b.getValue(param, getPos(b.fn))
}
result := b.CreateCall(llvmFn.GlobalValueType(), llvmFn, args, "")
b.CreateRet(result)
}
// Implement most math/bits functions.
//
// This implements all the functions that operate on bits. It does not yet
// implement the arithmetic functions (like bits.Add), which also have LLVM
// intrinsics.
func (b *builder) defineMathBitsIntrinsic() bool {
if b.fn.Pkg.Pkg.Path() != "math/bits" {
return false
}
name := b.fn.Name()
switch name {
case "LeadingZeros", "LeadingZeros8", "LeadingZeros16", "LeadingZeros32", "LeadingZeros64",
"TrailingZeros", "TrailingZeros8", "TrailingZeros16", "TrailingZeros32", "TrailingZeros64":
b.createFunctionStart(true)
param := b.getValue(b.fn.Params[0], b.fn.Pos())
valueType := param.Type()
var intrinsicName string
if strings.HasPrefix(name, "Leading") { // LeadingZeros
intrinsicName = "llvm.ctlz.i" + strconv.Itoa(valueType.IntTypeWidth())
} else { // TrailingZeros
intrinsicName = "llvm.cttz.i" + strconv.Itoa(valueType.IntTypeWidth())
}
llvmFn := b.mod.NamedFunction(intrinsicName)
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType, b.ctx.Int1Type()}, false)
if llvmFn.IsNil() {
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
}
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{
param,
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
}, "")
result = b.createZExtOrTrunc(result, b.intType)
b.CreateRet(result)
return true
case "Len", "Len8", "Len16", "Len32", "Len64":
// bits.Len can be implemented as:
// (unsafe.Sizeof(v) * 8) - bits.LeadingZeros(n)
// Not sure why this isn't already done in the standard library, as it
// is much simpler than a lookup table.
b.createFunctionStart(true)
param := b.getValue(b.fn.Params[0], b.fn.Pos())
valueType := param.Type()
valueBits := valueType.IntTypeWidth()
intrinsicName := "llvm.ctlz.i" + strconv.Itoa(valueBits)
llvmFn := b.mod.NamedFunction(intrinsicName)
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType, b.ctx.Int1Type()}, false)
if llvmFn.IsNil() {
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
}
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{
param,
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
}, "")
result = b.createZExtOrTrunc(result, b.intType)
maxLen := llvm.ConstInt(b.intType, uint64(valueBits), false) // number of bits in the value
result = b.CreateSub(maxLen, result, "")
b.CreateRet(result)
return true
case "OnesCount", "OnesCount8", "OnesCount16", "OnesCount32", "OnesCount64":
b.createFunctionStart(true)
param := b.getValue(b.fn.Params[0], b.fn.Pos())
valueType := param.Type()
intrinsicName := "llvm.ctpop.i" + strconv.Itoa(valueType.IntTypeWidth())
llvmFn := b.mod.NamedFunction(intrinsicName)
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType}, false)
if llvmFn.IsNil() {
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
}
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{param}, "")
result = b.createZExtOrTrunc(result, b.intType)
b.CreateRet(result)
return true
case "Reverse", "Reverse8", "Reverse16", "Reverse32", "Reverse64",
"ReverseBytes", "ReverseBytes16", "ReverseBytes32", "ReverseBytes64":
b.createFunctionStart(true)
param := b.getValue(b.fn.Params[0], b.fn.Pos())
valueType := param.Type()
var intrinsicName string
if strings.HasPrefix(name, "ReverseBytes") {
intrinsicName = "llvm.bswap.i" + strconv.Itoa(valueType.IntTypeWidth())
} else { // Reverse
intrinsicName = "llvm.bitreverse.i" + strconv.Itoa(valueType.IntTypeWidth())
}
llvmFn := b.mod.NamedFunction(intrinsicName)
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType}, false)
if llvmFn.IsNil() {
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
}
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{param}, "")
b.CreateRet(result)
return true
case "RotateLeft", "RotateLeft8", "RotateLeft16", "RotateLeft32", "RotateLeft64":
// Warning: the documentation says these functions must be constant time.
// I do not think LLVM guarantees this, but there's a good chance LLVM
// already recognized the rotate instruction so it probably won't get
// any _worse_ by implementing these rotate functions.
b.createFunctionStart(true)
x := b.getValue(b.fn.Params[0], b.fn.Pos())
k := b.getValue(b.fn.Params[1], b.fn.Pos())
valueType := x.Type()
intrinsicName := "llvm.fshl.i" + strconv.Itoa(valueType.IntTypeWidth())
llvmFn := b.mod.NamedFunction(intrinsicName)
llvmFnType := llvm.FunctionType(valueType, []llvm.Type{valueType, valueType, valueType}, false)
if llvmFn.IsNil() {
llvmFn = llvm.AddFunction(b.mod, intrinsicName, llvmFnType)
}
k = b.createZExtOrTrunc(k, valueType)
result := b.createCall(llvmFnType, llvmFn, []llvm.Value{x, x, k}, "")
b.CreateRet(result)
return true
default:
return false
}
}
+2 -5
View File
@@ -31,7 +31,7 @@ func (c *checker) checkType(t llvm.Type, checked map[llvm.Type]struct{}, special
return fmt.Errorf("type %q uses global context", t.String())
default:
// we used some other context by accident
return fmt.Errorf("type %q uses context %v instead of the main context %v", t.Context(), c.ctx)
return fmt.Errorf("type %q uses context %v instead of the main context %v", t.String(), t.Context(), c.ctx)
}
// if this is a composite type, check the components of the type
@@ -70,10 +70,7 @@ func (c *checker) checkType(t llvm.Type, checked map[llvm.Type]struct{}, special
return fmt.Errorf("failed to verify element type of array type %s: %s", t.String(), err.Error())
}
case llvm.PointerTypeKind:
// check underlying type
if err := c.checkType(t.ElementType(), checked, specials); err != nil {
return fmt.Errorf("failed to verify underlying type of pointer type %s: %s", t.String(), err.Error())
}
// Pointers can't be checked in an opaque pointer world.
case llvm.VectorTypeKind:
// check element type
if err := c.checkType(t.ElementType(), checked, specials); err != nil {
+438 -21
View File
@@ -1,6 +1,12 @@
package compiler
import (
"fmt"
"go/token"
"go/types"
"math/big"
"strings"
"github.com/tinygo-org/tinygo/compiler/llvmutil"
"tinygo.org/x/go-llvm"
)
@@ -8,31 +14,33 @@ import (
// This file contains helper functions for LLVM that are not exposed in the Go
// bindings.
// Return a list of values (actually, instructions) where this value is used as
// an operand.
func getUses(value llvm.Value) []llvm.Value {
if value.IsNil() {
return nil
}
var uses []llvm.Value
use := value.FirstUse()
for !use.IsNil() {
uses = append(uses, use.User())
use = use.NextUse()
}
return uses
}
// createTemporaryAlloca creates a new alloca in the entry block and adds
// lifetime start information in the IR signalling that the alloca won't be used
// before this point.
//
// This is useful for creating temporary allocas for intrinsics. Don't forget to
// end the lifetime using emitLifetimeEnd after you're done with it.
func (b *builder) createTemporaryAlloca(t llvm.Type, name string) (alloca, bitcast, size llvm.Value) {
func (b *builder) createTemporaryAlloca(t llvm.Type, name string) (alloca, size llvm.Value) {
return llvmutil.CreateTemporaryAlloca(b.Builder, b.mod, t, name)
}
// insertBasicBlock inserts a new basic block after the current basic block.
// This is useful when inserting new basic blocks while converting a
// *ssa.BasicBlock to a llvm.BasicBlock and the LLVM basic block needs some
// extra blocks.
// It does not update b.blockExits, this must be done by the caller.
func (b *builder) insertBasicBlock(name string) llvm.BasicBlock {
currentBB := b.Builder.GetInsertBlock()
nextBB := llvm.NextBasicBlock(currentBB)
if nextBB.IsNil() {
// Last basic block in the function, so add one to the end.
return b.ctx.AddBasicBlock(b.llvmFn, name)
}
// Insert a basic block before the next basic block - that is, at the
// current insert location.
return b.ctx.InsertBasicBlock(nextBB, name)
}
// emitLifetimeEnd signals the end of an (alloca) lifetime by calling the
// llvm.lifetime.end intrinsic. It is commonly used together with
// createTemporaryAlloca.
@@ -43,27 +51,436 @@ func (b *builder) emitLifetimeEnd(ptr, size llvm.Value) {
// emitPointerPack packs the list of values into a single pointer value using
// bitcasts, or else allocates a value on the heap if it cannot be packed in the
// pointer value directly. It returns the pointer with the packed data.
// If the values are all constants, they are be stored in a constant global and
// deduplicated.
func (b *builder) emitPointerPack(values []llvm.Value) llvm.Value {
return llvmutil.EmitPointerPack(b.Builder, b.mod, b.NeedsStackObjects, values)
valueTypes := make([]llvm.Type, len(values))
for i, value := range values {
valueTypes[i] = value.Type()
}
packedType := b.ctx.StructType(valueTypes, false)
// Allocate memory for the packed data.
size := b.targetData.TypeAllocSize(packedType)
if size == 0 {
return llvm.ConstPointerNull(b.dataPtrType)
} else if len(values) == 1 && values[0].Type().TypeKind() == llvm.PointerTypeKind {
return values[0]
} else if size <= b.targetData.TypeAllocSize(b.dataPtrType) {
// Packed data fits in a pointer, so store it directly inside the
// pointer.
if len(values) == 1 && values[0].Type().TypeKind() == llvm.IntegerTypeKind {
// Try to keep this cast in SSA form.
return b.CreateIntToPtr(values[0], b.dataPtrType, "pack.int")
}
// Because packedType is a struct and we have to cast it to a *i8, store
// it in a *i8 alloca first and load the *i8 value from there. This is
// effectively a bitcast.
packedAlloc, _ := b.createTemporaryAlloca(b.dataPtrType, "")
if size < b.targetData.TypeAllocSize(b.dataPtrType) {
// The alloca is bigger than the value that will be stored in it.
// To avoid having some bits undefined, zero the alloca first.
// Hopefully this will get optimized away.
b.CreateStore(llvm.ConstNull(b.dataPtrType), packedAlloc)
}
// Store all values in the alloca.
for i, value := range values {
indices := []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false),
}
gep := b.CreateInBoundsGEP(packedType, packedAlloc, indices, "")
b.CreateStore(value, gep)
}
// Load value (the *i8) from the alloca.
result := b.CreateLoad(b.dataPtrType, packedAlloc, "")
// End the lifetime of the alloca, to help the optimizer.
packedSize := llvm.ConstInt(b.ctx.Int64Type(), b.targetData.TypeAllocSize(packedAlloc.Type()), false)
b.emitLifetimeEnd(packedAlloc, packedSize)
return result
} else {
// Check if the values are all constants.
constant := true
for _, v := range values {
if !v.IsConstant() {
constant = false
break
}
}
if constant {
// The data is known at compile time, so store it in a constant global.
// The global address is marked as unnamed, which allows LLVM to merge duplicates.
global := llvm.AddGlobal(b.mod, packedType, b.pkg.Path()+"$pack")
global.SetInitializer(b.ctx.ConstStruct(values, false))
global.SetGlobalConstant(true)
global.SetUnnamedAddr(true)
global.SetLinkage(llvm.InternalLinkage)
return global
}
// Packed data is bigger than a pointer, so allocate it on the heap.
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
alloc := b.mod.NamedFunction("runtime.alloc")
packedAlloc := b.CreateCall(alloc.GlobalValueType(), alloc, []llvm.Value{
sizeValue,
llvm.ConstNull(b.dataPtrType),
llvm.Undef(b.dataPtrType), // unused context parameter
}, "")
if b.NeedsStackObjects {
b.trackPointer(packedAlloc)
}
// Store all values in the heap pointer.
for i, value := range values {
indices := []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false),
}
gep := b.CreateInBoundsGEP(packedType, packedAlloc, indices, "")
b.CreateStore(value, gep)
}
// Return the original heap allocation pointer, which already is an *i8.
return packedAlloc
}
}
// emitPointerUnpack extracts a list of values packed using emitPointerPack.
func (b *builder) emitPointerUnpack(ptr llvm.Value, valueTypes []llvm.Type) []llvm.Value {
return llvmutil.EmitPointerUnpack(b.Builder, b.mod, ptr, valueTypes)
packedType := b.ctx.StructType(valueTypes, false)
// Get a correctly-typed pointer to the packed data.
var packedAlloc llvm.Value
needsLifetimeEnd := false
size := b.targetData.TypeAllocSize(packedType)
if size == 0 {
// No data to unpack.
} else if len(valueTypes) == 1 && valueTypes[0].TypeKind() == llvm.PointerTypeKind {
// A single pointer is always stored directly.
return []llvm.Value{ptr}
} else if size <= b.targetData.TypeAllocSize(b.dataPtrType) {
// Packed data stored directly in pointer.
if len(valueTypes) == 1 && valueTypes[0].TypeKind() == llvm.IntegerTypeKind {
// Keep this cast in SSA form.
return []llvm.Value{b.CreatePtrToInt(ptr, valueTypes[0], "unpack.int")}
}
// Fallback: load it using an alloca.
packedAlloc, _ = b.createTemporaryAlloca(b.dataPtrType, "unpack.raw.alloc")
b.CreateStore(ptr, packedAlloc)
needsLifetimeEnd = true
} else {
// Packed data stored on the heap.
packedAlloc = ptr
}
// Load each value from the packed data.
values := make([]llvm.Value, len(valueTypes))
for i, valueType := range valueTypes {
if b.targetData.TypeAllocSize(valueType) == 0 {
// This value has length zero, so there's nothing to load.
values[i] = llvm.ConstNull(valueType)
continue
}
indices := []llvm.Value{
llvm.ConstInt(b.ctx.Int32Type(), 0, false),
llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false),
}
gep := b.CreateInBoundsGEP(packedType, packedAlloc, indices, "")
values[i] = b.CreateLoad(valueType, gep, "")
}
if needsLifetimeEnd {
allocSize := llvm.ConstInt(b.ctx.Int64Type(), b.targetData.TypeAllocSize(b.uintptrType), false)
b.emitLifetimeEnd(packedAlloc, allocSize)
}
return values
}
// makeGlobalArray creates a new LLVM global with the given name and integers as
// contents, and returns the global.
// contents, and returns the global and initializer type.
// Note that it is left with the default linkage etc., you should set
// linkage/constant/etc properties yourself.
func (c *compilerContext) makeGlobalArray(buf []byte, name string, elementType llvm.Type) llvm.Value {
func (c *compilerContext) makeGlobalArray(buf []byte, name string, elementType llvm.Type) (llvm.Type, llvm.Value) {
globalType := llvm.ArrayType(elementType, len(buf))
global := llvm.AddGlobal(c.mod, globalType, name)
value := llvm.Undef(globalType)
for i := 0; i < len(buf); i++ {
ch := uint64(buf[i])
value = llvm.ConstInsertValue(value, llvm.ConstInt(elementType, ch, false), []uint32{uint32(i)})
value = c.builder.CreateInsertValue(value, llvm.ConstInt(elementType, ch, false), i, "")
}
global.SetInitializer(value)
return globalType, global
}
// createObjectLayout returns a LLVM value (of type i8*) that describes where
// there are pointers in the type t. If all the data fits in a word, it is
// returned as a word. Otherwise it will store the data in a global.
//
// The value contains two pieces of information: the length of the object and
// which words contain a pointer (indicated by setting the given bit to 1). For
// arrays, only the element is stored. This works because the GC knows the
// object size and can therefore know how this value is repeated in the object.
//
// For details on what's in this value, see src/runtime/gc_precise.go.
func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Value {
// Use the element type for arrays. This works even for nested arrays.
for {
kind := t.TypeKind()
if kind == llvm.ArrayTypeKind {
t = t.ElementType()
continue
}
if kind == llvm.StructTypeKind {
fields := t.StructElementTypes()
if len(fields) == 1 {
t = fields[0]
continue
}
}
break
}
// Do a few checks to see whether we need to generate any object layout
// information at all.
objectSizeBytes := c.targetData.TypeAllocSize(t)
pointerSize := c.targetData.TypeAllocSize(c.dataPtrType)
pointerAlignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
if objectSizeBytes < pointerSize {
// Too small to contain a pointer.
layout := (uint64(1) << 1) | 1
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
}
bitmap := c.getPointerBitmap(t, pos)
if bitmap.BitLen() == 0 {
// There are no pointers in this type, so we can simplify the layout.
// TODO: this can be done in many other cases, e.g. when allocating an
// array (like [4][]byte, which repeats a slice 4 times).
layout := (uint64(1) << 1) | 1
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
}
if objectSizeBytes%uint64(pointerAlignment) != 0 {
// This shouldn't happen except for packed structs, which aren't
// currently used.
c.addError(pos, "internal error: unexpected object size for object with pointer field")
return llvm.ConstNull(c.dataPtrType)
}
objectSizeWords := objectSizeBytes / uint64(pointerAlignment)
pointerBits := pointerSize * 8
var sizeFieldBits uint64
switch pointerBits {
case 16:
sizeFieldBits = 4
case 32:
sizeFieldBits = 5
case 64:
sizeFieldBits = 6
default:
panic("unknown pointer size")
}
layoutFieldBits := pointerBits - 1 - sizeFieldBits
// Try to emit the value as an inline integer. This is possible in most
// cases.
if objectSizeWords < layoutFieldBits {
// If it can be stored directly in the pointer value, do so.
// The runtime knows that if the least significant bit of the pointer is
// set, the pointer contains the value itself.
layout := bitmap.Uint64()<<(sizeFieldBits+1) | (objectSizeWords << 1) | 1
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
}
// Unfortunately, the object layout is too big to fit in a pointer-sized
// integer. Store it in a global instead.
// Try first whether the global already exists. All objects with a
// particular name have the same type, so this is possible.
globalName := "runtime/gc.layout:" + fmt.Sprintf("%d-%0*x", objectSizeWords, (objectSizeWords+15)/16, bitmap)
global := c.mod.NamedGlobal(globalName)
if !global.IsNil() {
return global
}
// Create the global initializer.
bitmapBytes := make([]byte, int(objectSizeWords+7)/8)
bitmap.FillBytes(bitmapBytes)
reverseBytes(bitmapBytes) // big-endian to little-endian
var bitmapByteValues []llvm.Value
for _, b := range bitmapBytes {
bitmapByteValues = append(bitmapByteValues, llvm.ConstInt(c.ctx.Int8Type(), uint64(b), false))
}
initializer := c.ctx.ConstStruct([]llvm.Value{
llvm.ConstInt(c.uintptrType, objectSizeWords, false),
llvm.ConstArray(c.ctx.Int8Type(), bitmapByteValues),
}, false)
global = llvm.AddGlobal(c.mod, initializer.Type(), globalName)
global.SetInitializer(initializer)
global.SetUnnamedAddr(true)
global.SetGlobalConstant(true)
global.SetLinkage(llvm.LinkOnceODRLinkage)
if c.targetData.PrefTypeAlignment(c.uintptrType) < 2 {
// AVR doesn't have alignment by default.
global.SetAlignment(2)
}
if c.Debug && pos != token.NoPos {
// Creating a fake global so that the value can be inspected in GDB.
// For example, the layout for strings.stringFinder (as of Go version
// 1.15) has the following type according to GDB:
// type = struct {
// uintptr numBits;
// uint8 data[33];
// }
// ...that's sort of a mixed C/Go type, but it is readable. More
// importantly, these object layout globals can be read and printed by
// GDB which may be useful for debugging.
position := c.program.Fset.Position(pos)
diglobal := c.dibuilder.CreateGlobalVariableExpression(c.difiles[position.Filename], llvm.DIGlobalVariableExpression{
Name: globalName,
File: c.getDIFile(position.Filename),
Line: position.Line,
Type: c.getDIType(types.NewStruct([]*types.Var{
types.NewVar(pos, nil, "numBits", types.Typ[types.Uintptr]),
types.NewVar(pos, nil, "data", types.NewArray(types.Typ[types.Byte], int64(len(bitmapByteValues)))),
}, nil)),
LocalToUnit: false,
Expr: c.dibuilder.CreateExpression(nil),
})
global.AddMetadata(0, diglobal)
}
return global
}
// getPointerBitmap scans the given LLVM type for pointers and sets bits in a
// bigint at the word offset that contains a pointer. This scan is recursive.
func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.Int {
alignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
switch typ.TypeKind() {
case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
return big.NewInt(0)
case llvm.PointerTypeKind:
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 {
continue
}
offset := c.targetData.ElementOffset(typ, i)
if offset%uint64(alignment) != 0 {
// This error will let the compilation fail, but by continuing
// the error can still easily be shown.
c.addError(pos, "internal error: allocated struct contains unaligned pointer")
continue
}
subptrs.Lsh(subptrs, uint(offset)/uint(alignment))
ptrs.Or(ptrs, subptrs)
}
return ptrs
case llvm.ArrayTypeKind:
subtyp := typ.ElementType()
subptrs := c.getPointerBitmap(subtyp, pos)
ptrs := big.NewInt(0)
if subptrs.BitLen() == 0 {
return ptrs
}
elementSize := c.targetData.TypeAllocSize(subtyp)
if elementSize%uint64(alignment) != 0 {
// This error will let the compilation fail (but continues so that
// other errors can be shown).
c.addError(pos, "internal error: allocated array contains unaligned pointer")
return ptrs
}
for i := 0; i < typ.ArrayLength(); i++ {
ptrs.Lsh(ptrs, uint(elementSize)/uint(alignment))
ptrs.Or(ptrs, subptrs)
}
return ptrs
default:
// Should not happen.
panic("unknown LLVM type")
}
}
// archFamily returns the archtecture from the LLVM triple but with some
// architecture names ("armv6", "thumbv7m", etc) merged into a single
// architecture name ("arm").
func (c *compilerContext) archFamily() string {
arch := strings.Split(c.Triple, "-")[0]
if strings.HasPrefix(arch, "arm64") {
return "aarch64"
}
if strings.HasPrefix(arch, "arm") || strings.HasPrefix(arch, "thumb") {
return "arm"
}
return arch
}
// isThumb returns whether we're in ARM or in Thumb mode. It panics if the
// features string is not one for an ARM architecture.
func (c *compilerContext) isThumb() bool {
var isThumb, isNotThumb bool
for _, feature := range strings.Split(c.Features, ",") {
if feature == "+thumb-mode" {
isThumb = true
}
if feature == "-thumb-mode" {
isNotThumb = true
}
}
if isThumb == isNotThumb {
panic("unexpected feature flags")
}
return isThumb
}
// readStackPointer emits a LLVM intrinsic call that returns the current stack
// pointer as an *i8.
func (b *builder) readStackPointer() llvm.Value {
name := "llvm.stacksave.p0"
if llvmutil.Version() < 18 {
name = "llvm.stacksave" // backwards compatibility with LLVM 17 and below
}
stacksave := b.mod.NamedFunction(name)
if stacksave.IsNil() {
fnType := llvm.FunctionType(b.dataPtrType, nil, false)
stacksave = llvm.AddFunction(b.mod, name, fnType)
}
return b.CreateCall(stacksave.GlobalValueType(), stacksave, nil, "")
}
// 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 {
valueBits := value.Type().IntTypeWidth()
resultBits := t.IntTypeWidth()
if valueBits > resultBits {
value = b.CreateTrunc(value, t, "")
} else if valueBits < resultBits {
value = b.CreateZExt(value, t, "")
}
return value
}
// Reverse a slice of bytes. From the wiki:
// https://github.com/golang/go/wiki/SliceTricks#reversing
func reverseBytes(buf []byte) {
for i := len(buf)/2 - 1; i >= 0; i-- {
opp := len(buf) - 1 - i
buf[i], buf[opp] = buf[opp], buf[i]
}
}
+74 -24
View File
@@ -1,5 +1,5 @@
// Package llvmutil contains utility functions used across multiple compiler
// packages. For example, they may be used by both the compiler pacakge and
// packages. For example, they may be used by both the compiler package and
// transformation packages.
//
// Normally, utility packages are avoided. However, in this case, the utility
@@ -7,7 +7,12 @@
// places would be a big risk if only one of them is updated.
package llvmutil
import "tinygo.org/x/go-llvm"
import (
"strconv"
"strings"
"tinygo.org/x/go-llvm"
)
// CreateEntryBlockAlloca creates a new alloca in the entry block, even though
// the IR builder is located elsewhere. It assumes that the insert point is
@@ -26,19 +31,19 @@ func CreateEntryBlockAlloca(builder llvm.Builder, t llvm.Type, name string) llvm
}
// CreateTemporaryAlloca creates a new alloca in the entry block and adds
// lifetime start infromation in the IR signalling that the alloca won't be used
// lifetime start information in the IR signalling that the alloca won't be used
// before this point.
//
// This is useful for creating temporary allocas for intrinsics. Don't forget to
// end the lifetime using emitLifetimeEnd after you're done with it.
func CreateTemporaryAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, name string) (alloca, bitcast, size llvm.Value) {
func CreateTemporaryAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, name string) (alloca, size llvm.Value) {
ctx := t.Context()
targetData := llvm.NewTargetData(mod.DataLayout())
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
defer targetData.Dispose()
alloca = CreateEntryBlockAlloca(builder, t, name)
bitcast = builder.CreateBitCast(alloca, i8ptrType, name+".bitcast")
size = llvm.ConstInt(ctx.Int64Type(), targetData.TypeAllocSize(t), false)
builder.CreateCall(getLifetimeStartFunc(mod), []llvm.Value{size, bitcast}, "")
fnType, fn := getLifetimeStartFunc(mod)
builder.CreateCall(fnType, fn, []llvm.Value{size, alloca}, "")
return
}
@@ -46,19 +51,20 @@ func CreateTemporaryAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, n
func CreateInstructionAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type, inst llvm.Value, name string) llvm.Value {
ctx := mod.Context()
targetData := llvm.NewTargetData(mod.DataLayout())
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
defer targetData.Dispose()
alloca := CreateEntryBlockAlloca(builder, t, name)
builder.SetInsertPointBefore(inst)
bitcast := builder.CreateBitCast(alloca, i8ptrType, name+".bitcast")
size := llvm.ConstInt(ctx.Int64Type(), targetData.TypeAllocSize(t), false)
builder.CreateCall(getLifetimeStartFunc(mod), []llvm.Value{size, bitcast}, "")
fnType, fn := getLifetimeStartFunc(mod)
builder.CreateCall(fnType, fn, []llvm.Value{size, alloca}, "")
if next := llvm.NextInstruction(inst); !next.IsNil() {
builder.SetInsertPointBefore(next)
} else {
builder.SetInsertPointAtEnd(inst.InstructionParent())
}
builder.CreateCall(getLifetimeEndFunc(mod), []llvm.Value{size, bitcast}, "")
fnType, fn = getLifetimeEndFunc(mod)
builder.CreateCall(fnType, fn, []llvm.Value{size, alloca}, "")
return alloca
}
@@ -66,33 +72,36 @@ func CreateInstructionAlloca(builder llvm.Builder, mod llvm.Module, t llvm.Type,
// llvm.lifetime.end intrinsic. It is commonly used together with
// createTemporaryAlloca.
func EmitLifetimeEnd(builder llvm.Builder, mod llvm.Module, ptr, size llvm.Value) {
builder.CreateCall(getLifetimeEndFunc(mod), []llvm.Value{size, ptr}, "")
fnType, fn := getLifetimeEndFunc(mod)
builder.CreateCall(fnType, fn, []llvm.Value{size, ptr}, "")
}
// getLifetimeStartFunc returns the llvm.lifetime.start intrinsic and creates it
// first if it doesn't exist yet.
func getLifetimeStartFunc(mod llvm.Module) llvm.Value {
fn := mod.NamedFunction("llvm.lifetime.start.p0i8")
func getLifetimeStartFunc(mod llvm.Module) (llvm.Type, llvm.Value) {
fnName := "llvm.lifetime.start.p0"
fn := mod.NamedFunction(fnName)
ctx := mod.Context()
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
ptrType := llvm.PointerType(ctx.Int8Type(), 0)
fnType := llvm.FunctionType(ctx.VoidType(), []llvm.Type{ctx.Int64Type(), ptrType}, false)
if fn.IsNil() {
fnType := llvm.FunctionType(ctx.VoidType(), []llvm.Type{ctx.Int64Type(), i8ptrType}, false)
fn = llvm.AddFunction(mod, "llvm.lifetime.start.p0i8", fnType)
fn = llvm.AddFunction(mod, fnName, fnType)
}
return fn
return fnType, fn
}
// getLifetimeEndFunc returns the llvm.lifetime.end intrinsic and creates it
// first if it doesn't exist yet.
func getLifetimeEndFunc(mod llvm.Module) llvm.Value {
fn := mod.NamedFunction("llvm.lifetime.end.p0i8")
func getLifetimeEndFunc(mod llvm.Module) (llvm.Type, llvm.Value) {
fnName := "llvm.lifetime.end.p0"
fn := mod.NamedFunction(fnName)
ctx := mod.Context()
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
ptrType := llvm.PointerType(ctx.Int8Type(), 0)
fnType := llvm.FunctionType(ctx.VoidType(), []llvm.Type{ctx.Int64Type(), ptrType}, false)
if fn.IsNil() {
fnType := llvm.FunctionType(ctx.VoidType(), []llvm.Type{ctx.Int64Type(), i8ptrType}, false)
fn = llvm.AddFunction(mod, "llvm.lifetime.end.p0i8", fnType)
fn = llvm.AddFunction(mod, fnName, fnType)
}
return fn
return fnType, fn
}
// SplitBasicBlock splits a LLVM basic block into two parts. All instructions
@@ -166,3 +175,44 @@ func SplitBasicBlock(builder llvm.Builder, afterInst llvm.Value, insertAfter llv
return newBlock
}
// AppendToGlobal appends the given values to a global array like llvm.used. The global might
// not exist yet. The values can be any pointer type, they will be cast to i8*.
func AppendToGlobal(mod llvm.Module, globalName string, values ...llvm.Value) {
// Read the existing values in the llvm.used array (if it exists).
var usedValues []llvm.Value
if used := mod.NamedGlobal(globalName); !used.IsNil() {
builder := mod.Context().NewBuilder()
defer builder.Dispose()
usedInitializer := used.Initializer()
num := usedInitializer.Type().ArrayLength()
for i := 0; i < num; i++ {
usedValues = append(usedValues, builder.CreateExtractValue(usedInitializer, i, ""))
}
used.EraseFromParentAsGlobal()
}
// Add the new values.
ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
for _, value := range values {
// Note: the bitcast is necessary to cast AVR function pointers to
// address space 0 pointer types.
usedValues = append(usedValues, llvm.ConstPointerCast(value, ptrType))
}
// Create a new array (with the old and new values).
usedInitializer := llvm.ConstArray(ptrType, usedValues)
used := llvm.AddGlobal(mod, usedInitializer.Type(), globalName)
used.SetInitializer(usedInitializer)
used.SetLinkage(llvm.AppendingLinkage)
}
// Return the LLVM major version.
func Version() int {
majorStr := strings.Split(llvm.Version, ".")[0]
major, err := strconv.Atoi(majorStr)
if err != nil {
panic("unexpected error while parsing LLVM version: " + err.Error()) // should not happen
}
return major
}

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