Compare commits

..

111 Commits

Author SHA1 Message Date
Ayke van Laethem df8add7b60 machine: add tool to check consistency with documentation
This tool checks whether the machine package matches the documentation
in https://tinygo.org/docs/reference/machine/.
2022-09-26 16:50:14 +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
332 changed files with 3974 additions and 2381 deletions
+4 -13
View File
@@ -112,26 +112,17 @@ commands:
- /go/pkg/mod - /go/pkg/mod
jobs: jobs:
test-llvm13-go116: test-llvm14-go118:
docker: docker:
- image: golang:1.16-buster - image: golang:1.18-buster
steps:
- test-linux:
llvm: "13"
test-llvm14-go119:
docker:
- image: golang:1.19beta1-buster
steps: steps:
- test-linux: - test-linux:
llvm: "14" llvm: "14"
fmt-check: false resource_class: large
workflows: workflows:
test-all: test-all:
jobs: jobs:
# This tests our lowest supported versions of Go and LLVM, to make sure at # This tests our lowest supported versions of Go and LLVM, to make sure at
# least the smoke tests still pass. # least the smoke tests still pass.
- test-llvm13-go116 - test-llvm14-go118
# This tests a beta version of Go. It should be removed once regular
# release builds are built using this version.
- test-llvm14-go119
+27 -7
View File
@@ -16,10 +16,6 @@ jobs:
name: build-macos name: build-macos
runs-on: macos-11 runs-on: macos-11
steps: steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: '1.18.1'
- name: Install Dependencies - name: Install Dependencies
shell: bash shell: bash
run: | run: |
@@ -35,8 +31,13 @@ jobs:
uses: actions/checkout@v2 uses: actions/checkout@v2
with: with:
submodules: true submodules: true
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.19'
cache: true
- name: Cache LLVM source - name: Cache LLVM source
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-14-macos-v1 key: llvm-source-14-macos-v1
@@ -50,7 +51,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Cache LLVM build - name: Cache LLVM build
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-14-macos-v1 key: llvm-build-14-macos-v1
@@ -68,7 +69,7 @@ jobs:
make llvm-build make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Cache wasi-libc sysroot - name: Cache wasi-libc sysroot
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-wasi-libc id: cache-wasi-libc
with: with:
key: wasi-libc-sysroot-v4 key: wasi-libc-sysroot-v4
@@ -100,3 +101,22 @@ jobs:
- name: Smoke tests - name: Smoke tests
shell: bash shell: bash
run: make smoketest TINYGO=$(PWD)/build/tinygo AVR=0 run: make smoketest TINYGO=$(PWD)/build/tinygo AVR=0
test-macos-homebrew:
name: homebrew-install
runs-on: macos-latest
steps:
- name: Install LLVM
shell: bash
run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@14
- name: Checkout
uses: actions/checkout@v2
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.19'
cache: true
- name: Build TinyGo
run: go install
- name: Check binary
run: tinygo version
+35 -52
View File
@@ -18,14 +18,13 @@ jobs:
# statically linked binary. # statically linked binary.
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: alpine:3.16 image: golang:1.19-alpine
steps: steps:
- name: Install apk dependencies - name: Install apk dependencies
# tar: needed for actions/cache@v2 # tar: needed for actions/cache@v3
# git+openssh: needed for checkout (I think?) # git+openssh: needed for checkout (I think?)
# gcompat: needed for go binary
# ruby: needed to install fpm # ruby: needed to install fpm
run: apk add tar git openssh gcompat make g++ ruby run: apk add tar git openssh make g++ ruby
- name: Work around CVE-2022-24765 - name: Work around CVE-2022-24765
# We're not on a multi-user machine, so this is safe. # We're not on a multi-user machine, so this is safe.
run: git config --global --add safe.directory "$GITHUB_WORKSPACE" run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
@@ -33,19 +32,15 @@ jobs:
uses: actions/checkout@v2 uses: actions/checkout@v2
with: with:
submodules: true submodules: true
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: '1.18.1'
- name: Cache Go - name: Cache Go
uses: actions/cache@v2 uses: actions/cache@v3
with: with:
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }} key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
path: | path: |
~/.cache/go-build ~/.cache/go-build
~/go/pkg/mod ~/go/pkg/mod
- name: Cache LLVM source - name: Cache LLVM source
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-14-linux-alpine-v1 key: llvm-source-14-linux-alpine-v1
@@ -59,7 +54,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Cache LLVM build - name: Cache LLVM build
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-14-linux-alpine-v1 key: llvm-build-14-linux-alpine-v1
@@ -77,7 +72,7 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Cache Binaryen - name: Cache Binaryen
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-binaryen id: cache-binaryen
with: with:
key: binaryen-linux-alpine-v1 key: binaryen-linux-alpine-v1
@@ -88,7 +83,7 @@ jobs:
apk add cmake samurai python3 apk add cmake samurai python3
make binaryen STATIC=1 make binaryen STATIC=1
- name: Cache wasi-libc - name: Cache wasi-libc
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-wasi-libc id: cache-wasi-libc
with: with:
key: wasi-libc-sysroot-linux-alpine-v1 key: wasi-libc-sysroot-linux-alpine-v1
@@ -98,6 +93,7 @@ jobs:
run: make wasi-libc run: make wasi-libc
- name: Install fpm - name: Install fpm
run: | run: |
gem install --version 4.0.7 public_suffix
gem install --version 2.7.6 dotenv gem install --version 2.7.6 dotenv
gem install --no-document fpm gem install --no-document fpm
- name: Build TinyGo release - name: Build TinyGo release
@@ -120,9 +116,10 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Install Go - name: Install Go
uses: actions/setup-go@v2 uses: actions/setup-go@v3
with: with:
go-version: '1.18.1' go-version: '1.19'
cache: true
- name: Install wasmtime - name: Install wasmtime
run: | run: |
curl https://wasmtime.dev/install.sh -sSf | bash curl https://wasmtime.dev/install.sh -sSf | bash
@@ -172,9 +169,10 @@ jobs:
simavr \ simavr \
ninja-build ninja-build
- name: Install Go - name: Install Go
uses: actions/setup-go@v2 uses: actions/setup-go@v3
with: with:
go-version: '1.18.1' go-version: '1.19'
cache: true
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v2 uses: actions/setup-node@v2
with: with:
@@ -183,15 +181,8 @@ jobs:
run: | run: |
curl https://wasmtime.dev/install.sh -sSf | bash curl https://wasmtime.dev/install.sh -sSf | bash
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
- name: Cache Go
uses: actions/cache@v2
with:
key: go-cache-linux-asserts-v1-${{ hashFiles('go.mod') }}
path: |
~/.cache/go-build
~/go/pkg/mod
- name: Cache LLVM source - name: Cache LLVM source
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-14-linux-asserts-v2 key: llvm-source-14-linux-asserts-v2
@@ -205,7 +196,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Cache LLVM build - name: Cache LLVM build
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-14-linux-asserts-v1 key: llvm-build-14-linux-asserts-v1
@@ -221,7 +212,7 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Cache Binaryen - name: Cache Binaryen
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-binaryen id: cache-binaryen
with: with:
key: binaryen-linux-asserts-v1 key: binaryen-linux-asserts-v1
@@ -230,7 +221,7 @@ jobs:
if: steps.cache-binaryen.outputs.cache-hit != 'true' if: steps.cache-binaryen.outputs.cache-hit != 'true'
run: make binaryen run: make binaryen
- name: Cache wasi-libc - name: Cache wasi-libc
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-wasi-libc id: cache-wasi-libc
with: with:
key: wasi-libc-sysroot-linux-asserts-v5 key: wasi-libc-sysroot-linux-asserts-v5
@@ -245,6 +236,8 @@ jobs:
run: | run: |
make ASSERT=1 make ASSERT=1
echo "$(pwd)/build" >> $GITHUB_PATH echo "$(pwd)/build" >> $GITHUB_PATH
- name: Test machine package
run: make check-machine
- name: Test stdlib packages - name: Test stdlib packages
run: make tinygo-test run: make tinygo-test
- name: Install Xtensa toolchain - name: Install Xtensa toolchain
@@ -278,18 +271,12 @@ jobs:
g++-arm-linux-gnueabihf \ g++-arm-linux-gnueabihf \
libc6-dev-armhf-cross libc6-dev-armhf-cross
- name: Install Go - name: Install Go
uses: actions/setup-go@v2 uses: actions/setup-go@v3
with: with:
go-version: '1.18.1' go-version: '1.19'
- name: Cache Go cache: true
uses: actions/cache@v2
with:
key: go-cache-linux-arm-v2-${{ hashFiles('go.mod') }}
path: |
~/.cache/go-build
~/go/pkg/mod
- name: Cache LLVM source - name: Cache LLVM source
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-14-linux-v2 key: llvm-source-14-linux-v2
@@ -303,7 +290,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Cache LLVM build - name: Cache LLVM build
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-14-linux-arm-v1 key: llvm-build-14-linux-arm-v1
@@ -321,7 +308,7 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Cache Binaryen - name: Cache Binaryen
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-binaryen id: cache-binaryen
with: with:
key: binaryen-linux-arm-v1 key: binaryen-linux-arm-v1
@@ -334,6 +321,7 @@ jobs:
make CROSS=arm-linux-gnueabihf binaryen make CROSS=arm-linux-gnueabihf binaryen
- name: Install fpm - name: Install fpm
run: | run: |
sudo gem install --version 4.0.7 public_suffix
sudo gem install --version 2.7.6 dotenv sudo gem install --version 2.7.6 dotenv
sudo gem install --no-document fpm sudo gem install --no-document fpm
- name: Build TinyGo binary - name: Build TinyGo binary
@@ -383,18 +371,12 @@ jobs:
libc6-dev-arm64-cross \ libc6-dev-arm64-cross \
ninja-build ninja-build
- name: Install Go - name: Install Go
uses: actions/setup-go@v2 uses: actions/setup-go@v3
with: with:
go-version: '1.18.1' go-version: '1.19'
- name: Cache Go cache: true
uses: actions/cache@v2
with:
key: go-cache-linux-arm64-v2-${{ hashFiles('go.mod') }}
path: |
~/.cache/go-build
~/go/pkg/mod
- name: Cache LLVM source - name: Cache LLVM source
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-14-linux-v1 key: llvm-source-14-linux-v1
@@ -408,7 +390,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Cache LLVM build - name: Cache LLVM build
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-14-linux-arm64-v1 key: llvm-build-14-linux-arm64-v1
@@ -424,7 +406,7 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Cache Binaryen - name: Cache Binaryen
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-binaryen id: cache-binaryen
with: with:
key: binaryen-linux-arm64-v1 key: binaryen-linux-arm64-v1
@@ -436,6 +418,7 @@ jobs:
make CROSS=aarch64-linux-gnu binaryen make CROSS=aarch64-linux-gnu binaryen
- name: Install fpm - name: Install fpm
run: | run: |
sudo gem install --version 4.0.7 public_suffix
sudo gem install --version 2.7.6 dotenv sudo gem install --version 2.7.6 dotenv
sudo gem install --no-document fpm sudo gem install --no-document fpm
- name: Build TinyGo binary - name: Build TinyGo binary
+7 -13
View File
@@ -15,10 +15,6 @@ jobs:
build-windows: build-windows:
runs-on: windows-2022 runs-on: windows-2022
steps: steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: '1.18.1'
- uses: brechtm/setup-scoop@v2 - uses: brechtm/setup-scoop@v2
with: with:
scoop_update: 'false' scoop_update: 'false'
@@ -30,15 +26,13 @@ jobs:
uses: actions/checkout@v2 uses: actions/checkout@v2
with: with:
submodules: true submodules: true
- name: Cache Go - name: Install Go
uses: actions/cache@v2 uses: actions/setup-go@v3
with: with:
key: go-cache-windows-v1-${{ hashFiles('go.mod') }} go-version: '1.19'
path: | cache: true
~/AppData/Local/go-build
~/go/pkg/mod
- name: Cache LLVM source - name: Cache LLVM source
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-llvm-source id: cache-llvm-source
with: with:
key: llvm-source-14-windows-v2 key: llvm-source-14-windows-v2
@@ -52,7 +46,7 @@ jobs:
if: steps.cache-llvm-source.outputs.cache-hit != 'true' if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source run: make llvm-source
- name: Cache LLVM build - name: Cache LLVM build
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-llvm-build id: cache-llvm-build
with: with:
key: llvm-build-14-windows-v2 key: llvm-build-14-windows-v2
@@ -69,7 +63,7 @@ jobs:
# Remove unnecessary object files (to reduce cache size). # Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Cache wasi-libc sysroot - name: Cache wasi-libc sysroot
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-wasi-libc id: cache-wasi-libc
with: with:
key: wasi-libc-sysroot-v4 key: wasi-libc-sysroot-v4
+1 -1
View File
@@ -18,7 +18,7 @@ tarball. If you want to help with development of TinyGo itself, you should follo
LLVM, Clang and LLD are quite light on dependencies, requiring only standard 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. build tools to be built. Go is of course necessary to build TinyGo itself.
* Go (1.16+) * Go (1.18+)
* Standard build tools (gcc/clang) * Standard build tools (gcc/clang)
* git * git
* CMake * CMake
+1 -1
View File
@@ -1,5 +1,5 @@
# tinygo-llvm stage obtains the llvm source for TinyGo # tinygo-llvm stage obtains the llvm source for TinyGo
FROM golang:1.18 AS tinygo-llvm FROM golang:1.19 AS tinygo-llvm
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y apt-utils make cmake clang-11 binutils-avr gcc-avr avr-libc ninja-build apt-get install -y apt-utils make cmake clang-11 binutils-avr gcc-avr avr-libc ninja-build
+59 -11
View File
@@ -267,6 +267,18 @@ tinygo:
test: wasi-libc test: wasi-libc
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags "byollvm osusergo" ./builder ./cgo ./compileopts ./compiler ./interp ./transform . CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags "byollvm osusergo" ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
# Check whether the machine package matches the documentation.
# TODO: improve `tinygo targets` so it doesn't return these invalid targets.
CHECK_MACHINE_EXCULDE = \
cortex-m-qemu \
particle-3rd-gen \
riscv-qemu \
riscv64-qemu \
rp2040 \
$(nil)
check-machine:
$(GO) run ./tools/machinecheck $(filter-out $(CHECK_MACHINE_EXCULDE),$(shell $(TINYGO) targets))
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi # Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
TEST_PACKAGES_SLOW = \ TEST_PACKAGES_SLOW = \
compress/bzip2 \ compress/bzip2 \
@@ -280,7 +292,6 @@ TEST_PACKAGES_FAST = \
container/list \ container/list \
container/ring \ container/ring \
crypto/des \ crypto/des \
crypto/elliptic/internal/fiat \
crypto/internal/subtle \ crypto/internal/subtle \
crypto/md5 \ crypto/md5 \
crypto/rc4 \ crypto/rc4 \
@@ -317,13 +328,24 @@ TEST_PACKAGES_FAST = \
unicode \ unicode \
unicode/utf16 \ unicode/utf16 \
unicode/utf8 \ 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 # archive/zip requires os.ReadAt, which is not yet supported on windows
# compress/flate appears to hang on wasi
# compress/lzw 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 # debug/plan9obj requires os.ReadAt, which is not yet supported on windows
# io/fs requires os.ReadDir, which is not yet supported on windows or wasi # io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi
# strconv requires 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 # testing/fstest requires os.ReadDir, which is not yet supported on windows or wasi
# compress/flate fails windows go 1.18, https://github.com/tinygo-org/tinygo/issues/2762
# compress/lzw fails windows go 1.18 wasi, https://github.com/tinygo-org/tinygo/issues/2762
# Additional standard library packages that pass tests on individual platforms # Additional standard library packages that pass tests on individual platforms
TEST_PACKAGES_LINUX := \ TEST_PACKAGES_LINUX := \
@@ -333,7 +355,6 @@ TEST_PACKAGES_LINUX := \
crypto/hmac \ crypto/hmac \
debug/dwarf \ debug/dwarf \
debug/plan9obj \ debug/plan9obj \
io/fs \
io/ioutil \ io/ioutil \
strconv \ strconv \
testing/fstest \ testing/fstest \
@@ -342,7 +363,12 @@ TEST_PACKAGES_LINUX := \
TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX) TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
TEST_PACKAGES_WINDOWS := \ TEST_PACKAGES_WINDOWS := \
compress/lzw compress/flate \
compress/lzw \
crypto/hmac \
strconv \
text/template/parse \
$(nil)
# Report platforms on which each standard library package is known to pass tests # Report platforms on which each standard library package is known to pass tests
jointmp := $(shell echo /tmp/join.$$$$) jointmp := $(shell echo /tmp/join.$$$$)
@@ -357,12 +383,15 @@ report-stdlib-tests-pass:
# Standard library packages that pass tests quickly on the current platform # Standard library packages that pass tests quickly on the current platform
ifeq ($(shell uname),Darwin) ifeq ($(shell uname),Darwin)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_DARWIN) TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_DARWIN)
TEST_IOFS := true
endif endif
ifeq ($(shell uname),Linux) ifeq ($(shell uname),Linux)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_LINUX) TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_LINUX)
TEST_IOFS := true
endif endif
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS) TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
TEST_IOFS := false
endif endif
# Test known-working standard library packages. # Test known-working standard library packages.
@@ -370,6 +399,12 @@ endif
.PHONY: tinygo-test .PHONY: tinygo-test
tinygo-test: tinygo-test:
$(TINYGO) test $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW) $(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-fast:
$(TINYGO) test $(TEST_PACKAGES_HOST) $(TINYGO) test $(TEST_PACKAGES_HOST)
tinygo-bench: tinygo-bench:
@@ -379,9 +414,9 @@ tinygo-bench-fast:
# Same thing, except for wasi rather than the current platform. # Same thing, except for wasi rather than the current platform.
tinygo-test-wasi: tinygo-test-wasi:
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) $(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
tinygo-test-wasi-fast: tinygo-test-wasi-fast:
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
tinygo-bench-wasi: tinygo-bench-wasi:
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) $(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
tinygo-bench-wasi-fast: tinygo-bench-wasi-fast:
@@ -403,6 +438,7 @@ tinygo-baremetal:
.PHONY: smoketest .PHONY: smoketest
smoketest: smoketest:
$(TINYGO) version $(TINYGO) version
$(TINYGO) targets > /dev/null
# regression test for #2892 # regression test for #2892
cd tests/testing/recurse && ($(TINYGO) test ./... > recurse.log && cat recurse.log && test $$(wc -l < recurse.log) = 2 && rm recurse.log) 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 # compile-only platform-independent examples
@@ -512,6 +548,8 @@ endif
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=feather-m4 examples/blinky1
@$(MD5SUM) test.hex @$(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 $(TINYGO) build -size short -o test.hex -target=pybadge examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=metro-m4-airlift examples/blinky1 $(TINYGO) build -size short -o test.hex -target=metro-m4-airlift examples/blinky1
@@ -578,16 +616,22 @@ endif
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1
@$(MD5SUM) test.hex @$(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=macropad-rp2040 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=macropad-rp2040 examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=badger2040 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=badger2040 examples/blinky1
@$(MD5SUM) test.hex @$(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 $(TINYGO) build -size short -o test.hex -target=thingplus-rp2040 examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=xiao-rp2040 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=xiao-rp2040 examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=challenger-rp2040 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=challenger-rp2040 examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=trinkey-qt2040 examples/temp
@$(MD5SUM) test.hex
# test pwm # test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm $(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
@@ -668,14 +712,16 @@ ifneq ($(XTENSA), 0)
$(TINYGO) build -size short -o test.bin -target mch2022 examples/serial $(TINYGO) build -size short -o test.bin -target mch2022 examples/serial
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
endif endif
$(TINYGO) build -size short -o test.bin -target=esp32c3 examples/serial $(TINYGO) build -size short -o test.bin -target=esp32c3 examples/serial
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/serial
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/serial $(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/serial
@$(MD5SUM) test.bin @$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c3 examples/serial
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1 $(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
@$(MD5SUM) test.hex @$(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 $(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
ifneq ($(WASM), 0) ifneq ($(WASM), 0)
@@ -748,6 +794,7 @@ endif
@cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src @cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/malloc 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/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/signal build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/stdio 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/string build/release/tinygo/lib/musl/src
@@ -766,6 +813,7 @@ endif
@cp -rp lib/picolibc/newlib/libc/string 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/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/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/picolibc-stdio.c build/release/tinygo/lib
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot @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/lib/builtins build/release/tinygo/lib/compiler-rt-builtins
+6 -2
View File
@@ -43,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux. You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
The following 88 microcontroller boards are currently supported: The following 91 microcontroller boards are currently supported:
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333) * [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333) * [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
@@ -66,7 +66,9 @@ The following 88 microcontroller boards are currently supported:
* [Adafruit PyGamer](https://www.adafruit.com/product/4242) * [Adafruit PyGamer](https://www.adafruit.com/product/4242)
* [Adafruit PyPortal](https://www.adafruit.com/product/4116) * [Adafruit PyPortal](https://www.adafruit.com/product/4116)
* [Adafruit QT Py](https://www.adafruit.com/product/4600) * [Adafruit QT Py](https://www.adafruit.com/product/4600)
* [Adafruit QT Py RP2040](https://www.adafruit.com/product/4900)
* [Adafruit Trinket M0](https://www.adafruit.com/product/3500) * [Adafruit Trinket M0](https://www.adafruit.com/product/3500)
* [Adafruit Trinkey QT2040](https://adafruit.com/product/5056)
* [Arduino Mega 1280](https://www.arduino.cc/en/Main/arduinoBoardMega/) * [Arduino Mega 1280](https://www.arduino.cc/en/Main/arduinoBoardMega/)
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3) * [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
* [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi) * [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi)
@@ -108,6 +110,7 @@ The following 88 microcontroller boards are currently supported:
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/) * [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
* [Phytec reel board](https://www.phytec.eu/product-eu/internet-of-things/reelboard/) * [Phytec reel board](https://www.phytec.eu/product-eu/internet-of-things/reelboard/)
* [Pimoroni Badger2040](https://shop.pimoroni.com/products/badger-2040) * [Pimoroni Badger2040](https://shop.pimoroni.com/products/badger-2040)
* [Pimoroni Tufty2040](https://shop.pimoroni.com/products/tufty-2040)
* [PineTime DevKit](https://www.pine64.org/pinetime/) * [PineTime DevKit](https://www.pine64.org/pinetime/)
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html) * [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html) * [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
@@ -117,11 +120,12 @@ The following 88 microcontroller boards are currently supported:
* [Raytac MDBT50Q-RX Dongle (with TinyUF2 bootloader)](https://www.adafruit.com/product/5199) * [Raytac MDBT50Q-RX Dongle (with TinyUF2 bootloader)](https://www.adafruit.com/product/5199)
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html) * [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
* [Seeed XIAO BLE](https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html) * [Seeed XIAO BLE](https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html)
* [Seeed XIAO ESP32C3](https://www.seeedstudio.com/Seeed-XIAO-ESP32C3-p-5431.html)
* [Seeed XIAO RP2040](https://www.seeedstudio.com/XIAO-RP2040-v1-0-p-5026.html) * [Seeed XIAO RP2040](https://www.seeedstudio.com/XIAO-RP2040-v1-0-p-5026.html)
* [Seeed LoRa-E5 Development Kit](https://www.seeedstudio.com/LoRa-E5-Dev-Kit-p-4868.html) * [Seeed LoRa-E5 Development Kit](https://www.seeedstudio.com/LoRa-E5-Dev-Kit-p-4868.html)
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html) * [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) * [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
* [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1) * [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1-rev-b)
* [Sparkfun Thing Plus RP2040](https://www.sparkfun.com/products/17745) * [Sparkfun Thing Plus RP2040](https://www.sparkfun.com/products/17745)
* [ST Micro "Nucleo" F103RB](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html) * [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" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
+1 -1
View File
@@ -18,7 +18,7 @@ import (
// makeArchive creates an arcive for static linking from a list of object files // makeArchive creates an arcive for static linking from a list of object files
// given as a parameter. It is equivalent to the following command: // given as a parameter. It is equivalent to the following command:
// //
// ar -rcs <archivePath> <objs...> // ar -rcs <archivePath> <objs...>
func makeArchive(arfile *os.File, objs []string) error { func makeArchive(arfile *os.File, objs []string) error {
// Open the archive file. // Open the archive file.
arwriter := ar.NewWriter(arfile) arwriter := ar.NewWriter(arfile)
+16 -16
View File
@@ -14,7 +14,7 @@ import (
"fmt" "fmt"
"go/types" "go/types"
"hash/crc32" "hash/crc32"
"io/ioutil" "io/fs"
"math/bits" "math/bits"
"os" "os"
"os/exec" "os/exec"
@@ -103,7 +103,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
} }
// Create a temporary directory for intermediary files. // Create a temporary directory for intermediary files.
dir, err := ioutil.TempDir("", "tinygo") dir, err := os.MkdirTemp("", "tinygo")
if err != nil { if err != nil {
return err return err
} }
@@ -148,7 +148,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
libcDependencies = append(libcDependencies, libcJob) libcDependencies = append(libcDependencies, libcJob)
case "wasi-libc": case "wasi-libc":
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a") path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
if _, err := os.Stat(path); os.IsNotExist(err) { if _, err := os.Stat(path); errors.Is(err, fs.ErrNotExist) {
return errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?") return errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?")
} }
libcDependencies = append(libcDependencies, dummyCompileJob(path)) libcDependencies = append(libcDependencies, dummyCompileJob(path))
@@ -178,7 +178,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
Scheduler: config.Scheduler(), Scheduler: config.Scheduler(),
AutomaticStackSize: config.AutomaticStackSize(), AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.Target.DefaultStackSize, DefaultStackSize: config.StackSize(),
NeedsStackObjects: config.NeedsStackObjects(), NeedsStackObjects: config.NeedsStackObjects(),
Debug: true, Debug: true,
} }
@@ -370,7 +370,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Packages are compiled independently anyway. // Packages are compiled independently anyway.
for _, cgoHeader := range pkg.CGoHeaders { for _, cgoHeader := range pkg.CGoHeaders {
// Store the header text in a temporary file. // Store the header text in a temporary file.
f, err := ioutil.TempFile(dir, "cgosnippet-*.c") f, err := os.CreateTemp(dir, "cgosnippet-*.c")
if err != nil { if err != nil {
return err return err
} }
@@ -431,7 +431,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
if pkgInit.IsNil() { if pkgInit.IsNil() {
panic("init not found for " + pkg.Pkg.Path()) panic("init not found for " + pkg.Pkg.Path())
} }
err := interp.RunFunc(pkgInit, config.DumpSSA()) err := interp.RunFunc(pkgInit, config.Options.InterpTimeout, config.DumpSSA())
if err != nil { if err != nil {
return err return err
} }
@@ -445,7 +445,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Write to a temporary path that is renamed to the destination // Write to a temporary path that is renamed to the destination
// file to avoid race conditions with other TinyGo invocatiosn // file to avoid race conditions with other TinyGo invocatiosn
// that might also be compiling this package at the same time. // that might also be compiling this package at the same time.
f, err := ioutil.TempFile(filepath.Dir(job.result), filepath.Base(job.result)) f, err := os.CreateTemp(filepath.Dir(job.result), filepath.Base(job.result))
if err != nil { if err != nil {
return err return err
} }
@@ -589,7 +589,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
return err return err
} }
defer llvmBuf.Dispose() defer llvmBuf.Dispose()
return ioutil.WriteFile(outpath, llvmBuf.Bytes(), 0666) return os.WriteFile(outpath, llvmBuf.Bytes(), 0666)
case ".bc": case ".bc":
var buf llvm.MemoryBuffer var buf llvm.MemoryBuffer
if config.UseThinLTO() { if config.UseThinLTO() {
@@ -598,10 +598,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
buf = llvm.WriteBitcodeToMemoryBuffer(mod) buf = llvm.WriteBitcodeToMemoryBuffer(mod)
} }
defer buf.Dispose() defer buf.Dispose()
return ioutil.WriteFile(outpath, buf.Bytes(), 0666) return os.WriteFile(outpath, buf.Bytes(), 0666)
case ".ll": case ".ll":
data := []byte(mod.String()) data := []byte(mod.String())
return ioutil.WriteFile(outpath, data, 0666) return os.WriteFile(outpath, data, 0666)
default: default:
panic("unreachable") panic("unreachable")
} }
@@ -629,7 +629,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
} }
} }
defer llvmBuf.Dispose() defer llvmBuf.Dispose()
return ioutil.WriteFile(objfile, llvmBuf.Bytes(), 0666) return os.WriteFile(objfile, llvmBuf.Bytes(), 0666)
}, },
} }
@@ -1055,7 +1055,7 @@ func createEmbedObjectFile(data, hexSum, sourceFile, sourceDir, tmpdir string, c
// needed to convert a program to its final form. Some transformations are not // needed to convert a program to its final form. Some transformations are not
// optional and must be run as the compiler expects them to run. // optional and must be run as the compiler expects them to run.
func optimizeProgram(mod llvm.Module, config *compileopts.Config) error { func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
err := interp.Run(mod, config.DumpSSA()) err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA())
if err != nil { if err != nil {
return err return err
} }
@@ -1367,10 +1367,10 @@ func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map
// //
// It might print something like the following: // It might print something like the following:
// //
// function stack usage (in bytes) // function stack usage (in bytes)
// Reset_Handler 316 // Reset_Handler 316
// examples/blinky2.led1 92 // examples/blinky2.led1 92
// runtime.run$1 300 // runtime.run$1 300
func printStacks(calculatedStacks []string, stackSizes map[string]functionStackSize) { func printStacks(calculatedStacks []string, stackSizes map[string]functionStackSize) {
// Print the sizes of all stacks. // Print the sizes of all stacks.
fmt.Printf("%-32s %s\n", "function", "stack usage (in bytes)") fmt.Printf("%-32s %s\n", "function", "stack usage (in bytes)")
+1 -2
View File
@@ -2,7 +2,6 @@ package builder
import ( import (
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
@@ -90,7 +89,7 @@ func testClangAttributes(t *testing.T, options *compileopts.Options) {
// Create a very simple C input file. // Create a very simple C input file.
srcpath := filepath.Join(testDir, "test.c") srcpath := filepath.Join(testDir, "test.c")
err = ioutil.WriteFile(srcpath, []byte("int add(int a, int b) { return a + b; }"), 0o666) err = os.WriteFile(srcpath, []byte("int add(int a, int b) { return a + b; }"), 0o666)
if err != nil { if err != nil {
t.Fatalf("could not write target file %s: %s", srcpath, err) t.Fatalf("could not write target file %s: %s", srcpath, err)
} }
+1 -1
View File
@@ -24,7 +24,7 @@ func ReadBuildID() ([]byte, error) {
defer f.Close() defer f.Close()
switch runtime.GOOS { switch runtime.GOOS {
case "linux", "freebsd": case "linux", "freebsd", "android":
// Read the GNU build id section. (Not sure about FreeBSD though...) // Read the GNU build id section. (Not sure about FreeBSD though...)
file, err := elf.NewFile(f) file, err := elf.NewFile(f)
if err != nil { if err != nil {
+37 -36
View File
@@ -10,7 +10,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/fs"
"os" "os"
"path/filepath" "path/filepath"
"sort" "sort"
@@ -33,29 +33,29 @@ import (
// Because of this complexity, every file has in fact two cached build outputs: // 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: // the file itself, and the list of dependencies. Its operation is as follows:
// //
// depfile = hash(path, compiler, cflags, ...) // depfile = hash(path, compiler, cflags, ...)
// if depfile exists: // if depfile exists:
// outfile = hash of all files and depfile name // outfile = hash of all files and depfile name
// if outfile exists: // if outfile exists:
// # cache hit // # cache hit
// return outfile // return outfile
// # cache miss // # cache miss
// tmpfile = compile file // tmpfile = compile file
// read dependencies (side effect of compile) // read dependencies (side effect of compile)
// write depfile // write depfile
// outfile = hash of all files and depfile name // outfile = hash of all files and depfile name
// rename tmpfile to outfile // rename tmpfile to outfile
// //
// There are a few edge cases that are not handled: // 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 // - 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 // 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. // dependencies file, but I'm not aware of a compiler which does that.
// - The Makefile syntax that compilers output has issues, see readDepFile for // - The Makefile syntax that compilers output has issues, see readDepFile for
// details. // details.
// - A header file may be changed to add/remove an include. This invalidates the // - 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 // depfile but without invalidating its name. For this reason, the depfile is
// written on each new compilation (even when it seems unnecessary). However, it // 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. // could in rare cases lead to a stale file fetched from the cache.
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool, printCommands func(string, ...string)) (string, error) { func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool, printCommands func(string, ...string)) (string, error) {
// Hash input file. // Hash input file.
fileHash, err := hashFile(abspath) fileHash, err := hashFile(abspath)
@@ -93,7 +93,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
// Load dependencies file, if possible. // Load dependencies file, if possible.
depfileName := "dep-" + depfileNameHash + ".json" depfileName := "dep-" + depfileNameHash + ".json"
depfileCachePath := filepath.Join(goenv.Get("GOCACHE"), depfileName) 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 var dependencies []string // sorted list of dependency paths
if err == nil { if err == nil {
// There is a dependency file, that's great! // There is a dependency file, that's great!
@@ -108,21 +108,21 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
if err == nil { if err == nil {
if _, err := os.Stat(outpath); err == nil { if _, err := os.Stat(outpath); err == nil {
return outpath, nil return outpath, nil
} else if !os.IsNotExist(err) { } else if !errors.Is(err, fs.ErrNotExist) {
return "", err return "", err
} }
} }
} else if !os.IsNotExist(err) { } else if !errors.Is(err, fs.ErrNotExist) {
// expected either nil or IsNotExist // expected either nil or IsNotExist
return "", err return "", err
} }
objTmpFile, err := ioutil.TempFile(goenv.Get("GOCACHE"), "tmp-*"+ext) objTmpFile, err := os.CreateTemp(goenv.Get("GOCACHE"), "tmp-*"+ext)
if err != nil { if err != nil {
return "", err return "", err
} }
objTmpFile.Close() objTmpFile.Close()
depTmpFile, err := ioutil.TempFile(tmpdir, "dep-*.d") depTmpFile, err := os.CreateTemp(tmpdir, "dep-*.d")
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -166,7 +166,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
sort.Strings(dependencySlice) sort.Strings(dependencySlice)
// Write dependencies file. // Write dependencies file.
f, err := ioutil.TempFile(filepath.Dir(depfileCachePath), depfileName) f, err := os.CreateTemp(filepath.Dir(depfileCachePath), depfileName)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -252,13 +252,14 @@ func hashFile(path string) (string, error) {
// file is assumed to have a single target named deps. // file is assumed to have a single target named deps.
// //
// There are roughly three make syntax variants: // There are roughly three make syntax variants:
// - BSD make, which doesn't support any escaping. This means that many special // - BSD make, which doesn't support any escaping. This means that many special
// characters are not supported in file names. // characters are not supported in file names.
// - GNU make, which supports escaping using a backslash but when it fails to // - 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 // find a file it tries to fall back with the literal path name (to match BSD
// make). // make).
// - NMake (Visual Studio) and Jom, which simply quote the string if there are // - NMake (Visual Studio) and Jom, which simply quote the string if there are
// any weird characters. // any weird characters.
//
// Clang supports two variants: a format that's a compromise between BSD and GNU // 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 // 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 // is at least somewhat sane. This last format isn't perfect either: it does not
@@ -266,7 +267,7 @@ func hashFile(path string) (string, error) {
// allowed on Windows, but of course can be used on POSIX like systems. Still, // 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. // it's the most sane of any of the formats so readDepFile will use that format.
func readDepFile(filename string) ([]string, error) { func readDepFile(filename string) ([]string, error) {
buf, err := ioutil.ReadFile(filename) buf, err := os.ReadFile(filename)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+2 -2
View File
@@ -33,8 +33,8 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err) return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
} }
if major != 1 || minor < 16 || minor > 19 { if major != 1 || minor < 18 || minor > 19 {
return nil, fmt.Errorf("requires go version 1.16 through 1.19, got go%d.%d", major, minor) return nil, fmt.Errorf("requires go version 1.18 through 1.19, got go%d.%d", major, minor)
} }
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT")) clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
+4 -2
View File
@@ -1,6 +1,8 @@
package builder package builder
import ( import (
"errors"
"io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
@@ -17,13 +19,13 @@ import (
func getClangHeaderPath(TINYGOROOT string) string { func getClangHeaderPath(TINYGOROOT string) string {
// Check whether we're running from the source directory. // Check whether we're running from the source directory.
path := filepath.Join(TINYGOROOT, "llvm-project", "clang", "lib", "Headers") path := filepath.Join(TINYGOROOT, "llvm-project", "clang", "lib", "Headers")
if _, err := os.Stat(path); !os.IsNotExist(err) { if _, err := os.Stat(path); !errors.Is(err, fs.ErrNotExist) {
return path return path
} }
// Check whether we're running from the installation directory. // Check whether we're running from the installation directory.
path = filepath.Join(TINYGOROOT, "lib", "clang", "include") path = filepath.Join(TINYGOROOT, "lib", "clang", "include")
if _, err := os.Stat(path); !os.IsNotExist(err) { if _, err := os.Stat(path); !errors.Is(err, fs.ErrNotExist) {
return path return path
} }
+2 -2
View File
@@ -13,7 +13,7 @@ import (
"debug/elf" "debug/elf"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io/ioutil" "os"
"sort" "sort"
"strings" "strings"
) )
@@ -189,5 +189,5 @@ func makeESPFirmareImage(infile, outfile, format string) error {
} }
// Write the image to the output file. // Write the image to the output file.
return ioutil.WriteFile(outfile, outf.Bytes(), 0666) return os.WriteFile(outfile, outf.Bytes(), 0666)
} }
+12 -7
View File
@@ -1,7 +1,8 @@
package builder package builder
import ( import (
"io/ioutil" "errors"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
@@ -94,7 +95,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
target := config.Triple() target := config.Triple()
if l.makeHeaders != nil { if l.makeHeaders != nil {
if _, err = os.Stat(headerPath); err != nil { if _, err = os.Stat(headerPath); err != nil {
temporaryHeaderPath, err := ioutil.TempDir(outdir, "include.tmp*") temporaryHeaderPath, err := os.MkdirTemp(outdir, "include.tmp*")
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -110,10 +111,10 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
err = os.Rename(temporaryHeaderPath, headerPath) err = os.Rename(temporaryHeaderPath, headerPath)
if err != nil { if err != nil {
switch { switch {
case os.IsExist(err): case errors.Is(err, fs.ErrExist):
// Another invocation of TinyGo also seems to have already created the headers. // Another invocation of TinyGo also seems to have already created the headers.
case runtime.GOOS == "windows" && os.IsPermission(err): case runtime.GOOS == "windows" && errors.Is(err, fs.ErrPermission):
// On Windows, a rename with a destination directory that already // On Windows, a rename with a destination directory that already
// exists does not result in an IsExist error, but rather in an // exists does not result in an IsExist error, but rather in an
// access denied error. To be sure, check for this case by checking // access denied error. To be sure, check for this case by checking
@@ -155,7 +156,11 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
} }
} }
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") { if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables") 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") { if strings.HasPrefix(target, "avr") {
// AVR defaults to C float and double both being 32-bit. This deviates // AVR defaults to C float and double both being 32-bit. This deviates
@@ -189,7 +194,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
defer once.Do(unlock) defer once.Do(unlock)
// Create an archive of all object files. // Create an archive of all object files.
f, err := ioutil.TempFile(outdir, "libc.a.tmp*") f, err := os.CreateTemp(outdir, "libc.a.tmp*")
if err != nil { if err != nil {
return err return err
} }
@@ -250,7 +255,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
run: func(*compileJob) error { run: func(*compileJob) error {
var compileArgs []string var compileArgs []string
compileArgs = append(compileArgs, args...) compileArgs = append(compileArgs, args...)
tmpfile, err := ioutil.TempFile(outdir, "crt1.o.tmp*") tmpfile, err := os.CreateTemp(outdir, "crt1.o.tmp*")
if err != nil { if err != nil {
return err return err
} }
+1 -1
View File
@@ -78,7 +78,7 @@ func makeMinGWExtraLibs(tmpdir string) []*compileJob {
// .in files need to be preprocessed by a preprocessor (-E) // .in files need to be preprocessed by a preprocessor (-E)
// first. // first.
defpath = outpath + ".def" defpath = outpath + ".def"
err := runCCompiler("-E", "-x", "c", "-Wp,-w", "-P", "-DDEF_X64", "-o", defpath, inpath, "-I"+goenv.Get("TINYGOROOT")+"/lib/mingw-w64/mingw-w64-crt/def-include/") err := runCCompiler("-E", "-x", "c", "-Wp,-w", "-P", "-DDEF_X64", "-DDATA", "-o", defpath, inpath, "-I"+goenv.Get("TINYGOROOT")+"/lib/mingw-w64/mingw-w64-crt/def-include/")
if err != nil { if err != nil {
return err return err
} }
+4 -3
View File
@@ -3,7 +3,6 @@ package builder
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
@@ -35,7 +34,7 @@ var Musl = Library{
filepath.Join(muslDir, "include", "alltypes.h.in"), filepath.Join(muslDir, "include", "alltypes.h.in"),
} }
for _, infile := range infiles { for _, infile := range infiles {
data, err := ioutil.ReadFile(infile) data, err := os.ReadFile(infile)
if err != nil { if err != nil {
return err return err
} }
@@ -63,7 +62,7 @@ var Musl = Library{
if err != nil { if err != nil {
return err return err
} }
data, err := ioutil.ReadFile(filepath.Join(muslDir, "arch", arch, "bits", "syscall.h.in")) data, err := os.ReadFile(filepath.Join(muslDir, "arch", arch, "bits", "syscall.h.in"))
if err != nil { if err != nil {
return err return err
} }
@@ -90,6 +89,7 @@ var Musl = Library{
"-Wno-shift-op-parentheses", "-Wno-shift-op-parentheses",
"-Wno-ignored-attributes", "-Wno-ignored-attributes",
"-Wno-string-plus-int", "-Wno-string-plus-int",
"-Wno-ignored-pragmas",
"-Qunused-arguments", "-Qunused-arguments",
// Select include dirs. Don't include standard library includes // Select include dirs. Don't include standard library includes
// (that would introduce host dependencies and other complications), // (that would introduce host dependencies and other complications),
@@ -118,6 +118,7 @@ var Musl = Library{
"legacy/*.c", "legacy/*.c",
"malloc/*.c", "malloc/*.c",
"mman/*.c", "mman/*.c",
"math/*.c",
"signal/*.c", "signal/*.c",
"stdio/*.c", "stdio/*.c",
"string/*.c", "string/*.c",
+2 -2
View File
@@ -2,7 +2,7 @@ package builder
import ( import (
"fmt" "fmt"
"io/ioutil" "io"
"os/exec" "os/exec"
"github.com/tinygo-org/tinygo/compileopts" "github.com/tinygo-org/tinygo/compileopts"
@@ -18,7 +18,7 @@ func makeDFUFirmwareImage(options *compileopts.Options, infile, outfile string)
} }
cmd := exec.Command(cmdLine[0], cmdLine[1:]...) cmd := exec.Command(cmdLine[0], cmdLine[1:]...)
cmd.Stdout = ioutil.Discard cmd.Stdout = io.Discard
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
return fmt.Errorf("could not run nrfutil pkg generate: %w", err) return fmt.Errorf("could not run nrfutil pkg generate: %w", err)
+2 -2
View File
@@ -2,7 +2,7 @@ package builder
import ( import (
"debug/elf" "debug/elf"
"io/ioutil" "io"
"os" "os"
"sort" "sort"
@@ -87,7 +87,7 @@ func extractROM(path string) (uint64, []byte, error) {
// Pad the difference // Pad the difference
rom = append(rom, make([]byte, diff)...) rom = append(rom, make([]byte, diff)...)
} }
data, err := ioutil.ReadAll(prog.Open()) data, err := io.ReadAll(prog.Open())
if err != nil { if err != nil {
return 0, nil, objcopyError{"failed to extract segment from ELF file: " + path, err} return 0, nil, objcopyError{"failed to extract segment from ELF file: " + path, err}
} }
+380 -204
View File
@@ -19,7 +19,7 @@ var Picolibc = Library{
return f.Close() return f.Close()
}, },
cflags: func(target, headerPath string) []string { cflags: func(target, headerPath string) []string {
picolibcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib/libc") newlibDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib")
return []string{ return []string{
"-Werror", "-Werror",
"-Wall", "-Wall",
@@ -27,219 +27,395 @@ var Picolibc = Library{
"-D_COMPILING_NEWLIB", "-D_COMPILING_NEWLIB",
"-DHAVE_ALIAS_ATTRIBUTE", "-DHAVE_ALIAS_ATTRIBUTE",
"-DTINY_STDIO", "-DTINY_STDIO",
"-D_IEEE_LIBM",
"-D__OBSOLETE_MATH_FLOAT=1", // use old math code that doesn't expect a FPU
"-D__OBSOLETE_MATH_DOUBLE=0",
"-nostdlibinc", "-nostdlibinc",
"-isystem", picolibcDir + "/include", "-isystem", newlibDir + "/libc/include",
"-I" + picolibcDir + "/tinystdio", "-I" + newlibDir + "/libc/tinystdio",
"-I" + newlibDir + "/libm/common",
"-I" + headerPath, "-I" + headerPath,
} }
}, },
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib/libc") }, sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib") },
librarySources: func(target string) []string { librarySources: func(target string) []string {
return picolibcSources return picolibcSources
}, },
} }
var picolibcSources = []string{ var picolibcSources = []string{
"../../../picolibc-stdio.c", "../../picolibc-stdio.c",
"tinystdio/asprintf.c", "libc/tinystdio/asprintf.c",
"tinystdio/atod_engine.c", "libc/tinystdio/atod_engine.c",
"tinystdio/atod_ryu.c", "libc/tinystdio/atod_ryu.c",
"tinystdio/atof_engine.c", "libc/tinystdio/atof_engine.c",
"tinystdio/atof_ryu.c", "libc/tinystdio/atof_ryu.c",
//"tinystdio/atold_engine.c", // have_long_double and not long_double_equals_double //"libc/tinystdio/atold_engine.c", // have_long_double and not long_double_equals_double
"tinystdio/clearerr.c", "libc/tinystdio/clearerr.c",
"tinystdio/compare_exchange.c", "libc/tinystdio/compare_exchange.c",
"tinystdio/dtoa_data.c", "libc/tinystdio/dtoa_data.c",
"tinystdio/dtoa_engine.c", "libc/tinystdio/dtoa_engine.c",
"tinystdio/dtoa_ryu.c", "libc/tinystdio/dtoa_ryu.c",
"tinystdio/ecvtbuf.c", "libc/tinystdio/ecvtbuf.c",
"tinystdio/ecvt.c", "libc/tinystdio/ecvt.c",
"tinystdio/ecvt_data.c", "libc/tinystdio/ecvt_data.c",
"tinystdio/ecvtfbuf.c", "libc/tinystdio/ecvtfbuf.c",
"tinystdio/ecvtf.c", "libc/tinystdio/ecvtf.c",
"tinystdio/ecvtf_data.c", "libc/tinystdio/ecvtf_data.c",
"tinystdio/exchange.c", "libc/tinystdio/exchange.c",
//"tinystdio/fclose.c", // posix-io //"libc/tinystdio/fclose.c", // posix-io
"tinystdio/fcvtbuf.c", "libc/tinystdio/fcvtbuf.c",
"tinystdio/fcvt.c", "libc/tinystdio/fcvt.c",
"tinystdio/fcvtfbuf.c", "libc/tinystdio/fcvtfbuf.c",
"tinystdio/fcvtf.c", "libc/tinystdio/fcvtf.c",
"tinystdio/fdevopen.c", "libc/tinystdio/fdevopen.c",
//"tinystdio/fdopen.c", // posix-io //"libc/tinystdio/fdopen.c", // posix-io
"tinystdio/feof.c", "libc/tinystdio/feof.c",
"tinystdio/ferror.c", "libc/tinystdio/ferror.c",
"tinystdio/fflush.c", "libc/tinystdio/fflush.c",
"tinystdio/fgetc.c", "libc/tinystdio/fgetc.c",
"tinystdio/fgets.c", "libc/tinystdio/fgets.c",
"tinystdio/fileno.c", "libc/tinystdio/fileno.c",
"tinystdio/filestrget.c", "libc/tinystdio/filestrget.c",
"tinystdio/filestrputalloc.c", "libc/tinystdio/filestrputalloc.c",
"tinystdio/filestrput.c", "libc/tinystdio/filestrput.c",
//"tinystdio/fopen.c", // posix-io //"libc/tinystdio/fopen.c", // posix-io
"tinystdio/fprintf.c", "libc/tinystdio/fprintf.c",
"tinystdio/fputc.c", "libc/tinystdio/fputc.c",
"tinystdio/fputs.c", "libc/tinystdio/fputs.c",
"tinystdio/fread.c", "libc/tinystdio/fread.c",
"tinystdio/fscanf.c", "libc/tinystdio/fscanf.c",
"tinystdio/fseek.c", "libc/tinystdio/fseek.c",
"tinystdio/ftell.c", "libc/tinystdio/ftell.c",
"tinystdio/ftoa_data.c", "libc/tinystdio/ftoa_data.c",
"tinystdio/ftoa_engine.c", "libc/tinystdio/ftoa_engine.c",
"tinystdio/ftoa_ryu.c", "libc/tinystdio/ftoa_ryu.c",
"tinystdio/fwrite.c", "libc/tinystdio/fwrite.c",
"tinystdio/gcvtbuf.c", "libc/tinystdio/gcvtbuf.c",
"tinystdio/gcvt.c", "libc/tinystdio/gcvt.c",
"tinystdio/gcvtfbuf.c", "libc/tinystdio/gcvtfbuf.c",
"tinystdio/gcvtf.c", "libc/tinystdio/gcvtf.c",
"tinystdio/getchar.c", "libc/tinystdio/getchar.c",
"tinystdio/gets.c", "libc/tinystdio/gets.c",
"tinystdio/matchcaseprefix.c", "libc/tinystdio/matchcaseprefix.c",
"tinystdio/perror.c", "libc/tinystdio/perror.c",
//"tinystdio/posixiob.c", // posix-io //"libc/tinystdio/posixiob.c", // posix-io
//"tinystdio/posixio.c", // posix-io //"libc/tinystdio/posixio.c", // posix-io
"tinystdio/printf.c", "libc/tinystdio/printf.c",
"tinystdio/putchar.c", "libc/tinystdio/putchar.c",
"tinystdio/puts.c", "libc/tinystdio/puts.c",
"tinystdio/ryu_divpow2.c", "libc/tinystdio/ryu_divpow2.c",
"tinystdio/ryu_log10.c", "libc/tinystdio/ryu_log10.c",
"tinystdio/ryu_log2pow5.c", "libc/tinystdio/ryu_log2pow5.c",
"tinystdio/ryu_pow5bits.c", "libc/tinystdio/ryu_pow5bits.c",
"tinystdio/ryu_table.c", "libc/tinystdio/ryu_table.c",
"tinystdio/ryu_umul128.c", "libc/tinystdio/ryu_umul128.c",
"tinystdio/scanf.c", "libc/tinystdio/scanf.c",
"tinystdio/setbuf.c", "libc/tinystdio/setbuf.c",
"tinystdio/setvbuf.c", "libc/tinystdio/setvbuf.c",
//"tinystdio/sflags.c", // posix-io //"libc/tinystdio/sflags.c", // posix-io
"tinystdio/snprintf.c", "libc/tinystdio/snprintf.c",
"tinystdio/snprintfd.c", "libc/tinystdio/snprintfd.c",
"tinystdio/snprintff.c", "libc/tinystdio/snprintff.c",
"tinystdio/sprintf.c", "libc/tinystdio/sprintf.c",
"tinystdio/sprintfd.c", "libc/tinystdio/sprintfd.c",
"tinystdio/sprintff.c", "libc/tinystdio/sprintff.c",
"tinystdio/sscanf.c", "libc/tinystdio/sscanf.c",
"tinystdio/strfromd.c", "libc/tinystdio/strfromd.c",
"tinystdio/strfromf.c", "libc/tinystdio/strfromf.c",
"tinystdio/strtod.c", "libc/tinystdio/strtod.c",
"tinystdio/strtod_l.c", "libc/tinystdio/strtod_l.c",
"tinystdio/strtof.c", "libc/tinystdio/strtof.c",
//"tinystdio/strtold.c", // have_long_double and not long_double_equals_double //"libc/tinystdio/strtold.c", // have_long_double and not long_double_equals_double
//"tinystdio/strtold_l.c", // have_long_double and not long_double_equals_double //"libc/tinystdio/strtold_l.c", // have_long_double and not long_double_equals_double
"tinystdio/ungetc.c", "libc/tinystdio/ungetc.c",
"tinystdio/vasprintf.c", "libc/tinystdio/vasprintf.c",
"tinystdio/vfiprintf.c", "libc/tinystdio/vfiprintf.c",
"tinystdio/vfiscanf.c", "libc/tinystdio/vfiscanf.c",
"tinystdio/vfprintf.c", "libc/tinystdio/vfprintf.c",
"tinystdio/vfprintff.c", "libc/tinystdio/vfprintff.c",
"tinystdio/vfscanf.c", "libc/tinystdio/vfscanf.c",
"tinystdio/vfscanff.c", "libc/tinystdio/vfscanff.c",
"tinystdio/vprintf.c", "libc/tinystdio/vprintf.c",
"tinystdio/vscanf.c", "libc/tinystdio/vscanf.c",
"tinystdio/vsnprintf.c", "libc/tinystdio/vsnprintf.c",
"tinystdio/vsprintf.c", "libc/tinystdio/vsprintf.c",
"tinystdio/vsscanf.c", "libc/tinystdio/vsscanf.c",
"string/bcmp.c", "libc/string/bcmp.c",
"string/bcopy.c", "libc/string/bcopy.c",
"string/bzero.c", "libc/string/bzero.c",
"string/explicit_bzero.c", "libc/string/explicit_bzero.c",
"string/ffsl.c", "libc/string/ffsl.c",
"string/ffsll.c", "libc/string/ffsll.c",
"string/fls.c", "libc/string/fls.c",
"string/flsl.c", "libc/string/flsl.c",
"string/flsll.c", "libc/string/flsll.c",
"string/gnu_basename.c", "libc/string/gnu_basename.c",
"string/index.c", "libc/string/index.c",
"string/memccpy.c", "libc/string/memccpy.c",
"string/memchr.c", "libc/string/memchr.c",
"string/memcmp.c", "libc/string/memcmp.c",
"string/memcpy.c", "libc/string/memcpy.c",
"string/memmem.c", "libc/string/memmem.c",
"string/memmove.c", "libc/string/memmove.c",
"string/mempcpy.c", "libc/string/mempcpy.c",
"string/memrchr.c", "libc/string/memrchr.c",
"string/memset.c", "libc/string/memset.c",
"string/rawmemchr.c", "libc/string/rawmemchr.c",
"string/rindex.c", "libc/string/rindex.c",
"string/stpcpy.c", "libc/string/stpcpy.c",
"string/stpncpy.c", "libc/string/stpncpy.c",
"string/strcasecmp.c", "libc/string/strcasecmp.c",
"string/strcasecmp_l.c", "libc/string/strcasecmp_l.c",
"string/strcasestr.c", "libc/string/strcasestr.c",
"string/strcat.c", "libc/string/strcat.c",
"string/strchr.c", "libc/string/strchr.c",
"string/strchrnul.c", "libc/string/strchrnul.c",
"string/strcmp.c", "libc/string/strcmp.c",
"string/strcoll.c", "libc/string/strcoll.c",
"string/strcoll_l.c", "libc/string/strcoll_l.c",
"string/strcpy.c", "libc/string/strcpy.c",
"string/strcspn.c", "libc/string/strcspn.c",
"string/strdup.c", "libc/string/strdup.c",
"string/strerror.c", "libc/string/strerror.c",
"string/strerror_r.c", "libc/string/strerror_r.c",
"string/strlcat.c", "libc/string/strlcat.c",
"string/strlcpy.c", "libc/string/strlcpy.c",
"string/strlen.c", "libc/string/strlen.c",
"string/strlwr.c", "libc/string/strlwr.c",
"string/strncasecmp.c", "libc/string/strncasecmp.c",
"string/strncasecmp_l.c", "libc/string/strncasecmp_l.c",
"string/strncat.c", "libc/string/strncat.c",
"string/strncmp.c", "libc/string/strncmp.c",
"string/strncpy.c", "libc/string/strncpy.c",
"string/strndup.c", "libc/string/strndup.c",
"string/strnlen.c", "libc/string/strnlen.c",
"string/strnstr.c", "libc/string/strnstr.c",
"string/strpbrk.c", "libc/string/strpbrk.c",
"string/strrchr.c", "libc/string/strrchr.c",
"string/strsep.c", "libc/string/strsep.c",
"string/strsignal.c", "libc/string/strsignal.c",
"string/strspn.c", "libc/string/strspn.c",
"string/strstr.c", "libc/string/strstr.c",
"string/strtok.c", "libc/string/strtok.c",
"string/strtok_r.c", "libc/string/strtok_r.c",
"string/strupr.c", "libc/string/strupr.c",
"string/strverscmp.c", "libc/string/strverscmp.c",
"string/strxfrm.c", "libc/string/strxfrm.c",
"string/strxfrm_l.c", "libc/string/strxfrm_l.c",
"string/swab.c", "libc/string/swab.c",
"string/timingsafe_bcmp.c", "libc/string/timingsafe_bcmp.c",
"string/timingsafe_memcmp.c", "libc/string/timingsafe_memcmp.c",
"string/u_strerr.c", "libc/string/u_strerr.c",
"string/wcpcpy.c", "libc/string/wcpcpy.c",
"string/wcpncpy.c", "libc/string/wcpncpy.c",
"string/wcscasecmp.c", "libc/string/wcscasecmp.c",
"string/wcscasecmp_l.c", "libc/string/wcscasecmp_l.c",
"string/wcscat.c", "libc/string/wcscat.c",
"string/wcschr.c", "libc/string/wcschr.c",
"string/wcscmp.c", "libc/string/wcscmp.c",
"string/wcscoll.c", "libc/string/wcscoll.c",
"string/wcscoll_l.c", "libc/string/wcscoll_l.c",
"string/wcscpy.c", "libc/string/wcscpy.c",
"string/wcscspn.c", "libc/string/wcscspn.c",
"string/wcsdup.c", "libc/string/wcsdup.c",
"string/wcslcat.c", "libc/string/wcslcat.c",
"string/wcslcpy.c", "libc/string/wcslcpy.c",
"string/wcslen.c", "libc/string/wcslen.c",
"string/wcsncasecmp.c", "libc/string/wcsncasecmp.c",
"string/wcsncasecmp_l.c", "libc/string/wcsncasecmp_l.c",
"string/wcsncat.c", "libc/string/wcsncat.c",
"string/wcsncmp.c", "libc/string/wcsncmp.c",
"string/wcsncpy.c", "libc/string/wcsncpy.c",
"string/wcsnlen.c", "libc/string/wcsnlen.c",
"string/wcspbrk.c", "libc/string/wcspbrk.c",
"string/wcsrchr.c", "libc/string/wcsrchr.c",
"string/wcsspn.c", "libc/string/wcsspn.c",
"string/wcsstr.c", "libc/string/wcsstr.c",
"string/wcstok.c", "libc/string/wcstok.c",
"string/wcswidth.c", "libc/string/wcswidth.c",
"string/wcsxfrm.c", "libc/string/wcsxfrm.c",
"string/wcsxfrm_l.c", "libc/string/wcsxfrm_l.c",
"string/wcwidth.c", "libc/string/wcwidth.c",
"string/wmemchr.c", "libc/string/wmemchr.c",
"string/wmemcmp.c", "libc/string/wmemcmp.c",
"string/wmemcpy.c", "libc/string/wmemcpy.c",
"string/wmemmove.c", "libc/string/wmemmove.c",
"string/wmempcpy.c", "libc/string/wmempcpy.c",
"string/wmemset.c", "libc/string/wmemset.c",
"string/xpg_strerror_r.c", "libc/string/xpg_strerror_r.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_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_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_xflow.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/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/e_acos.c",
"libm/math/e_acosh.c",
"libm/math/e_asin.c",
"libm/math/e_atan2.c",
"libm/math/e_atanh.c",
"libm/math/e_cosh.c",
"libm/math/e_exp.c",
"libm/math/ef_acos.c",
"libm/math/ef_acosh.c",
"libm/math/ef_asin.c",
"libm/math/ef_atan2.c",
"libm/math/ef_atanh.c",
"libm/math/ef_cosh.c",
"libm/math/ef_exp.c",
"libm/math/ef_fmod.c",
"libm/math/ef_hypot.c",
"libm/math/ef_j0.c",
"libm/math/ef_j1.c",
"libm/math/ef_jn.c",
"libm/math/ef_lgamma.c",
"libm/math/ef_log10.c",
"libm/math/ef_log.c",
"libm/math/e_fmod.c",
"libm/math/ef_pow.c",
"libm/math/ef_remainder.c",
"libm/math/ef_rem_pio2.c",
"libm/math/ef_scalb.c",
"libm/math/ef_sinh.c",
"libm/math/ef_sqrt.c",
"libm/math/ef_tgamma.c",
"libm/math/e_hypot.c",
"libm/math/e_j0.c",
"libm/math/e_j1.c",
"libm/math/e_jn.c",
"libm/math/e_lgamma.c",
"libm/math/e_log10.c",
"libm/math/e_log.c",
"libm/math/e_pow.c",
"libm/math/e_remainder.c",
"libm/math/e_rem_pio2.c",
"libm/math/erf_lgamma.c",
"libm/math/er_lgamma.c",
"libm/math/e_scalb.c",
"libm/math/e_sinh.c",
"libm/math/e_sqrt.c",
"libm/math/e_tgamma.c",
"libm/math/s_asinh.c",
"libm/math/s_atan.c",
"libm/math/s_ceil.c",
"libm/math/s_cos.c",
"libm/math/s_erf.c",
"libm/math/s_fabs.c",
"libm/math/sf_asinh.c",
"libm/math/sf_atan.c",
"libm/math/sf_ceil.c",
"libm/math/sf_cos.c",
"libm/math/sf_erf.c",
"libm/math/sf_fabs.c",
"libm/math/sf_floor.c",
"libm/math/sf_frexp.c",
"libm/math/sf_ldexp.c",
"libm/math/s_floor.c",
"libm/math/s_frexp.c",
"libm/math/sf_signif.c",
"libm/math/sf_sin.c",
"libm/math/sf_tan.c",
"libm/math/sf_tanh.c",
"libm/math/s_ldexp.c",
"libm/math/s_signif.c",
"libm/math/s_sin.c",
"libm/math/s_tan.c",
"libm/math/s_tanh.c",
} }
+2 -2
View File
@@ -10,7 +10,7 @@ package builder
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"io/ioutil" "os"
"strconv" "strconv"
) )
@@ -26,7 +26,7 @@ func convertELFFileToUF2File(infile, outfile string, uf2FamilyID string) error {
if err != nil { if err != nil {
return err 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. // convertBinToUF2 converts the binary bytes in input to UF2 formatted data.
+72 -31
View File
@@ -32,6 +32,7 @@ type cgoPackage struct {
errors []error errors []error
currentDir string // current working directory currentDir string // current working directory
packageDir string // full path to the package to process packageDir string // full path to the package to process
importPath string
fset *token.FileSet fset *token.FileSet
tokenFiles map[string]*token.File tokenFiles map[string]*token.File
definedGlobally map[string]ast.Node definedGlobally map[string]ast.Node
@@ -39,12 +40,15 @@ type cgoPackage struct {
cflags []string // CFlags from #cgo lines cflags []string // CFlags from #cgo lines
ldflags []string // LDFlags from #cgo lines ldflags []string // LDFlags from #cgo lines
visitedFiles map[string][]byte visitedFiles map[string][]byte
cgoHeaders []string
} }
// cgoFile holds information only for a single Go file (with one or more // cgoFile holds information only for a single Go file (with one or more
// `import "C"` statements). // `import "C"` statements).
type cgoFile struct { type cgoFile struct {
*cgoPackage *cgoPackage
file *ast.File
index int
defined map[string]ast.Node defined map[string]ast.Node
names map[string]clangCursor names map[string]clangCursor
} }
@@ -158,9 +162,10 @@ func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
// functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file // functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
// hashes of the accessed C header files. If there is one or more error, it // hashes of the accessed C header files. If there is one or more error, it
// returns these in the []error slice but still modifies the AST. // returns these in the []error slice but still modifies the AST.
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string, clangHeaders string) (*ast.File, []string, []string, []string, map[string][]byte, []error) { func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cflags []string, clangHeaders string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
p := &cgoPackage{ p := &cgoPackage{
currentDir: dir, currentDir: dir,
importPath: importPath,
fset: fset, fset: fset,
tokenFiles: map[string]*token.File{}, tokenFiles: map[string]*token.File{},
definedGlobally: map[string]ast.Node{}, definedGlobally: map[string]ast.Node{},
@@ -210,13 +215,13 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
} }
} }
// Patch some types, for example *C.char in C.CString. // Patch some types, for example *C.char in C.CString.
cf := p.newCGoFile() cf := p.newCGoFile(nil, -1) // dummy *cgoFile for the walker
astutil.Apply(p.generated, func(cursor *astutil.Cursor) bool { astutil.Apply(p.generated, func(cursor *astutil.Cursor) bool {
return cf.walker(cursor, nil) return cf.walker(cursor, nil)
}, nil) }, nil)
// Find `import "C"` C fragments in the file. // Find `import "C"` C fragments in the file.
cgoHeaders := make([]string, len(files)) // combined CGo header fragment for each file p.cgoHeaders = make([]string, len(files)) // combined CGo header fragment for each file
for i, f := range files { for i, f := range files {
var cgoHeader string var cgoHeader string
for i := 0; i < len(f.Decls); i++ { for i := 0; i < len(f.Decls); i++ {
@@ -275,7 +280,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
cgoHeader += fragment cgoHeader += fragment
} }
cgoHeaders[i] = cgoHeader p.cgoHeaders[i] = cgoHeader
} }
// Define CFlags that will be used while parsing the package. // Define CFlags that will be used while parsing the package.
@@ -289,7 +294,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
} }
// Retrieve types such as C.int, C.longlong, etc from C. // Retrieve types such as C.int, C.longlong, etc from C.
p.newCGoFile().readNames(builtinAliasTypedefs, cflagsForCGo, "", func(names map[string]clangCursor) { p.newCGoFile(nil, -1).readNames(builtinAliasTypedefs, cflagsForCGo, "", func(names map[string]clangCursor) {
gen := &ast.GenDecl{ gen := &ast.GenDecl{
TokPos: token.NoPos, TokPos: token.NoPos,
Tok: token.TYPE, Tok: token.TYPE,
@@ -303,8 +308,8 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
// Process CGo imports for each file. // Process CGo imports for each file.
for i, f := range files { for i, f := range files {
cf := p.newCGoFile() cf := p.newCGoFile(f, i)
cf.readNames(cgoHeaders[i], cflagsForCGo, filepath.Base(fset.File(f.Pos()).Name()), func(names map[string]clangCursor) { cf.readNames(p.cgoHeaders[i], cflagsForCGo, filepath.Base(fset.File(f.Pos()).Name()), func(names map[string]clangCursor) {
for _, name := range builtinAliases { for _, name := range builtinAliases {
// Names such as C.int should not be obtained from C. // Names such as C.int should not be obtained from C.
// This works around an issue in picolibc that has `#define int` // This works around an issue in picolibc that has `#define int`
@@ -320,12 +325,14 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
// Print the newly generated in-memory AST, for debugging. // Print the newly generated in-memory AST, for debugging.
//ast.Print(fset, p.generated) //ast.Print(fset, p.generated)
return p.generated, cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors return p.generated, p.cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
} }
func (p *cgoPackage) newCGoFile() *cgoFile { func (p *cgoPackage) newCGoFile(file *ast.File, index int) *cgoFile {
return &cgoFile{ return &cgoFile{
cgoPackage: p, cgoPackage: p,
file: file,
index: index,
defined: make(map[string]ast.Node), defined: make(map[string]ast.Node),
names: make(map[string]clangCursor), names: make(map[string]clangCursor),
} }
@@ -493,15 +500,15 @@ func (p *cgoPackage) makeUnionField(typ *elaboratedTypeInfo) *ast.StructType {
// createUnionAccessor creates a function that returns a typed pointer to a // createUnionAccessor creates a function that returns a typed pointer to a
// union field for each field in a union. For example: // union field for each field in a union. For example:
// //
// func (union *C.union_1) unionfield_d() *float64 { // func (union *C.union_1) unionfield_d() *float64 {
// return (*float64)(unsafe.Pointer(&union.$union)) // return (*float64)(unsafe.Pointer(&union.$union))
// } // }
// //
// Where C.union_1 is defined as: // Where C.union_1 is defined as:
// //
// type C.union_1 struct{ // type C.union_1 struct{
// $union uint64 // $union uint64
// } // }
// //
// The returned pointer can be used to get or set the field, or get the pointer // The returned pointer can be used to get or set the field, or get the pointer
// to a subfield. // to a subfield.
@@ -617,9 +624,9 @@ func (p *cgoPackage) createUnionAccessor(field *ast.Field, typeName string) {
// createBitfieldGetter creates a bitfield getter function like the following: // createBitfieldGetter creates a bitfield getter function like the following:
// //
// func (s *C.struct_foo) bitfield_b() byte { // func (s *C.struct_foo) bitfield_b() byte {
// return (s.__bitfield_1 >> 5) & 0x1 // return (s.__bitfield_1 >> 5) & 0x1
// } // }
func (p *cgoPackage) createBitfieldGetter(bitfield bitfieldInfo, typeName string) { func (p *cgoPackage) createBitfieldGetter(bitfield bitfieldInfo, typeName string) {
// The value to return from the getter. // The value to return from the getter.
// Not complete: this is just an expression to get the complete field. // Not complete: this is just an expression to get the complete field.
@@ -729,15 +736,15 @@ func (p *cgoPackage) createBitfieldGetter(bitfield bitfieldInfo, typeName string
// createBitfieldSetter creates a bitfield setter function like the following: // createBitfieldSetter creates a bitfield setter function like the following:
// //
// func (s *C.struct_foo) set_bitfield_b(value byte) { // func (s *C.struct_foo) set_bitfield_b(value byte) {
// s.__bitfield_1 = s.__bitfield_1 ^ 0x60 | ((value & 1) << 5) // s.__bitfield_1 = s.__bitfield_1 ^ 0x60 | ((value & 1) << 5)
// } // }
// //
// Or the following: // Or the following:
// //
// func (s *C.struct_foo) set_bitfield_c(value byte) { // func (s *C.struct_foo) set_bitfield_c(value byte) {
// s.__bitfield_1 = s.__bitfield_1 & 0x3f | (value << 6) // s.__bitfield_1 = s.__bitfield_1 & 0x3f | (value << 6)
// } // }
func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string) { func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string) {
// The full field with all bitfields. // The full field with all bitfields.
var field ast.Expr = &ast.SelectorExpr{ var field ast.Expr = &ast.SelectorExpr{
@@ -1117,8 +1124,11 @@ func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) st
return alias return alias
} }
node := f.getASTDeclNode(name, found, iscall) node := f.getASTDeclNode(name, found, iscall)
if _, ok := node.(*ast.FuncDecl); ok && !iscall { if node, ok := node.(*ast.FuncDecl); ok {
return "C." + name + "$funcaddr" if !iscall {
return node.Name.Name + "$funcaddr"
}
return node.Name.Name
} }
return "C." + name return "C." + name
} }
@@ -1142,7 +1152,7 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
// Original cgo reports an error like // Original cgo reports an error like
// cgo: inconsistent definitions for C.myint // cgo: inconsistent definitions for C.myint
// which is far less helpful. // which is far less helpful.
f.addError(getPos(node), "defined previously at "+f.fset.Position(getPos(newNode)).String()+" with a different type") f.addError(getPos(node), name+" defined previously at "+f.fset.Position(getPos(newNode)).String()+" with a different type")
} }
f.defined[name] = node f.defined[name] = node
return node return node
@@ -1150,11 +1160,39 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
// The declaration has no AST node. Create it now. // The declaration has no AST node. Create it now.
f.defined[name] = nil f.defined[name] = nil
node, elaboratedType := f.createASTNode(name, found) node, extra := f.createASTNode(name, found)
f.defined[name] = node f.defined[name] = node
f.definedGlobally[name] = node
switch node := node.(type) { switch node := node.(type) {
case *ast.FuncDecl: case *ast.FuncDecl:
if strings.HasPrefix(node.Doc.List[0].Text, "//export _Cgo_static_") {
// Static function. Only accessible in the current Go file.
globalName := strings.TrimPrefix(node.Doc.List[0].Text, "//export ")
// Make an alias. Normally this is done using the alias function
// attribute, but MacOS for some reason doesn't support this (even
// though the linker has support for aliases in the form of N_INDR).
// Therefore, create an actual function for MacOS.
var params []string
for _, param := range node.Type.Params.List {
params = append(params, param.Names[0].Name)
}
callInst := fmt.Sprintf("%s(%s);", name, strings.Join(params, ", "))
if node.Type.Results != nil {
callInst = "return " + callInst
}
aliasDeclaration := fmt.Sprintf(`
#ifdef __APPLE__
%s {
%s
}
#else
extern __typeof(%s) %s __attribute__((alias(%#v)));
#endif
`, extra.(string), callInst, name, globalName, name)
f.cgoHeaders[f.index] += "\n\n" + aliasDeclaration
} else {
// Regular (non-static) function.
f.definedGlobally[name] = node
}
f.generated.Decls = append(f.generated.Decls, node) f.generated.Decls = append(f.generated.Decls, node)
// Also add a declaration like the following: // Also add a declaration like the following:
// var C.foo$funcaddr unsafe.Pointer // var C.foo$funcaddr unsafe.Pointer
@@ -1162,7 +1200,7 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
Tok: token.VAR, Tok: token.VAR,
Specs: []ast.Spec{ Specs: []ast.Spec{
&ast.ValueSpec{ &ast.ValueSpec{
Names: []*ast.Ident{{Name: "C." + name + "$funcaddr"}}, Names: []*ast.Ident{{Name: node.Name.Name + "$funcaddr"}},
Type: &ast.SelectorExpr{ Type: &ast.SelectorExpr{
X: &ast.Ident{Name: "unsafe"}, X: &ast.Ident{Name: "unsafe"},
Sel: &ast.Ident{Name: "Pointer"}, Sel: &ast.Ident{Name: "Pointer"},
@@ -1171,8 +1209,10 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
}, },
}) })
case *ast.GenDecl: case *ast.GenDecl:
f.definedGlobally[name] = node
f.generated.Decls = append(f.generated.Decls, node) f.generated.Decls = append(f.generated.Decls, node)
case *ast.TypeSpec: case *ast.TypeSpec:
f.definedGlobally[name] = node
f.generated.Decls = append(f.generated.Decls, &ast.GenDecl{ f.generated.Decls = append(f.generated.Decls, &ast.GenDecl{
Tok: token.TYPE, Tok: token.TYPE,
Specs: []ast.Spec{node}, Specs: []ast.Spec{node},
@@ -1186,7 +1226,8 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
// If this is a struct or union it may need bitfields or union accessor // If this is a struct or union it may need bitfields or union accessor
// methods. // methods.
if elaboratedType != nil { switch elaboratedType := extra.(type) {
case *elaboratedTypeInfo:
// Add struct bitfields. // Add struct bitfields.
for _, bitfield := range elaboratedType.bitfields { for _, bitfield := range elaboratedType.bitfields {
f.createBitfieldGetter(bitfield, "C."+name) f.createBitfieldGetter(bitfield, "C."+name)
+4 -19
View File
@@ -5,12 +5,11 @@ import (
"flag" "flag"
"fmt" "fmt"
"go/ast" "go/ast"
"go/build"
"go/format" "go/format"
"go/parser" "go/parser"
"go/token" "go/token"
"go/types" "go/types"
"io/ioutil" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
@@ -40,20 +39,6 @@ func TestCGo(t *testing.T) {
} { } {
name := name // avoid a race condition name := name // avoid a race condition
t.Run(name, func(t *testing.T) { 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. // Read the AST in memory.
path := filepath.Join("testdata", name+".go") path := filepath.Join("testdata", name+".go")
fset := token.NewFileSet() fset := token.NewFileSet()
@@ -63,7 +48,7 @@ func TestCGo(t *testing.T) {
} }
// Process the AST with CGo. // Process the AST with CGo.
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags, "") cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", "main", fset, cflags, "")
// Check the AST for type errors. // Check the AST for type errors.
var typecheckErrors []error var typecheckErrors []error
@@ -107,7 +92,7 @@ func TestCGo(t *testing.T) {
// Read the file with the expected output, to compare against. // Read the file with the expected output, to compare against.
outfile := filepath.Join("testdata", name+".out.go") outfile := filepath.Join("testdata", name+".out.go")
expectedBytes, err := ioutil.ReadFile(outfile) expectedBytes, err := os.ReadFile(outfile)
if err != nil { if err != nil {
t.Fatalf("could not read expected output: %v", err) t.Fatalf("could not read expected output: %v", err)
} }
@@ -118,7 +103,7 @@ func TestCGo(t *testing.T) {
// It is not. Test failed. // It is not. Test failed.
if *flagUpdate { if *flagUpdate {
// Update the file with the expected data. // Update the file with the expected data.
err := ioutil.WriteFile(outfile, []byte(actual), 0666) err := os.WriteFile(outfile, []byte(actual), 0666)
if err != nil { if err != nil {
t.Error("could not write updated output file:", err) t.Error("could not write updated output file:", err)
} }
+33 -4
View File
@@ -4,7 +4,9 @@ package cgo
// modification. It does not touch the AST itself. // modification. It does not touch the AST itself.
import ( import (
"crypto/sha256"
"crypto/sha512" "crypto/sha512"
"encoding/hex"
"fmt" "fmt"
"go/ast" "go/ast"
"go/scanner" "go/scanner"
@@ -43,6 +45,8 @@ typedef struct {
GoCXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu); GoCXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu);
unsigned tinygo_clang_visitChildren(GoCXCursor parent, CXCursorVisitor visitor, CXClientData client_data); unsigned tinygo_clang_visitChildren(GoCXCursor parent, CXCursorVisitor visitor, CXClientData client_data);
CXString tinygo_clang_getCursorSpelling(GoCXCursor c); 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); enum CXCursorKind tinygo_clang_getCursorKind(GoCXCursor c);
CXType tinygo_clang_getCursorType(GoCXCursor c); CXType tinygo_clang_getCursorType(GoCXCursor c);
GoCXCursor tinygo_clang_getTypeDeclaration(CXType t); GoCXCursor tinygo_clang_getTypeDeclaration(CXType t);
@@ -50,6 +54,7 @@ CXType tinygo_clang_getTypedefDeclUnderlyingType(GoCXCursor c);
CXType tinygo_clang_getCursorResultType(GoCXCursor c); CXType tinygo_clang_getCursorResultType(GoCXCursor c);
int tinygo_clang_Cursor_getNumArguments(GoCXCursor c); int tinygo_clang_Cursor_getNumArguments(GoCXCursor c);
GoCXCursor tinygo_clang_Cursor_getArgument(GoCXCursor c, unsigned i); GoCXCursor tinygo_clang_Cursor_getArgument(GoCXCursor c, unsigned i);
enum CX_StorageClass tinygo_clang_Cursor_getStorageClass(GoCXCursor c);
CXSourceLocation tinygo_clang_getCursorLocation(GoCXCursor c); CXSourceLocation tinygo_clang_getCursorLocation(GoCXCursor c);
CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c); CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c);
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c); CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c);
@@ -189,7 +194,7 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
// Convert the AST node under the given Clang cursor to a Go AST node and return // Convert the AST node under the given Clang cursor to a Go AST node and return
// it. // it.
func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, *elaboratedTypeInfo) { func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
kind := C.tinygo_clang_getCursorKind(c) kind := C.tinygo_clang_getCursorKind(c)
pos := f.getCursorPosition(c) pos := f.getCursorPosition(c)
switch kind { switch kind {
@@ -200,19 +205,43 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, *elaborat
Kind: ast.Fun, Kind: ast.Fun,
Name: "C." + name, 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) args := make([]*ast.Field, numArgs)
decl := &ast.FuncDecl{ decl := &ast.FuncDecl{
Doc: &ast.CommentGroup{ Doc: &ast.CommentGroup{
List: []*ast.Comment{ List: []*ast.Comment{
{ {
Slash: pos - 1, Slash: pos - 1,
Text: "//export " + name, Text: "//export " + exportName,
}, },
}, },
}, },
Name: &ast.Ident{ Name: &ast.Ident{
NamePos: pos, NamePos: pos,
Name: "C." + name, Name: "C." + localName,
Obj: obj, Obj: obj,
}, },
Type: &ast.FuncType{ Type: &ast.FuncType{
@@ -263,7 +292,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, *elaborat
} }
} }
obj.Decl = decl obj.Decl = decl
return decl, nil return decl, stringSignature
case C.CXCursor_StructDecl, C.CXCursor_UnionDecl: case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
typ := f.makeASTRecordType(c, pos) typ := f.makeASTRecordType(c, pos)
typeName := "C." + name typeName := "C." + name
-16
View File
@@ -1,16 +0,0 @@
//go:build !byollvm && llvm13
// +build !byollvm,llvm13
package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-13/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@13/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@13/include
#cgo freebsd CFLAGS: -I/usr/local/llvm13/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-13/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@13/lib -lclang -lffi
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@13/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm13/lib -lclang
*/
import "C"
+2 -2
View File
@@ -1,5 +1,5 @@
//go:build !byollvm && !llvm13 //go:build !byollvm
// +build !byollvm,!llvm13 // +build !byollvm
package cgo package cgo
+12
View File
@@ -17,6 +17,14 @@ CXString tinygo_clang_getCursorSpelling(CXCursor c) {
return clang_getCursorSpelling(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) { enum CXCursorKind tinygo_clang_getCursorKind(CXCursor c) {
return clang_getCursorKind(c); return clang_getCursorKind(c);
} }
@@ -45,6 +53,10 @@ CXCursor tinygo_clang_Cursor_getArgument(CXCursor c, unsigned i) {
return clang_Cursor_getArgument(c, 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) { CXSourceLocation tinygo_clang_getCursorLocation(CXCursor c) {
return clang_getCursorLocation(c); return clang_getCursorLocation(c);
} }
+2
View File
@@ -5,6 +5,7 @@ package main
int foo(int a, int b); int foo(int a, int b);
void variadic0(); void variadic0();
void variadic2(int x, int y, ...); void variadic2(int x, int y, ...);
static void staticfunc(int x);
// Global variable signatures. // Global variable signatures.
extern int someValue; extern int someValue;
@@ -16,6 +17,7 @@ func accessFunctions() {
C.foo(3, 4) C.foo(3, 4)
C.variadic0() C.variadic0()
C.variadic2(3, 5) C.variadic2(3, 5)
C.staticfunc(3)
} }
func accessGlobals() { func accessGlobals() {
+5
View File
@@ -55,5 +55,10 @@ func C.variadic2(x C.int, y C.int)
var C.variadic2$funcaddr unsafe.Pointer 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 //go:extern someValue
var C.someValue C.int var C.someValue C.int
+20 -6
View File
@@ -73,9 +73,7 @@ func (c *Config) BuildTags() []string {
for i := 1; i <= c.GoMinorVersion; i++ { for i := 1; i <= c.GoMinorVersion; i++ {
tags = append(tags, fmt.Sprintf("go1.%d", i)) tags = append(tags, fmt.Sprintf("go1.%d", i))
} }
if extraTags := strings.Fields(c.Options.Tags); len(extraTags) != 0 { tags = append(tags, c.Options.Tags...)
tags = append(tags, extraTags...)
}
return tags return tags
} }
@@ -177,6 +175,15 @@ func (c *Config) AutomaticStackSize() bool {
return false 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
}
// UseThinLTO returns whether ThinLTO should be used for the given target. Some // UseThinLTO returns whether ThinLTO should be used for the given target. Some
// targets (such as wasm) are not yet supported. // targets (such as wasm) are not yet supported.
// We should try and remove as many exceptions as possible in the future, so // We should try and remove as many exceptions as possible in the future, so
@@ -442,13 +449,13 @@ func (c *Config) OpenOCDConfiguration() (args []string, err error) {
if openocdInterface == "" { if openocdInterface == "" {
return nil, errors.New("OpenOCD programmer not set") 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) return nil, fmt.Errorf("OpenOCD programmer has an invalid name: %#v", openocdInterface)
} }
if c.Target.OpenOCDTarget == "" { if c.Target.OpenOCDTarget == "" {
return nil, errors.New("OpenOCD chip not set") 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) return nil, fmt.Errorf("OpenOCD target has an invalid name: %#v", c.Target.OpenOCDTarget)
} }
if c.Target.OpenOCDTransport != "" && c.Target.OpenOCDTransport != "swd" { if c.Target.OpenOCDTransport != "" && c.Target.OpenOCDTransport != "swd" {
@@ -459,7 +466,14 @@ func (c *Config) OpenOCDConfiguration() (args []string, err error) {
args = append(args, "-c", cmd) args = append(args, "-c", cmd)
} }
if c.Target.OpenOCDTransport != "" { if c.Target.OpenOCDTransport != "" {
args = append(args, "-c", "transport select "+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") args = append(args, "-f", "target/"+c.Target.OpenOCDTarget+".cfg")
return args, nil return args, nil
+6 -1
View File
@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"regexp" "regexp"
"strings" "strings"
"time"
) )
var ( var (
@@ -27,8 +28,10 @@ type Options struct {
GC string GC string
PanicStrategy string PanicStrategy string
Scheduler string Scheduler string
StackSize uint64 // goroutine stack size (if none could be automatically determined)
Serial string Serial string
Work bool // -work flag to print temporary build directory Work bool // -work flag to print temporary build directory
InterpTimeout time.Duration
PrintIR bool PrintIR bool
DumpSSA bool DumpSSA bool
VerifyIR bool VerifyIR bool
@@ -38,7 +41,7 @@ type Options struct {
PrintSizes string PrintSizes string
PrintAllocs *regexp.Regexp // regexp string PrintAllocs *regexp.Regexp // regexp string
PrintStacks bool PrintStacks bool
Tags string Tags []string
WasmAbi string WasmAbi string
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
TestConfig TestConfig TestConfig TestConfig
@@ -47,6 +50,8 @@ type Options struct {
LLVMFeatures string LLVMFeatures string
Directory string Directory string
PrintJSON bool PrintJSON bool
Monitor bool
BaudRate int
} }
// Verify performs a validation on the given options, raising an error if options are not valid. // Verify performs a validation on the given options, raising an error if options are not valid.
+28 -13
View File
@@ -65,7 +65,7 @@ type TargetSpec struct {
} }
// overrideProperties overrides all properties that are set in child into itself using reflection. // 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() specType := reflect.TypeOf(spec).Elem()
specValue := reflect.ValueOf(spec).Elem() specValue := reflect.ValueOf(spec).Elem()
childValue := reflect.ValueOf(child).Elem() childValue := reflect.ValueOf(child).Elem()
@@ -88,12 +88,22 @@ func (spec *TargetSpec) overrideProperties(child *TargetSpec) {
if !src.IsNil() { if !src.IsNil() {
dst.Set(src) dst.Set(src)
} }
case reflect.Slice: // for slices, append the field case reflect.Slice: // for slices, append the field and check for duplicates
dst.Set(reflect.AppendSlice(dst, src)) 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: 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 // load reads a target specification from the JSON in the given io.Reader. It
@@ -108,10 +118,10 @@ func (spec *TargetSpec) load(r io.Reader) error {
} }
// loadFromGivenStr loads the TargetSpec from the given string that could be: // loadFromGivenStr loads the TargetSpec from the given string that could be:
// - targets/ directory inside the compiler sources // - targets/ directory inside the compiler sources
// - a relative or absolute path to custom (project specific) target specification .json file; // - a relative or absolute path to custom (project specific) target specification .json file;
// the Inherits[] could contain the files from target folder (ex. stm32f4disco) // the Inherits[] could contain the files from target folder (ex. stm32f4disco)
// as well as path to custom files (ex. myAwesomeProject.json) // as well as path to custom files (ex. myAwesomeProject.json)
func (spec *TargetSpec) loadFromGivenStr(str string) error { func (spec *TargetSpec) loadFromGivenStr(str string) error {
path := "" path := ""
if strings.HasSuffix(str, ".json") { if strings.HasSuffix(str, ".json") {
@@ -141,11 +151,17 @@ func (spec *TargetSpec) resolveInherits() error {
if err != nil { if err != nil {
return err 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. // 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 *spec = *newSpec
return nil return nil
@@ -193,11 +209,10 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
// triples for historical reasons) have the form: // triples for historical reasons) have the form:
// arch-vendor-os-environment // arch-vendor-os-environment
target := llvmarch + "-unknown-" + llvmos target := llvmarch + "-unknown-" + llvmos
if options.GOARCH == "arm" {
target += "-gnueabihf"
}
if options.GOOS == "windows" { if options.GOOS == "windows" {
target += "-gnu" target += "-gnu"
} else if options.GOARCH == "arm" {
target += "-gnueabihf"
} }
return defaultTarget(options.GOOS, options.GOARCH, target) return defaultTarget(options.GOOS, options.GOARCH, target)
} }
@@ -213,7 +228,7 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
// it includes all parents as specified in the "inherits" key. // it includes all parents as specified in the "inherits" key.
err = spec.resolveInherits() err = spec.resolveInherits()
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("%s : %w", options.Target, err)
} }
if spec.Scheduler == "asyncify" { if spec.Scheduler == "asyncify" {
+3 -2
View File
@@ -1,7 +1,8 @@
package compileopts package compileopts
import ( import (
"os" "errors"
"io/fs"
"reflect" "reflect"
"testing" "testing"
) )
@@ -17,7 +18,7 @@ func TestLoadTarget(t *testing.T) {
t.Error("LoadTarget should have failed with non existing target") t.Error("LoadTarget should have failed with non existing target")
} }
if !os.IsNotExist(err) { if !errors.Is(err, fs.ErrNotExist) {
t.Error("LoadTarget failed for wrong reason:", err) t.Error("LoadTarget failed for wrong reason:", err)
} }
} }
+2 -43
View File
@@ -16,6 +16,8 @@ import "tinygo.org/x/go-llvm"
var stdlibAliases = map[string]string{ var stdlibAliases = map[string]string{
// crypto packages // crypto packages
"crypto/ed25519/internal/edwards25519/field.feMul": "crypto/ed25519/internal/edwards25519/field.feMulGeneric",
"crypto/ed25519/internal/edwards25519/field.feSquare": "crypto/ed25519/internal/edwards25519/field.feSquareGeneric",
"crypto/md5.block": "crypto/md5.blockGeneric", "crypto/md5.block": "crypto/md5.blockGeneric",
"crypto/sha1.block": "crypto/sha1.blockGeneric", "crypto/sha1.block": "crypto/sha1.blockGeneric",
"crypto/sha1.blockAMD64": "crypto/sha1.blockGeneric", "crypto/sha1.blockAMD64": "crypto/sha1.blockGeneric",
@@ -23,53 +25,10 @@ var stdlibAliases = map[string]string{
"crypto/sha512.blockAMD64": "crypto/sha512.blockGeneric", "crypto/sha512.blockAMD64": "crypto/sha512.blockGeneric",
// math package // math package
"math.Asin": "math.asin",
"math.Asinh": "math.asinh",
"math.Acos": "math.acos",
"math.Acosh": "math.acosh",
"math.Atan": "math.atan",
"math.Atanh": "math.atanh",
"math.Atan2": "math.atan2",
"math.Cbrt": "math.cbrt",
"math.Ceil": "math.ceil",
"math.archCeil": "math.ceil",
"math.Cos": "math.cos",
"math.Cosh": "math.cosh",
"math.Erf": "math.erf",
"math.Erfc": "math.erfc",
"math.Exp": "math.exp",
"math.archExp": "math.exp",
"math.Expm1": "math.expm1",
"math.Exp2": "math.exp2",
"math.archExp2": "math.exp2",
"math.Floor": "math.floor",
"math.archFloor": "math.floor",
"math.Frexp": "math.frexp",
"math.Hypot": "math.hypot",
"math.archHypot": "math.hypot", "math.archHypot": "math.hypot",
"math.Ldexp": "math.ldexp",
"math.Log": "math.log",
"math.archLog": "math.log",
"math.Log1p": "math.log1p",
"math.Log10": "math.log10",
"math.Log2": "math.log2",
"math.Max": "math.max",
"math.archMax": "math.max", "math.archMax": "math.max",
"math.Min": "math.min",
"math.archMin": "math.min", "math.archMin": "math.min",
"math.Mod": "math.mod",
"math.Modf": "math.modf",
"math.archModf": "math.modf", "math.archModf": "math.modf",
"math.Pow": "math.pow",
"math.Remainder": "math.remainder",
"math.Sin": "math.sin",
"math.Sinh": "math.sinh",
"math.Sqrt": "math.sqrt",
"math.archSqrt": "math.sqrt",
"math.Tan": "math.tan",
"math.Tanh": "math.tanh",
"math.Trunc": "math.trunc",
"math.archTrunc": "math.trunc",
} }
// createAlias implements the function (in the builder) as a call to the alias // createAlias implements the function (in the builder) as a call to the alias
+22 -23
View File
@@ -22,10 +22,6 @@ import (
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
var typeParamUnderlyingType = func(t types.Type) types.Type {
return t
}
func init() { func init() {
llvm.InitializeAllTargets() llvm.InitializeAllTargets()
llvm.InitializeAllTargetMCs() llvm.InitializeAllTargetMCs()
@@ -345,7 +341,6 @@ func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type {
// makeLLVMType creates a LLVM type for a Go type. Don't call this, use // makeLLVMType creates a LLVM type for a Go type. Don't call this, use
// getLLVMType instead. // getLLVMType instead.
func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type { func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type {
goType = typeParamUnderlyingType(goType)
switch typ := goType.(type) { switch typ := goType.(type) {
case *types.Array: case *types.Array:
elemType := c.getLLVMType(typ.Elem()) elemType := c.getLLVMType(typ.Elem())
@@ -420,6 +415,8 @@ func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type {
members[i] = c.getLLVMType(typ.Field(i).Type()) members[i] = c.getLLVMType(typ.Field(i).Type())
} }
return c.ctx.StructType(members, false) return c.ctx.StructType(members, false)
case *types.TypeParam:
return c.getLLVMType(typ.Underlying())
case *types.Tuple: case *types.Tuple:
members := make([]llvm.Type, typ.Len()) members := make([]llvm.Type, typ.Len())
for i := 0; i < typ.Len(); i++ { for i := 0; i < typ.Len(); i++ {
@@ -455,7 +452,6 @@ func (c *compilerContext) getDIType(typ types.Type) llvm.Metadata {
// createDIType creates a new DWARF type. Don't call this function directly, // createDIType creates a new DWARF type. Don't call this function directly,
// call getDIType instead. // call getDIType instead.
func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata { func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
typ = typeParamUnderlyingType(typ)
llvmType := c.getLLVMType(typ) llvmType := c.getLLVMType(typ)
sizeInBytes := c.targetData.TypeAllocSize(llvmType) sizeInBytes := c.targetData.TypeAllocSize(llvmType)
switch typ := typ.(type) { switch typ := typ.(type) {
@@ -619,6 +615,8 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
}) })
temporaryMDNode.ReplaceAllUsesWith(md) temporaryMDNode.ReplaceAllUsesWith(md)
return md return md
case *types.TypeParam:
return c.getDIType(typ.Underlying())
default: default:
panic("unknown type while generating DWARF debug type: " + typ.String()) panic("unknown type while generating DWARF debug type: " + typ.String())
} }
@@ -688,7 +686,7 @@ func (b *builder) getLocalVariable(variable *types.Var) llvm.Metadata {
Name: param.Name(), Name: param.Name(),
File: b.getDIFile(pos.Filename), File: b.getDIFile(pos.Filename),
Line: pos.Line, Line: pos.Line,
Type: b.getDIType(variable.Type()), Type: b.getDIType(param.Type()),
AlwaysPreserve: true, AlwaysPreserve: true,
ArgNo: i + 1, ArgNo: i + 1,
}) })
@@ -792,6 +790,12 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
} }
// Create the function definition. // Create the function definition.
b := newBuilder(c, irbuilder, member) b := newBuilder(c, irbuilder, member)
if _, ok := mathToLLVMMapping[member.RelString(nil)]; ok {
// The body of this function (if there is one) is ignored and
// replaced with a LLVM intrinsic call.
b.defineMathOp()
continue
}
if member.Blocks == nil { if member.Blocks == nil {
// Try to define this as an intrinsic function. // Try to define this as an intrinsic function.
b.defineIntrinsicFunction() b.defineIntrinsicFunction()
@@ -1026,7 +1030,7 @@ func (c *compilerContext) getEmbedFileString(file *loader.EmbedFile) llvm.Value
// parameters, create basic blocks, and set up debug information. // parameters, create basic blocks, and set up debug information.
// This is separated out from createFunction() so that it is also usable to // This is separated out from createFunction() so that it is also usable to
// define compiler intrinsics like the atomic operations in sync/atomic. // define compiler intrinsics like the atomic operations in sync/atomic.
func (b *builder) createFunctionStart() { func (b *builder) createFunctionStart(intrinsic bool) {
if b.DumpSSA { if b.DumpSSA {
fmt.Printf("\nfunc %s:\n", b.fn) fmt.Printf("\nfunc %s:\n", b.fn)
} }
@@ -1099,20 +1103,20 @@ func (b *builder) createFunctionStart() {
} }
// Pre-create all basic blocks in the function. // Pre-create all basic blocks in the function.
for _, block := range b.fn.DomPreorder() {
llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment)
b.blockEntries[block] = llvmBlock
b.blockExits[block] = llvmBlock
}
var entryBlock llvm.BasicBlock var entryBlock llvm.BasicBlock
if len(b.fn.Blocks) != 0 { if intrinsic {
// Normal functions have an entry block.
entryBlock = b.blockEntries[b.fn.Blocks[0]]
} else {
// This function isn't defined in Go SSA. It is probably a compiler // This function isn't defined in Go SSA. It is probably a compiler
// intrinsic (like an atomic operation). Create the entry block // intrinsic (like an atomic operation). Create the entry block
// manually. // manually.
entryBlock = b.ctx.AddBasicBlock(b.llvmFn, "entry") entryBlock = b.ctx.AddBasicBlock(b.llvmFn, "entry")
} else {
for _, block := range b.fn.DomPreorder() {
llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment)
b.blockEntries[block] = llvmBlock
b.blockExits[block] = llvmBlock
}
// Normal functions have an entry block.
entryBlock = b.blockEntries[b.fn.Blocks[0]]
} }
b.SetInsertPointAtEnd(entryBlock) b.SetInsertPointAtEnd(entryBlock)
@@ -1194,7 +1198,7 @@ func (b *builder) createFunctionStart() {
// function must not yet be defined, otherwise this function will create a // function must not yet be defined, otherwise this function will create a
// diagnostic. // diagnostic.
func (b *builder) createFunction() { func (b *builder) createFunction() {
b.createFunctionStart() b.createFunctionStart(false)
// Fill blocks with instructions. // Fill blocks with instructions.
for _, block := range b.fn.DomPreorder() { for _, block := range b.fn.DomPreorder() {
@@ -1656,11 +1660,6 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
// applied) function call. If it is anonymous, it may be a closure. // applied) function call. If it is anonymous, it may be a closure.
name := fn.RelString(nil) name := fn.RelString(nil)
switch { switch {
case name == "math.Ceil" || name == "math.Floor" || name == "math.Sqrt" || name == "math.Trunc":
result, ok := b.createMathOp(instr)
if ok {
return result, nil
}
case name == "device.Asm" || name == "device/arm.Asm" || name == "device/arm64.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm": case name == "device.Asm" || name == "device/arm.Asm" || name == "device/arm64.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm":
return b.createInlineAsm(instr.Args) return b.createInlineAsm(instr.Args)
case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/arm64.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull": case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/arm64.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull":
-18
View File
@@ -1,18 +0,0 @@
//go:build go1.18
// +build go1.18
package compiler
// Workaround for Go 1.17 support. Should be removed once we drop Go 1.17
// support.
import "go/types"
func init() {
typeParamUnderlyingType = func(t types.Type) types.Type {
if t, ok := t.(*types.TypeParam); ok {
return t.Underlying()
}
return t
}
}
+4 -29
View File
@@ -3,13 +3,12 @@ package compiler
import ( import (
"flag" "flag"
"go/types" "go/types"
"io/ioutil" "os"
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
"github.com/tinygo-org/tinygo/compileopts" "github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
"github.com/tinygo-org/tinygo/loader" "github.com/tinygo-org/tinygo/loader"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
@@ -28,18 +27,6 @@ type testCase struct {
func TestCompiler(t *testing.T) { func TestCompiler(t *testing.T) {
t.Parallel() t.Parallel()
// Determine LLVM version.
llvmMajor, err := strconv.Atoi(strings.SplitN(llvm.Version, ".", 2)[0])
if err != nil {
t.Fatal("could not parse LLVM version:", llvm.Version)
}
// Determine Go minor version (e.g. 16 in go1.16.3).
_, goMinor, err := goenv.GetGorootVersion(goenv.Get("GOROOT"))
if err != nil {
t.Fatal("could not read Go version:", err)
}
// Determine which tests to run, depending on the Go and LLVM versions. // Determine which tests to run, depending on the Go and LLVM versions.
tests := []testCase{ tests := []testCase{
{"basic.go", "", ""}, {"basic.go", "", ""},
@@ -54,20 +41,8 @@ func TestCompiler(t *testing.T) {
{"goroutine.go", "wasm", "asyncify"}, {"goroutine.go", "wasm", "asyncify"},
{"goroutine.go", "cortex-m-qemu", "tasks"}, {"goroutine.go", "cortex-m-qemu", "tasks"},
{"channel.go", "", ""}, {"channel.go", "", ""},
{"intrinsics.go", "cortex-m-qemu", ""},
{"intrinsics.go", "wasm", ""},
{"gc.go", "", ""}, {"gc.go", "", ""},
} }
if llvmMajor >= 12 {
tests = append(tests, testCase{"intrinsics.go", "cortex-m-qemu", ""})
tests = append(tests, testCase{"intrinsics.go", "wasm", ""})
}
if goMinor >= 17 {
tests = append(tests, testCase{"go1.17.go", "", ""})
}
if goMinor >= 18 {
tests = append(tests, testCase{"generics.go", "", ""})
}
for _, tc := range tests { for _, tc := range tests {
name := tc.file name := tc.file
@@ -104,7 +79,7 @@ func TestCompiler(t *testing.T) {
RelocationModel: config.RelocationModel(), RelocationModel: config.RelocationModel(),
Scheduler: config.Scheduler(), Scheduler: config.Scheduler(),
AutomaticStackSize: config.AutomaticStackSize(), AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.Target.DefaultStackSize, DefaultStackSize: config.StackSize(),
NeedsStackObjects: config.NeedsStackObjects(), NeedsStackObjects: config.NeedsStackObjects(),
} }
machine, err := NewTargetMachine(compilerConfig) machine, err := NewTargetMachine(compilerConfig)
@@ -162,14 +137,14 @@ func TestCompiler(t *testing.T) {
// Update test if needed. Do not check the result. // Update test if needed. Do not check the result.
if *flagUpdate { if *flagUpdate {
err := ioutil.WriteFile(outPath, []byte(mod.String()), 0666) err := os.WriteFile(outPath, []byte(mod.String()), 0666)
if err != nil { if err != nil {
t.Error("failed to write updated output file:", err) t.Error("failed to write updated output file:", err)
} }
return return
} }
expected, err := ioutil.ReadFile(outPath) expected, err := os.ReadFile(outPath)
if err != nil { if err != nil {
t.Fatal("failed to read golden file:", err) t.Fatal("failed to read golden file:", err)
} }
+7 -7
View File
@@ -120,16 +120,16 @@ func (b *builder) createGo(instr *ssa.Go) {
// createGoroutineStartWrapper creates a wrapper for the task-based // createGoroutineStartWrapper creates a wrapper for the task-based
// implementation of goroutines. For example, to call a function like this: // 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: // It creates a wrapper like this:
// //
// func add$gowrapper(ptr *unsafe.Pointer) { // func add$gowrapper(ptr *unsafe.Pointer) {
// args := (*struct{ // args := (*struct{
// x, y int // x, y int
// })(ptr) // })(ptr)
// add(args.x, args.y) // add(args.x, args.y)
// } // }
// //
// This is useful because the task-based goroutine start implementation only // This is useful because the task-based goroutine start implementation only
// allows a single (pointer) argument to the newly started goroutine. Also, it // allows a single (pointer) argument to the newly started goroutine. Also, it
+22 -22
View File
@@ -17,7 +17,7 @@ import (
// operands or return values. It is useful for trivial instructions, like wfi in // operands or return values. It is useful for trivial instructions, like wfi in
// ARM or sleep in AVR. // ARM or sleep in AVR.
// //
// func Asm(asm string) // func Asm(asm string)
// //
// The provided assembly must be a constant. // The provided assembly must be a constant.
func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) { func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
@@ -31,17 +31,17 @@ func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
// This is a compiler builtin, which allows assembly to be called in a flexible // This is a compiler builtin, which allows assembly to be called in a flexible
// way. // 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 // The asm parameter must be a constant string. The regs parameter must be
// provided immediately. For example: // provided immediately. For example:
// //
// arm.AsmFull( // arm.AsmFull(
// "str {value}, {result}", // "str {value}, {result}",
// map[string]interface{}{ // map[string]interface{}{
// "value": 1 // "value": 1
// "result": &dest, // "result": &dest,
// }) // })
func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error) { func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error) {
asmString := constant.StringVal(instr.Args[0].(*ssa.Const).Value) asmString := constant.StringVal(instr.Args[0].(*ssa.Const).Value)
registers := map[string]llvm.Value{} registers := map[string]llvm.Value{}
@@ -132,11 +132,11 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
// This is a compiler builtin which emits an inline SVCall instruction. It can // This is a compiler builtin which emits an inline SVCall instruction. It can
// be one of: // be one of:
// //
// func SVCall0(num uintptr) uintptr // func SVCall0(num uintptr) uintptr
// func SVCall1(num uintptr, a1 interface{}) uintptr // func SVCall1(num uintptr, a1 interface{}) uintptr
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr // func SVCall2(num uintptr, a1, a2 interface{}) uintptr
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr // func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
// func SVCall4(num uintptr, a1, a2, a3, a4 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 // The num parameter must be a constant. All other parameters may be any scalar
// value supported by LLVM inline assembly. // value supported by LLVM inline assembly.
@@ -169,11 +169,11 @@ func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
// This is a compiler builtin which emits an inline SVCall instruction. It can // This is a compiler builtin which emits an inline SVCall instruction. It can
// be one of: // be one of:
// //
// func SVCall0(num uintptr) uintptr // func SVCall0(num uintptr) uintptr
// func SVCall1(num uintptr, a1 interface{}) uintptr // func SVCall1(num uintptr, a1 interface{}) uintptr
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr // func SVCall2(num uintptr, a1, a2 interface{}) uintptr
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr // func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
// func SVCall4(num uintptr, a1, a2, a3, a4 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 // The num parameter must be a constant. All other parameters may be any scalar
// value supported by LLVM inline assembly. // value supported by LLVM inline assembly.
@@ -206,10 +206,10 @@ func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
// This is a compiler builtin which emits CSR instructions. It can be one of: // This is a compiler builtin which emits CSR instructions. It can be one of:
// //
// func (csr CSR) Get() uintptr // func (csr CSR) Get() uintptr
// func (csr CSR) Set(uintptr) // func (csr CSR) Set(uintptr)
// func (csr CSR) SetBits(uintptr) uintptr // func (csr CSR) SetBits(uintptr) uintptr
// func (csr CSR) ClearBits(uintptr) uintptr // func (csr CSR) ClearBits(uintptr) uintptr
// //
// The csr parameter (method receiver) must be a constant. Other parameter can // The csr parameter (method receiver) must be a constant. Other parameter can
// be any value. // be any value.
+4 -4
View File
@@ -550,8 +550,8 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFn llv
// internally to match interfaces and to call the correct method on an // internally to match interfaces and to call the correct method on an
// interface. Examples: // interface. Examples:
// //
// String() string // String() string
// Read([]byte) (int, error) // Read([]byte) (int, error)
func methodSignature(method *types.Func) string { func methodSignature(method *types.Func) string {
return method.Name() + signature(method.Type().(*types.Signature)) return method.Name() + signature(method.Type().(*types.Signature))
} }
@@ -559,8 +559,8 @@ func methodSignature(method *types.Func) string {
// Make a readable version of a function (pointer) signature. // Make a readable version of a function (pointer) signature.
// Examples: // Examples:
// //
// () string // () string
// (string, int) (int, error) // (string, int) (int, error)
func signature(sig *types.Signature) string { func signature(sig *types.Signature) string {
s := "" s := ""
if sig.Params().Len() == 0 { if sig.Params().Len() == 0 {
+30 -42
View File
@@ -7,7 +7,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"golang.org/x/tools/go/ssa"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
@@ -29,7 +28,7 @@ func (b *builder) defineIntrinsicFunction() {
case strings.HasPrefix(name, "runtime/volatile.Store"): case strings.HasPrefix(name, "runtime/volatile.Store"):
b.createVolatileStore() b.createVolatileStore()
case strings.HasPrefix(name, "sync/atomic.") && token.IsExported(b.fn.Name()): case strings.HasPrefix(name, "sync/atomic.") && token.IsExported(b.fn.Name()):
b.createFunctionStart() b.createFunctionStart(true)
returnValue := b.createAtomicOp(b.fn.Name()) returnValue := b.createAtomicOp(b.fn.Name())
if !returnValue.IsNil() { if !returnValue.IsNil() {
b.CreateRet(returnValue) b.CreateRet(returnValue)
@@ -44,7 +43,7 @@ func (b *builder) defineIntrinsicFunction() {
// specially by optimization passes possibly resulting in better generated code, // specially by optimization passes possibly resulting in better generated code,
// and will otherwise be lowered to regular libc memcpy/memmove calls. // and will otherwise be lowered to regular libc memcpy/memmove calls.
func (b *builder) createMemoryCopyImpl() { func (b *builder) createMemoryCopyImpl() {
b.createFunctionStart() b.createFunctionStart(true)
fnName := "llvm." + b.fn.Name() + ".p0i8.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth()) fnName := "llvm." + b.fn.Name() + ".p0i8.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
llvmFn := b.mod.NamedFunction(fnName) llvmFn := b.mod.NamedFunction(fnName)
if llvmFn.IsNil() { if llvmFn.IsNil() {
@@ -64,7 +63,7 @@ func (b *builder) createMemoryCopyImpl() {
// memory, declaring the function if needed. These calls will be lowered to // 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. // regular libc memset calls if they aren't optimized out in a different way.
func (b *builder) createMemoryZeroImpl() { func (b *builder) createMemoryZeroImpl() {
b.createFunctionStart() b.createFunctionStart(true)
fnName := "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth()) fnName := "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
llvmFn := b.mod.NamedFunction(fnName) llvmFn := b.mod.NamedFunction(fnName)
if llvmFn.IsNil() { if llvmFn.IsNil() {
@@ -82,55 +81,44 @@ func (b *builder) createMemoryZeroImpl() {
} }
var mathToLLVMMapping = map[string]string{ var mathToLLVMMapping = map[string]string{
"math.Sqrt": "llvm.sqrt.f64",
"math.Floor": "llvm.floor.f64",
"math.Ceil": "llvm.ceil.f64", "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", "math.Trunc": "llvm.trunc.f64",
} }
// createMathOp tries to lower the given call as a LLVM math intrinsic, if // defineMathOp defines a math function body as a call to a LLVM intrinsic,
// possible. It returns the call result if possible, and a boolean whether it // instead of the regular Go implementation. This allows LLVM to reason about
// succeeded. If it doesn't succeed, the architecture doesn't support the given // the math operation and (depending on the architecture) allows it to lower the
// intrinsic. // operation to very fast floating point instructions. If this is not possible,
func (b *builder) createMathOp(call *ssa.CallCommon) (llvm.Value, bool) { // LLVM will emit a call to a libm function that implements the same operation.
// Check whether this intrinsic is supported on the given GOARCH. //
// If it is unsupported, this can have two reasons: // 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
// 1. LLVM can expand the intrinsic inline (using float instructions), but // beneficial on architectures where 64-bit floating point operations are (much)
// the result doesn't pass the tests of the math package. // more expensive than 32-bit ones.
// 2. LLVM cannot expand the intrinsic inline, will therefore lower it as a func (b *builder) defineMathOp() {
// libm function call, but the libm function call also fails the math b.createFunctionStart(true)
// package tests. llvmName := mathToLLVMMapping[b.fn.RelString(nil)]
// if llvmName == "" {
// Whatever the implementation, it must pass the tests in the math package panic("unreachable: unknown math operation") // sanity check
// so unfortunately only the below intrinsic+architecture combinations are
// supported.
name := call.StaticCallee().RelString(nil)
switch name {
case "math.Ceil", "math.Floor", "math.Trunc":
if b.GOARCH != "wasm" && b.GOARCH != "arm64" {
return llvm.Value{}, false
}
case "math.Sqrt":
if b.GOARCH != "wasm" && b.GOARCH != "amd64" && b.GOARCH != "386" {
return llvm.Value{}, false
}
default:
return llvm.Value{}, false // only the above functions are supported.
} }
llvmFn := b.mod.NamedFunction(llvmName)
llvmFn := b.mod.NamedFunction(mathToLLVMMapping[name])
if llvmFn.IsNil() { if llvmFn.IsNil() {
// The intrinsic doesn't exist yet, so declare it. // The intrinsic doesn't exist yet, so declare it.
// At the moment, all supported intrinsics have the form "double // At the moment, all supported intrinsics have the form "double
// foo(double %x)" so we can hardcode the signature here. // foo(double %x)" so we can hardcode the signature here.
llvmType := llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType()}, false) llvmType := llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType()}, false)
llvmFn = llvm.AddFunction(b.mod, mathToLLVMMapping[name], llvmType) llvmFn = llvm.AddFunction(b.mod, llvmName, llvmType)
} }
// Create a call to the intrinsic. // Create a call to the intrinsic.
args := make([]llvm.Value, len(call.Args)) args := make([]llvm.Value, len(b.fn.Params))
for i, arg := range call.Args { for i, param := range b.fn.Params {
args[i] = b.getValue(arg) args[i] = b.getValue(param)
} }
return b.CreateCall(llvmFn, args, ""), true result := b.CreateCall(llvmFn, args, "")
b.CreateRet(result)
} }
+1 -1
View File
@@ -152,7 +152,7 @@ func (s *stdSizes) Sizeof(T types.Type) int64 {
return align(offsets[n-1]+s.Sizeof(fields[n-1].Type()), maxAlign) return align(offsets[n-1]+s.Sizeof(fields[n-1].Type()), maxAlign)
case *types.Interface: case *types.Interface:
return s.PtrSize * 2 return s.PtrSize * 2
case *types.Pointer: case *types.Pointer, *types.Chan, *types.Map:
return s.PtrSize return s.PtrSize
case *types.Signature: case *types.Signature:
// Func values in TinyGo are two words in size. // Func values in TinyGo are two words in size.
+12 -10
View File
@@ -163,18 +163,20 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
// External/exported functions may not retain pointer values. // External/exported functions may not retain pointer values.
// https://golang.org/cmd/cgo/#hdr-Passing_pointers // https://golang.org/cmd/cgo/#hdr-Passing_pointers
if info.exported { if info.exported {
// Set the wasm-import-module attribute if the function's module is set. if c.archFamily() == "wasm32" {
if info.module != "" {
// We need to add the wasm-import-module and the wasm-import-name // We need to add the wasm-import-module and the wasm-import-name
wasmImportModuleAttr := c.ctx.CreateStringAttribute("wasm-import-module", info.module) // attributes.
llvmFn.AddFunctionAttr(wasmImportModuleAttr) module := info.module
if module == "" {
// Add the Wasm Import Name, if we are a named wasm import module = "env"
if info.importName != "" {
wasmImportNameAttr := c.ctx.CreateStringAttribute("wasm-import-name", info.importName)
llvmFn.AddFunctionAttr(wasmImportNameAttr)
} }
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-module", module))
name := info.importName
if name == "" {
name = info.linkName
}
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", name))
} }
nocaptureKind := llvm.AttributeKindID("nocapture") nocaptureKind := llvm.AttributeKindID("nocapture")
nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0) nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
-41
View File
@@ -1,41 +0,0 @@
package main
// Test changes to the language introduced in Go 1.17.
// For details, see: https://tip.golang.org/doc/go1.17#language
// These tests should be merged into the regular slice tests once Go 1.17 is the
// minimun Go version for TinyGo.
import "unsafe"
func Add32(p unsafe.Pointer, len int) unsafe.Pointer {
return unsafe.Add(p, len)
}
func Add64(p unsafe.Pointer, len int64) unsafe.Pointer {
return unsafe.Add(p, len)
}
func SliceToArray(s []int) *[4]int {
return (*[4]int)(s)
}
func SliceToArrayConst() *[4]int {
s := make([]int, 6)
return (*[4]int)(s)
}
func SliceInt(ptr *int, len int) []int {
return unsafe.Slice(ptr, len)
}
func SliceUint16(ptr *byte, len uint16) []byte {
return unsafe.Slice(ptr, len)
}
func SliceUint64(ptr *int, len uint64) []int {
return unsafe.Slice(ptr, len)
}
func SliceInt64(ptr *int, len int64) []int {
return unsafe.Slice(ptr, len)
}
-161
View File
@@ -1,161 +0,0 @@
; ModuleID = 'go1.17.go'
source_filename = "go1.17.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i8* @main.Add32(i8* %p, i32 %len, i8* %context) unnamed_addr #1 {
entry:
%0 = getelementptr i8, i8* %p, i32 %len
call void @runtime.trackPointer(i8* %0, i8* undef) #2
ret i8* %0
}
; Function Attrs: nounwind
define hidden i8* @main.Add64(i8* %p, i64 %len, i8* %context) unnamed_addr #1 {
entry:
%0 = trunc i64 %len to i32
%1 = getelementptr i8, i8* %p, i32 %0
call void @runtime.trackPointer(i8* %1, i8* undef) #2
ret i8* %1
}
; Function Attrs: nounwind
define hidden [4 x i32]* @main.SliceToArray(i32* %s.data, i32 %s.len, i32 %s.cap, i8* %context) unnamed_addr #1 {
entry:
%0 = icmp ult i32 %s.len, 4
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
slicetoarray.next: ; preds = %entry
%1 = bitcast i32* %s.data to [4 x i32]*
ret [4 x i32]* %1
slicetoarray.throw: ; preds = %entry
call void @runtime.sliceToArrayPointerPanic(i8* undef) #2
unreachable
}
declare void @runtime.sliceToArrayPointerPanic(i8*) #0
; Function Attrs: nounwind
define hidden [4 x i32]* @main.SliceToArrayConst(i8* %context) unnamed_addr #1 {
entry:
%makeslice = call i8* @runtime.alloc(i32 24, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #2
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
slicetoarray.next: ; preds = %entry
%0 = bitcast i8* %makeslice to [4 x i32]*
ret [4 x i32]* %0
slicetoarray.throw: ; preds = %entry
unreachable
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.SliceInt(i32* dereferenceable_or_null(4) %ptr, i32 %len, i8* %context) unnamed_addr #1 {
entry:
%0 = icmp ugt i32 %len, 1073741823
%1 = icmp eq i32* %ptr, null
%2 = icmp ne i32 %len, 0
%3 = and i1 %1, %2
%4 = or i1 %3, %0
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.next: ; preds = %entry
%5 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
%6 = insertvalue { i32*, i32, i32 } %5, i32 %len, 1
%7 = insertvalue { i32*, i32, i32 } %6, i32 %len, 2
%8 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %8, i8* undef) #2
ret { i32*, i32, i32 } %7
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #2
unreachable
}
declare void @runtime.unsafeSlicePanic(i8*) #0
; Function Attrs: nounwind
define hidden { i8*, i32, i32 } @main.SliceUint16(i8* dereferenceable_or_null(1) %ptr, i16 %len, i8* %context) unnamed_addr #1 {
entry:
%0 = icmp eq i8* %ptr, null
%1 = icmp ne i16 %len, 0
%2 = and i1 %0, %1
br i1 %2, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.next: ; preds = %entry
%3 = zext i16 %len to i32
%4 = insertvalue { i8*, i32, i32 } undef, i8* %ptr, 0
%5 = insertvalue { i8*, i32, i32 } %4, i32 %3, 1
%6 = insertvalue { i8*, i32, i32 } %5, i32 %3, 2
call void @runtime.trackPointer(i8* %ptr, i8* undef) #2
ret { i8*, i32, i32 } %6
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #2
unreachable
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.SliceUint64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #1 {
entry:
%0 = icmp ugt i64 %len, 1073741823
%1 = icmp eq i32* %ptr, null
%2 = icmp ne i64 %len, 0
%3 = and i1 %1, %2
%4 = or i1 %3, %0
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.next: ; preds = %entry
%5 = trunc i64 %len to i32
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
%7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2
%9 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %9, i8* undef) #2
ret { i32*, i32, i32 } %8
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #2
unreachable
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.SliceInt64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #1 {
entry:
%0 = icmp ugt i64 %len, 1073741823
%1 = icmp eq i32* %ptr, null
%2 = icmp ne i64 %len, 0
%3 = and i1 %1, %2
%4 = or i1 %3, %0
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.next: ; preds = %entry
%5 = trunc i64 %len to i32
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
%7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2
%9 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %9, i8* undef) #2
ret { i32*, i32, i32 } %8
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #2
unreachable
}
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind }
-34
View File
@@ -1,34 +0,0 @@
; ModuleID = 'intrinsics.go'
source_filename = "intrinsics.go"
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "thumbv7m-unknown-unknown-eabi"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden double @main.mySqrt(double %x, i8* %context) unnamed_addr #1 {
entry:
%0 = call double @math.Sqrt(double %x, i8* undef) #2
ret double %0
}
declare double @math.Sqrt(double, i8*) #0
; Function Attrs: nounwind
define hidden double @main.myTrunc(double %x, i8* %context) unnamed_addr #1 {
entry:
%0 = call double @math.Trunc(double %x, i8* undef) #2
ret double %0
}
declare double @math.Trunc(double, i8*) #0
attributes #0 = { "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #1 = { nounwind "target-features"="+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
attributes #2 = { nounwind }
-38
View File
@@ -1,38 +0,0 @@
; ModuleID = 'intrinsics.go'
source_filename = "intrinsics.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) #0
declare void @runtime.trackPointer(i8* nocapture readonly, i8*) #0
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #1 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden double @main.mySqrt(double %x, i8* %context) unnamed_addr #1 {
entry:
%0 = call double @llvm.sqrt.f64(double %x)
ret double %0
}
; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare double @llvm.sqrt.f64(double) #2
; Function Attrs: nounwind
define hidden double @main.myTrunc(double %x, i8* %context) unnamed_addr #1 {
entry:
%0 = call double @llvm.trunc.f64(double %x)
ret double %0
}
; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare double @llvm.trunc.f64(double) #2
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nofree nosync nounwind readnone speculatable willreturn }
-14
View File
@@ -1,14 +0,0 @@
package main
// Test how intrinsics are lowered: either as regular calls to the math
// functions or as LLVM builtins (such as llvm.sqrt.f64).
import "math"
func mySqrt(x float64) float64 {
return math.Sqrt(x)
}
func myTrunc(x float64) float64 {
return math.Trunc(x)
}
+10
View File
@@ -3,44 +3,53 @@ package main
import _ "unsafe" import _ "unsafe"
// Creates an external global with name extern_global. // Creates an external global with name extern_global.
//
//go:extern extern_global //go:extern extern_global
var externGlobal [0]byte var externGlobal [0]byte
// Creates a // Creates a
//
//go:align 32 //go:align 32
var alignedGlobal [4]uint32 var alignedGlobal [4]uint32
// Test conflicting pragmas (the last one counts). // Test conflicting pragmas (the last one counts).
//
//go:align 64 //go:align 64
//go:align 16 //go:align 16
var alignedGlobal16 [4]uint32 var alignedGlobal16 [4]uint32
// Test exported functions. // Test exported functions.
//
//export extern_func //export extern_func
func externFunc() { func externFunc() {
} }
// Define a function in a different package using go:linkname. // Define a function in a different package using go:linkname.
//
//go:linkname withLinkageName1 somepkg.someFunction1 //go:linkname withLinkageName1 somepkg.someFunction1
func withLinkageName1() { func withLinkageName1() {
} }
// Import a function from a different package using go:linkname. // Import a function from a different package using go:linkname.
//
//go:linkname withLinkageName2 somepkg.someFunction2 //go:linkname withLinkageName2 somepkg.someFunction2
func withLinkageName2() func withLinkageName2()
// Function has an 'inline hint', similar to the inline keyword in C. // Function has an 'inline hint', similar to the inline keyword in C.
//
//go:inline //go:inline
func inlineFunc() { func inlineFunc() {
} }
// Function should never be inlined, equivalent to GCC // Function should never be inlined, equivalent to GCC
// __attribute__((noinline)). // __attribute__((noinline)).
//
//go:noinline //go:noinline
func noinlineFunc() { func noinlineFunc() {
} }
// This function should have the specified section. // This function should have the specified section.
//
//go:section .special_function_section //go:section .special_function_section
func functionInSection() { func functionInSection() {
} }
@@ -51,6 +60,7 @@ func exportedFunctionInSection() {
} }
// This function should not: it's only a declaration and not a definition. // This function should not: it's only a declaration and not a definition.
//
//go:section .special_function_section //go:section .special_function_section
func undefinedFunctionNotInSection() func undefinedFunctionNotInSection()
+2 -2
View File
@@ -62,7 +62,7 @@ declare void @main.undefinedFunctionNotInSection(i8*) #0
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" } attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" } attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" } attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" "wasm-import-module"="env" "wasm-import-name"="extern_func" }
attributes #3 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" } attributes #3 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #4 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" } attributes #4 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" } attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" }
+35
View File
@@ -1,5 +1,7 @@
package main package main
import "unsafe"
func sliceLen(ints []int) int { func sliceLen(ints []int) int {
return len(ints) return len(ints)
} }
@@ -41,3 +43,36 @@ func makeArraySlice(len int) [][3]byte {
func makeInt32Slice(len int) []int32 { func makeInt32Slice(len int) []int32 {
return make([]int32, len) return make([]int32, len)
} }
func Add32(p unsafe.Pointer, len int) unsafe.Pointer {
return unsafe.Add(p, len)
}
func Add64(p unsafe.Pointer, len int64) unsafe.Pointer {
return unsafe.Add(p, len)
}
func SliceToArray(s []int) *[4]int {
return (*[4]int)(s)
}
func SliceToArrayConst() *[4]int {
s := make([]int, 6)
return (*[4]int)(s)
}
func SliceInt(ptr *int, len int) []int {
return unsafe.Slice(ptr, len)
}
func SliceUint16(ptr *byte, len uint16) []byte {
return unsafe.Slice(ptr, len)
}
func SliceUint64(ptr *int, len uint64) []int {
return unsafe.Slice(ptr, len)
}
func SliceInt64(ptr *int, len int64) []int {
return unsafe.Slice(ptr, len)
}
+143
View File
@@ -183,6 +183,149 @@ slice.throw: ; preds = %entry
unreachable unreachable
} }
; Function Attrs: nounwind
define hidden i8* @main.Add32(i8* %p, i32 %len, i8* %context) unnamed_addr #1 {
entry:
%0 = getelementptr i8, i8* %p, i32 %len
call void @runtime.trackPointer(i8* %0, i8* undef) #2
ret i8* %0
}
; Function Attrs: nounwind
define hidden i8* @main.Add64(i8* %p, i64 %len, i8* %context) unnamed_addr #1 {
entry:
%0 = trunc i64 %len to i32
%1 = getelementptr i8, i8* %p, i32 %0
call void @runtime.trackPointer(i8* %1, i8* undef) #2
ret i8* %1
}
; Function Attrs: nounwind
define hidden [4 x i32]* @main.SliceToArray(i32* %s.data, i32 %s.len, i32 %s.cap, i8* %context) unnamed_addr #1 {
entry:
%0 = icmp ult i32 %s.len, 4
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
slicetoarray.next: ; preds = %entry
%1 = bitcast i32* %s.data to [4 x i32]*
ret [4 x i32]* %1
slicetoarray.throw: ; preds = %entry
call void @runtime.sliceToArrayPointerPanic(i8* undef) #2
unreachable
}
declare void @runtime.sliceToArrayPointerPanic(i8*) #0
; Function Attrs: nounwind
define hidden [4 x i32]* @main.SliceToArrayConst(i8* %context) unnamed_addr #1 {
entry:
%makeslice = call i8* @runtime.alloc(i32 24, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #2
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #2
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
slicetoarray.next: ; preds = %entry
%0 = bitcast i8* %makeslice to [4 x i32]*
ret [4 x i32]* %0
slicetoarray.throw: ; preds = %entry
unreachable
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.SliceInt(i32* dereferenceable_or_null(4) %ptr, i32 %len, i8* %context) unnamed_addr #1 {
entry:
%0 = icmp ugt i32 %len, 1073741823
%1 = icmp eq i32* %ptr, null
%2 = icmp ne i32 %len, 0
%3 = and i1 %1, %2
%4 = or i1 %3, %0
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.next: ; preds = %entry
%5 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
%6 = insertvalue { i32*, i32, i32 } %5, i32 %len, 1
%7 = insertvalue { i32*, i32, i32 } %6, i32 %len, 2
%8 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %8, i8* undef) #2
ret { i32*, i32, i32 } %7
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #2
unreachable
}
declare void @runtime.unsafeSlicePanic(i8*) #0
; Function Attrs: nounwind
define hidden { i8*, i32, i32 } @main.SliceUint16(i8* dereferenceable_or_null(1) %ptr, i16 %len, i8* %context) unnamed_addr #1 {
entry:
%0 = icmp eq i8* %ptr, null
%1 = icmp ne i16 %len, 0
%2 = and i1 %0, %1
br i1 %2, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.next: ; preds = %entry
%3 = zext i16 %len to i32
%4 = insertvalue { i8*, i32, i32 } undef, i8* %ptr, 0
%5 = insertvalue { i8*, i32, i32 } %4, i32 %3, 1
%6 = insertvalue { i8*, i32, i32 } %5, i32 %3, 2
call void @runtime.trackPointer(i8* %ptr, i8* undef) #2
ret { i8*, i32, i32 } %6
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #2
unreachable
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.SliceUint64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #1 {
entry:
%0 = icmp ugt i64 %len, 1073741823
%1 = icmp eq i32* %ptr, null
%2 = icmp ne i64 %len, 0
%3 = and i1 %1, %2
%4 = or i1 %3, %0
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.next: ; preds = %entry
%5 = trunc i64 %len to i32
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
%7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2
%9 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %9, i8* undef) #2
ret { i32*, i32, i32 } %8
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #2
unreachable
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.SliceInt64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #1 {
entry:
%0 = icmp ugt i64 %len, 1073741823
%1 = icmp eq i32* %ptr, null
%2 = icmp ne i64 %len, 0
%3 = and i1 %1, %2
%4 = or i1 %3, %0
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.next: ; preds = %entry
%5 = trunc i64 %len to i32
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
%7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2
%9 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %9, i8* undef) #2
ret { i32*, i32, i32 } %8
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #2
unreachable
}
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" } attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" } attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
attributes #2 = { nounwind } attributes #2 = { nounwind }
+2 -2
View File
@@ -6,7 +6,7 @@ package compiler
// createVolatileLoad is the implementation of the intrinsic function // createVolatileLoad is the implementation of the intrinsic function
// runtime/volatile.LoadT(). // runtime/volatile.LoadT().
func (b *builder) createVolatileLoad() { func (b *builder) createVolatileLoad() {
b.createFunctionStart() b.createFunctionStart(true)
addr := b.getValue(b.fn.Params[0]) addr := b.getValue(b.fn.Params[0])
b.createNilCheck(b.fn.Params[0], addr, "deref") b.createNilCheck(b.fn.Params[0], addr, "deref")
val := b.CreateLoad(addr, "") val := b.CreateLoad(addr, "")
@@ -17,7 +17,7 @@ func (b *builder) createVolatileLoad() {
// createVolatileStore is the implementation of the intrinsic function // createVolatileStore is the implementation of the intrinsic function
// runtime/volatile.StoreT(). // runtime/volatile.StoreT().
func (b *builder) createVolatileStore() { func (b *builder) createVolatileStore() {
b.createFunctionStart() b.createFunctionStart(true)
addr := b.getValue(b.fn.Params[0]) addr := b.getValue(b.fn.Params[0])
val := b.getValue(b.fn.Params[1]) val := b.getValue(b.fn.Params[1])
b.createNilCheck(b.fn.Params[0], addr, "deref") b.createNilCheck(b.fn.Params[0], addr, "deref")
+5 -2
View File
@@ -8,6 +8,7 @@ import (
"sync" "sync"
"testing" "testing"
"golang.org/x/tools/go/buildutil"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
@@ -111,9 +112,11 @@ func TestCorpus(t *testing.T) {
opts := optionsFromTarget(target, sema) opts := optionsFromTarget(target, sema)
opts.Directory = dir opts.Directory = dir
opts.Tags = repo.Tags var tags buildutil.TagsFlag
tags.Set(repo.Tags)
opts.Tags = []string(tags)
passed, err := Test(path, out, out, &opts, false, testing.Verbose(), false, "", "", "", "") passed, err := Test(path, out, out, &opts, false, testing.Verbose(), false, "", "", "", false, "")
if err != nil { if err != nil {
t.Errorf("test error: %v", err) t.Errorf("test error: %v", err)
} }
+18 -4
View File
@@ -1,6 +1,6 @@
module github.com/tinygo-org/tinygo module github.com/tinygo-org/tinygo
go 1.16 go 1.18
require ( require (
github.com/aykevl/go-wasm v0.0.2-0.20220616010729-4a0a888aebdc github.com/aykevl/go-wasm v0.0.2-0.20220616010729-4a0a888aebdc
@@ -9,11 +9,25 @@ require (
github.com/chromedp/chromedp v0.7.6 github.com/chromedp/chromedp v0.7.6
github.com/gofrs/flock v0.8.1 github.com/gofrs/flock v0.8.1
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
github.com/mattn/go-colorable v0.1.8 github.com/mattn/go-colorable v0.1.8
go.bug.st/serial v1.1.3 github.com/mattn/go-tty v0.0.4
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 go.bug.st/serial v1.3.5
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261
golang.org/x/tools v0.1.11 golang.org/x/tools v0.1.11
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
tinygo.org/x/go-llvm v0.0.0-20220626113704-45f1e2dbf887 tinygo.org/x/go-llvm v0.0.0-20220802112859-5bb0b77907a7
)
require (
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/creack/goselect v0.1.2 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
) )
+19 -34
View File
@@ -12,7 +12,6 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0= github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
@@ -23,61 +22,47 @@ github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg= github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s=
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw= github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M= github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc= github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= go.bug.st/serial v1.3.5 h1:k50SqGZCnHZ2MiBQgzccXWG+kd/XpOs1jUljpDDKzaE=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= go.bug.st/serial v1.3.5/go.mod h1:z8CesKorE90Qr/oRSJiEuvzYRKol9r/anJZEb5kt304=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.bug.st/serial v1.1.3 h1:YEBxJa9pKS9Wdg46B/jiaKbvvbUrjhZZZITfJHEJhaE=
go.bug.st/serial v1.1.3/go.mod h1:8TT7u/SwwNIpJ8QaG4s+HTjFt9ReXs2cdOU7ZEk50Dk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY= golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
tinygo.org/x/go-llvm v0.0.0-20220626113704-45f1e2dbf887 h1:k+Y1DU/WoBDkTkRJGF149yk3S2K2VhNglN435DXDS5s= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
tinygo.org/x/go-llvm v0.0.0-20220626113704-45f1e2dbf887/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0= tinygo.org/x/go-llvm v0.0.0-20220802112859-5bb0b77907a7 h1:nSLR52mUw7DPQQVA3ZJFH63zjU4ME84fKiin6mdnYWc=
tinygo.org/x/go-llvm v0.0.0-20220802112859-5bb0b77907a7/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
+9 -4
View File
@@ -6,6 +6,7 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"io/fs"
"os" "os"
"os/exec" "os/exec"
"os/user" "os/user"
@@ -41,10 +42,14 @@ var TINYGOROOT string
func Get(name string) string { func Get(name string) string {
switch name { switch name {
case "GOOS": case "GOOS":
if dir := os.Getenv("GOOS"); dir != "" { goos := os.Getenv("GOOS")
return dir if goos == "" {
goos = runtime.GOOS
} }
return runtime.GOOS if goos == "android" {
goos = "linux"
}
return goos
case "GOARCH": case "GOARCH":
if dir := os.Getenv("GOARCH"); dir != "" { if dir := os.Getenv("GOARCH"); dir != "" {
return dir return dir
@@ -122,7 +127,7 @@ func findWasmOpt() string {
} }
_, err := os.Stat(path) _, err := os.Stat(path)
if err != nil && os.IsNotExist(err) { if err != nil && errors.Is(err, fs.ErrNotExist) {
continue continue
} }
+4 -4
View File
@@ -4,7 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
@@ -12,7 +12,7 @@ import (
// Version of TinyGo. // Version of TinyGo.
// Update this value before release of new version of software. // Update this value before release of new version of software.
const Version = "0.25.0" const Version = "0.26.0-dev"
var ( var (
// This variable is set at build time using -ldflags parameters. // This variable is set at build time using -ldflags parameters.
@@ -54,10 +54,10 @@ func GetGorootVersion(goroot string) (major, minor int, err error) {
// toolchain for the given GOROOT path. It is usually of the form `go1.x.y` but // toolchain for the given GOROOT path. It is usually of the form `go1.x.y` but
// can have some variations (for beta releases, for example). // can have some variations (for beta releases, for example).
func GorootVersionString(goroot string) (string, error) { func GorootVersionString(goroot string) (string, error) {
if data, err := ioutil.ReadFile(filepath.Join(goroot, "VERSION")); err == nil { if data, err := os.ReadFile(filepath.Join(goroot, "VERSION")); err == nil {
return string(data), nil return string(data), nil
} else if data, err := ioutil.ReadFile(filepath.Join( } else if data, err := os.ReadFile(filepath.Join(
goroot, "src", "internal", "buildcfg", "zbootstrap.go")); err == nil { goroot, "src", "internal", "buildcfg", "zbootstrap.go")); err == nil {
r := regexp.MustCompile("const version = `(.*)`") r := regexp.MustCompile("const version = `(.*)`")
+7 -5
View File
@@ -30,10 +30,11 @@ type runner struct {
objects []object // slice of objects in memory objects []object // slice of objects in memory
globals map[llvm.Value]int // map from global to index in objects slice globals map[llvm.Value]int // map from global to index in objects slice
start time.Time start time.Time
timeout time.Duration
callsExecuted uint64 callsExecuted uint64
} }
func newRunner(mod llvm.Module, debug bool) *runner { func newRunner(mod llvm.Module, timeout time.Duration, debug bool) *runner {
r := runner{ r := runner{
mod: mod, mod: mod,
targetData: llvm.NewTargetData(mod.DataLayout()), targetData: llvm.NewTargetData(mod.DataLayout()),
@@ -42,6 +43,7 @@ func newRunner(mod llvm.Module, debug bool) *runner {
objects: []object{{}}, objects: []object{{}},
globals: make(map[llvm.Value]int), globals: make(map[llvm.Value]int),
start: time.Now(), start: time.Now(),
timeout: timeout,
} }
r.pointerSize = uint32(r.targetData.PointerSize()) r.pointerSize = uint32(r.targetData.PointerSize())
r.i8ptrType = llvm.PointerType(mod.Context().Int8Type(), 0) r.i8ptrType = llvm.PointerType(mod.Context().Int8Type(), 0)
@@ -58,8 +60,8 @@ func (r *runner) dispose() {
// Run evaluates runtime.initAll function as much as possible at compile time. // Run evaluates runtime.initAll function as much as possible at compile time.
// Set debug to true if it should print output while running. // Set debug to true if it should print output while running.
func Run(mod llvm.Module, debug bool) error { func Run(mod llvm.Module, timeout time.Duration, debug bool) error {
r := newRunner(mod, debug) r := newRunner(mod, timeout, debug)
defer r.dispose() defer r.dispose()
initAll := mod.NamedFunction("runtime.initAll") initAll := mod.NamedFunction("runtime.initAll")
@@ -199,10 +201,10 @@ func Run(mod llvm.Module, debug bool) error {
// RunFunc evaluates a single package initializer at compile time. // RunFunc evaluates a single package initializer at compile time.
// Set debug to true if it should print output while running. // Set debug to true if it should print output while running.
func RunFunc(fn llvm.Value, debug bool) error { func RunFunc(fn llvm.Value, timeout time.Duration, debug bool) error {
// Create and initialize *runner object. // Create and initialize *runner object.
mod := fn.GlobalParent() mod := fn.GlobalParent()
r := newRunner(mod, debug) r := newRunner(mod, timeout, debug)
defer r.dispose() defer r.dispose()
initName := fn.Name() initName := fn.Name()
if !strings.HasSuffix(initName, ".init") { if !strings.HasSuffix(initName, ".init") {
+3 -3
View File
@@ -1,11 +1,11 @@
package interp package interp
import ( import (
"io/ioutil"
"os" "os"
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
"time"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
@@ -53,7 +53,7 @@ func runTest(t *testing.T, pathPrefix string) {
defer mod.Dispose() defer mod.Dispose()
// Perform the transform. // Perform the transform.
err = Run(mod, false) err = Run(mod, 10*time.Minute, false)
if err != nil { if err != nil {
if err, match := err.(*Error); match { if err, match := err.(*Error); match {
println(err.Error()) println(err.Error())
@@ -87,7 +87,7 @@ func runTest(t *testing.T, pathPrefix string) {
pm.Run(mod) pm.Run(mod)
// Read the expected output IR. // Read the expected output IR.
out, err := ioutil.ReadFile(pathPrefix + ".out.ll") out, err := os.ReadFile(pathPrefix + ".out.ll")
if err != nil { if err != nil {
t.Fatalf("could not read output file %s: %v", pathPrefix+".out.ll", err) t.Fatalf("could not read output file %s: %v", pathPrefix+".out.ll", err)
} }
+8 -6
View File
@@ -17,8 +17,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
locals := make([]value, len(fn.locals)) locals := make([]value, len(fn.locals))
r.callsExecuted++ r.callsExecuted++
t0 := time.Since(r.start)
// Parameters are considered a kind of local values. // Parameters are considered a kind of local values.
for i, param := range params { for i, param := range params {
locals[i] = param locals[i] = param
@@ -143,11 +141,10 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
} }
switch inst.opcode { switch inst.opcode {
case llvm.Ret: case llvm.Ret:
const maxInterpSeconds = 180 if time.Since(r.start) > r.timeout {
if t0 > maxInterpSeconds*time.Second { // Running for more than the allowed timeout; This shouldn't happen, but it does.
// Running for more than maxInterpSeconds seconds. This should never happen, but does.
// See github.com/tinygo-org/tinygo/issues/2124 // See github.com/tinygo-org/tinygo/issues/2124
return nil, mem, r.errorAt(fn.blocks[0].instructions[0], fmt.Errorf("interp: running for more than %d seconds, timing out (executed calls: %d)", maxInterpSeconds, r.callsExecuted)) return nil, mem, r.errorAt(fn.blocks[0].instructions[0], fmt.Errorf("interp: running for more than %s, timing out (executed calls: %d)", r.timeout, r.callsExecuted))
} }
if len(operands) != 0 { if len(operands) != 0 {
@@ -372,6 +369,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
nBytes := uint32(operands[3].Uint()) nBytes := uint32(operands[3].Uint())
dstObj := mem.getWritable(dst.index()) dstObj := mem.getWritable(dst.index())
dstBuf := dstObj.buffer.asRawValue(r) dstBuf := dstObj.buffer.asRawValue(r)
if mem.get(src.index()).buffer == nil {
// Looks like the source buffer is not defined.
// This can happen with //extern or //go:embed.
return nil, mem, r.errorAt(inst, errUnsupportedRuntimeInst)
}
srcBuf := mem.get(src.index()).buffer.asRawValue(r) srcBuf := mem.get(src.index()).buffer.asRawValue(r)
copy(dstBuf.buf[dst.offset():dst.offset()+nBytes], srcBuf.buf[src.offset():]) copy(dstBuf.buf[dst.offset():dst.offset()+nBytes], srcBuf.buf[src.offset():])
dstObj.buffer = dstBuf dstObj.buffer = dstBuf
+13 -6
View File
@@ -17,6 +17,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
@@ -45,7 +46,7 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
} }
// Find the overrides needed for the goroot. // Find the overrides needed for the goroot.
overrides := pathsToOverride(needsSyscallPackage(config.BuildTags())) overrides := pathsToOverride(config.GoMinorVersion, needsSyscallPackage(config.BuildTags()))
// Resolve the merge links within the goroot. // Resolve the merge links within the goroot.
merge, err := listGorootMergeLinks(goroot, tinygoroot, overrides) merge, err := listGorootMergeLinks(goroot, tinygoroot, overrides)
@@ -83,7 +84,7 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
} }
// Create a temporary directory to construct the goroot within. // Create a temporary directory to construct the goroot within.
tmpgoroot, err := ioutil.TempDir(goenv.Get("GOCACHE"), cachedGorootName+".tmp") tmpgoroot, err := os.MkdirTemp(goenv.Get("GOCACHE"), cachedGorootName+".tmp")
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -122,13 +123,13 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
// Rename the new merged gorooot into place. // Rename the new merged gorooot into place.
err = os.Rename(tmpgoroot, cachedgoroot) err = os.Rename(tmpgoroot, cachedgoroot)
if err != nil { if err != nil {
if os.IsExist(err) { if errors.Is(err, fs.ErrExist) {
// Another invocation of TinyGo also seems to have created a GOROOT. // Another invocation of TinyGo also seems to have created a GOROOT.
// Use that one instead. Our new GOROOT will be automatically // Use that one instead. Our new GOROOT will be automatically
// deleted by the defer above. // deleted by the defer above.
return cachedgoroot, nil return cachedgoroot, nil
} }
if runtime.GOOS == "windows" && os.IsPermission(err) { if runtime.GOOS == "windows" && errors.Is(err, fs.ErrPermission) {
// On Windows, a rename with a destination directory that already // On Windows, a rename with a destination directory that already
// exists does not result in an IsExist error, but rather in an // exists does not result in an IsExist error, but rather in an
// access denied error. To be sure, check for this case by checking // access denied error. To be sure, check for this case by checking
@@ -222,7 +223,7 @@ func needsSyscallPackage(buildTags []string) bool {
// The boolean indicates whether to merge the subdirs. True means merge, false // The boolean indicates whether to merge the subdirs. True means merge, false
// means use the TinyGo version. // means use the TinyGo version.
func pathsToOverride(needsSyscallPackage bool) map[string]bool { func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
paths := map[string]bool{ paths := map[string]bool{
"": true, "": true,
"crypto/": true, "crypto/": true,
@@ -234,7 +235,6 @@ func pathsToOverride(needsSyscallPackage bool) map[string]bool {
"internal/bytealg/": false, "internal/bytealg/": false,
"internal/reflectlite/": false, "internal/reflectlite/": false,
"internal/task/": false, "internal/task/": false,
"internal/itoa/": false, // TODO: Remove when we drop support for go 1.16
"machine/": false, "machine/": false,
"net/": true, "net/": true,
"os/": true, "os/": true,
@@ -243,6 +243,13 @@ func pathsToOverride(needsSyscallPackage bool) map[string]bool {
"sync/": true, "sync/": true,
"testing/": true, "testing/": true,
} }
if goMinor >= 19 {
paths["crypto/internal/"] = true
paths["crypto/internal/boring/"] = true
paths["crypto/internal/boring/sig/"] = false
}
if needsSyscallPackage { if needsSyscallPackage {
paths["syscall/"] = true // include syscall/js paths["syscall/"] = true // include syscall/js
} }
+4 -9
View File
@@ -13,7 +13,6 @@ import (
"go/token" "go/token"
"go/types" "go/types"
"io" "io"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path" "path"
@@ -28,8 +27,6 @@ import (
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
) )
var addInstances func(*types.Info)
// Program holds all packages and some metadata about the program as a whole. // Program holds all packages and some metadata about the program as a whole.
type Program struct { type Program struct {
config *compileopts.Config config *compileopts.Config
@@ -159,6 +156,7 @@ func Load(config *compileopts.Config, inputPkg string, clangHeaders string, type
EmbedGlobals: make(map[string][]*EmbedFile), EmbedGlobals: make(map[string][]*EmbedFile),
info: types.Info{ info: types.Info{
Types: make(map[ast.Expr]types.TypeAndValue), Types: make(map[ast.Expr]types.TypeAndValue),
Instances: make(map[*ast.Ident]types.Instance),
Defs: make(map[*ast.Ident]types.Object), Defs: make(map[*ast.Ident]types.Object),
Uses: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object),
Implicits: make(map[ast.Node]types.Object), Implicits: make(map[ast.Node]types.Object),
@@ -166,9 +164,6 @@ func Load(config *compileopts.Config, inputPkg string, clangHeaders string, type
Selections: make(map[*ast.SelectorExpr]*types.Selection), Selections: make(map[*ast.SelectorExpr]*types.Selection),
}, },
} }
if addInstances != nil {
addInstances(&pkg.info)
}
err := decoder.Decode(&pkg.PackageJSON) err := decoder.Decode(&pkg.PackageJSON)
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {
@@ -269,7 +264,7 @@ func (p *Program) getOriginalPath(path string) string {
originalPath = realgorootPath originalPath = realgorootPath
} }
maybeInTinyGoRoot := false maybeInTinyGoRoot := false
for prefix := range pathsToOverride(needsSyscallPackage(p.config.BuildTags())) { for prefix := range pathsToOverride(p.config.GoMinorVersion, needsSyscallPackage(p.config.BuildTags())) {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
prefix = strings.ReplaceAll(prefix, "/", "\\") prefix = strings.ReplaceAll(prefix, "/", "\\")
} }
@@ -335,7 +330,7 @@ func (p *Package) OriginalDir() string {
// parseFile is a wrapper around parser.ParseFile. // parseFile is a wrapper around parser.ParseFile.
func (p *Package) parseFile(path string, mode parser.Mode) (*ast.File, error) { func (p *Package) parseFile(path string, mode parser.Mode) (*ast.File, error) {
originalPath := p.program.getOriginalPath(path) originalPath := p.program.getOriginalPath(path)
data, err := ioutil.ReadFile(path) data, err := os.ReadFile(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -445,7 +440,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
var initialCFlags []string var initialCFlags []string
initialCFlags = append(initialCFlags, p.program.config.CFlags()...) initialCFlags = append(initialCFlags, p.program.config.CFlags()...)
initialCFlags = append(initialCFlags, "-I"+p.Dir) initialCFlags = append(initialCFlags, "-I"+p.Dir)
generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.program.fset, initialCFlags, p.program.clangHeaders) generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.ImportPath, p.program.fset, initialCFlags, p.program.clangHeaders)
p.CFlags = append(initialCFlags, cflags...) p.CFlags = append(initialCFlags, cflags...)
p.CGoHeaders = headerCode p.CGoHeaders = headerCode
for path, hash := range accessedFiles { for path, hash := range accessedFiles {
-18
View File
@@ -1,18 +0,0 @@
//go:build go1.18
// +build go1.18
package loader
// Workaround for Go 1.17 support. Should be removed once we drop Go 1.17
// support.
import (
"go/ast"
"go/types"
)
func init() {
addInstances = func(info *types.Info) {
info.Instances = make(map[*ast.Ident]types.Instance)
}
}
+63 -30
View File
@@ -26,12 +26,14 @@ import (
"time" "time"
"github.com/google/shlex" "github.com/google/shlex"
"github.com/inhies/go-bytesize"
"github.com/mattn/go-colorable" "github.com/mattn/go-colorable"
"github.com/tinygo-org/tinygo/builder" "github.com/tinygo-org/tinygo/builder"
"github.com/tinygo-org/tinygo/compileopts" "github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
"github.com/tinygo-org/tinygo/interp" "github.com/tinygo-org/tinygo/interp"
"github.com/tinygo-org/tinygo/loader" "github.com/tinygo-org/tinygo/loader"
"golang.org/x/tools/go/buildutil"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
"go.bug.st/serial" "go.bug.st/serial"
@@ -194,7 +196,7 @@ func Build(pkgName, outpath string, options *compileopts.Options) error {
// Test runs the tests in the given package. Returns whether the test passed and // Test runs the tests in the given package. Returns whether the test passed and
// possibly an error if the test failed to run. // possibly an error if the test failed to run.
func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options, testCompileOnly, testVerbose, testShort bool, testRunRegexp string, testBenchRegexp string, testBenchTime string, outpath string) (bool, error) { func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options, testCompileOnly, testVerbose, testShort bool, testRunRegexp string, testBenchRegexp string, testBenchTime string, testBenchMem bool, outpath string) (bool, error) {
options.TestConfig.CompileTestBinary = true options.TestConfig.CompileTestBinary = true
config, err := builder.NewConfig(options) config, err := builder.NewConfig(options)
if err != nil { if err != nil {
@@ -218,6 +220,9 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
if testBenchTime != "" { if testBenchTime != "" {
flags = append(flags, "-test.benchtime="+testBenchTime) flags = append(flags, "-test.benchtime="+testBenchTime)
} }
if testBenchMem {
flags = append(flags, "-test.benchmem")
}
passed := false passed := false
err = buildAndRun(pkgName, config, os.Stdout, flags, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error { err = buildAndRun(pkgName, config, os.Stdout, flags, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error {
@@ -239,18 +244,37 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
// Tests are always run in the package directory. // Tests are always run in the package directory.
cmd.Dir = result.MainDir cmd.Dir = result.MainDir
// Wasmtime needs a few extra flags to work. // wasmtime is the default emulator used for `-target=wasi`. wasmtime
// is a WebAssembly runtime CLI with WASI enabled by default. However,
// only stdio are allowed by default. For example, while STDOUT routes
// to the host, other files don't. It also does not inherit environment
// variables from the host. Some tests read testdata files, often from
// outside the package directory. Other tests require temporary
// writeable directories. We allow this by adding wasmtime flags below.
if config.EmulatorName() == "wasmtime" { if config.EmulatorName() == "wasmtime" {
// Add directories to the module root, but skip the current working // At this point, The current working directory is at the package
// directory which is already added by buildAndRun. // directory. Ex. $GOROOT/src/compress/flate for compress/flate.
// buildAndRun has already added arguments for wasmtime, that allow
// read-access to files such as "testdata/huffman-zero.in".
//
// Ex. main(.wasm) --dir=. -- -test.v
// Below adds additional wasmtime flags in case a test reads files
// outside its directory, like "../testdata/e.txt". This allows any
// relative directory up to the module root, even if the test never
// reads any files.
//
// Ex. --dir=.. --dir=../.. --dir=../../..
dirs := dirsToModuleRoot(result.MainDir, result.ModuleRoot) dirs := dirsToModuleRoot(result.MainDir, result.ModuleRoot)
var args []string var args []string
for _, d := range dirs[1:] { for _, d := range dirs[1:] {
args = append(args, "--dir="+d) args = append(args, "--dir="+d)
} }
// create a new temp directory just for this run, announce it to os.TempDir() via TMPDIR // Some tests create temp directories using os.MkdirTemp or via
tmpdir, err := ioutil.TempDir("", "tinygotmp") // t.TempDir(). Create a writeable directory and map it to the
// default tempDir environment variable: TMPDIR.
tmpdir, err := os.MkdirTemp("", "tinygotmp")
if err != nil { if err != nil {
return fmt.Errorf("failed to create temporary directory: %w", err) return fmt.Errorf("failed to create temporary directory: %w", err)
} }
@@ -258,7 +282,8 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
// TODO: add option to not delete temp dir for debugging? // TODO: add option to not delete temp dir for debugging?
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
// Insert new argments at the front of the command line argments. // The below re-organizes the arguments so that the current
// directory is added last.
args = append(args, cmd.Args[1:]...) args = append(args, cmd.Args[1:]...)
cmd.Args = append(cmd.Args[:1:1], args...) cmd.Args = append(cmd.Args[:1:1], args...)
} }
@@ -398,7 +423,6 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
if err != nil { if err != nil {
return &commandError{"failed to flash", result.Binary, err} return &commandError{"failed to flash", result.Binary, err}
} }
return nil
case "msd": case "msd":
switch fileExt { switch fileExt {
case ".uf2": case ".uf2":
@@ -406,13 +430,11 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
if err != nil { if err != nil {
return &commandError{"failed to flash", result.Binary, err} return &commandError{"failed to flash", result.Binary, err}
} }
return nil
case ".hex": case ".hex":
err := flashHexUsingMSD(config.Target.FlashVolume, result.Binary, config.Options) err := flashHexUsingMSD(config.Target.FlashVolume, result.Binary, config.Options)
if err != nil { if err != nil {
return &commandError{"failed to flash", result.Binary, err} return &commandError{"failed to flash", result.Binary, err}
} }
return nil
default: default:
return errors.New("mass storage device flashing currently only supports uf2 and hex") return errors.New("mass storage device flashing currently only supports uf2 and hex")
} }
@@ -433,7 +455,6 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
if err != nil { if err != nil {
return &commandError{"failed to flash", result.Binary, err} return &commandError{"failed to flash", result.Binary, err}
} }
return nil
case "bmp": case "bmp":
gdb, err := config.Target.LookupGDB() gdb, err := config.Target.LookupGDB()
if err != nil { if err != nil {
@@ -452,10 +473,13 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
if err != nil { if err != nil {
return &commandError{"failed to flash", result.Binary, err} return &commandError{"failed to flash", result.Binary, err}
} }
return nil
default: default:
return fmt.Errorf("unknown flash method: %s", flashMethod) return fmt.Errorf("unknown flash method: %s", flashMethod)
} }
if options.Monitor {
return Monitor("", options)
}
return nil
}) })
} }
@@ -1015,18 +1039,6 @@ func getDefaultPort(portFlag string, usbInterfaces []string) (port string, err e
// available in the system. // available in the system.
ports = secondaryPorts ports = secondaryPorts
} }
if len(ports) == 0 {
// fallback
switch runtime.GOOS {
case "darwin":
ports, err = filepath.Glob("/dev/cu.usb*")
case "linux":
ports, err = filepath.Glob("/dev/ttyACM*")
case "windows":
ports, err = serial.GetPortsList()
}
}
default: default:
return "", errors.New("unable to search for a default USB device to be flashed on this OS") return "", errors.New("unable to search for a default USB device to be flashed on this OS")
} }
@@ -1040,7 +1052,9 @@ func getDefaultPort(portFlag string, usbInterfaces []string) (port string, err e
} }
if len(portCandidates) == 0 { if len(portCandidates) == 0 {
if len(ports) == 1 { if len(usbInterfaces) > 0 {
return "", errors.New("unable to search for a default USB device - use -port flag, available ports are " + strings.Join(ports, ", "))
} else if len(ports) == 1 {
return ports[0], nil return ports[0], nil
} else { } else {
return "", errors.New("multiple serial ports available - use -port flag, available ports are " + strings.Join(ports, ", ")) return "", errors.New("multiple serial ports available - use -port flag, available ports are " + strings.Join(ports, ", "))
@@ -1105,6 +1119,7 @@ func usage(command string) {
fmt.Fprintln(os.Stderr, " flash: compile and flash to the device") fmt.Fprintln(os.Stderr, " flash: compile and flash to the device")
fmt.Fprintln(os.Stderr, " gdb: run/flash and immediately enter GDB") fmt.Fprintln(os.Stderr, " gdb: run/flash and immediately enter GDB")
fmt.Fprintln(os.Stderr, " lldb: run/flash and immediately enter LLDB") fmt.Fprintln(os.Stderr, " lldb: run/flash and immediately enter LLDB")
fmt.Fprintln(os.Stderr, " monitor: open communication port")
fmt.Fprintln(os.Stderr, " env: list environment variables used during build") fmt.Fprintln(os.Stderr, " env: list environment variables used during build")
fmt.Fprintln(os.Stderr, " list: run go list using the TinyGo root") fmt.Fprintln(os.Stderr, " list: run go list using the TinyGo root")
fmt.Fprintln(os.Stderr, " clean: empty cache directory ("+goenv.Get("GOCACHE")+")") fmt.Fprintln(os.Stderr, " clean: empty cache directory ("+goenv.Get("GOCACHE")+")")
@@ -1294,11 +1309,19 @@ func main() {
scheduler := flag.String("scheduler", "", "which scheduler to use (none, tasks, asyncify)") scheduler := flag.String("scheduler", "", "which scheduler to use (none, tasks, asyncify)")
serial := flag.String("serial", "", "which serial output to use (none, uart, usb)") serial := flag.String("serial", "", "which serial output to use (none, uart, usb)")
work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit") work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit")
interpTimeout := flag.Duration("interp-timeout", 180*time.Second, "interp optimization pass timeout")
printIR := flag.Bool("printir", false, "print LLVM IR") printIR := flag.Bool("printir", false, "print LLVM IR")
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA") dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR") verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR")
tags := flag.String("tags", "", "a space-separated list of extra build tags") var tags buildutil.TagsFlag
flag.Var(&tags, "tags", "a space-separated list of extra build tags")
target := flag.String("target", "", "chip/board name or JSON target specification file") target := flag.String("target", "", "chip/board name or JSON target specification file")
var stackSize uint64
flag.Func("stack-size", "goroutine stack size (if unknown at compile time)", func(s string) error {
size, err := bytesize.Parse(s)
stackSize = uint64(size)
return err
})
printSize := flag.String("size", "", "print sizes (none, short, full)") printSize := flag.String("size", "", "print sizes (none, short, full)")
printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines") printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines")
printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed") printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed")
@@ -1313,6 +1336,8 @@ func main() {
wasmAbi := flag.String("wasm-abi", "", "WebAssembly ABI conventions: js (no i64 params) or generic") wasmAbi := flag.String("wasm-abi", "", "WebAssembly ABI conventions: js (no i64 params) or generic")
llvmFeatures := flag.String("llvm-features", "", "comma separated LLVM features to enable") llvmFeatures := flag.String("llvm-features", "", "comma separated LLVM features to enable")
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output") cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
monitor := flag.Bool("monitor", false, "enable serial monitor")
baudrate := flag.Int("baudrate", 115200, "baudrate of serial monitor")
var flagJSON, flagDeps, flagTest bool var flagJSON, flagDeps, flagTest bool
if command == "help" || command == "list" || command == "info" || command == "build" { if command == "help" || command == "list" || command == "info" || command == "build" {
@@ -1330,6 +1355,7 @@ func main() {
var testBenchRegexp *string var testBenchRegexp *string
var testBenchTime *string var testBenchTime *string
var testRunRegexp *string var testRunRegexp *string
var testBenchMem *bool
if command == "help" || command == "test" { if command == "help" || command == "test" {
testCompileOnlyFlag = flag.Bool("c", false, "compile the test binary but do not run it") testCompileOnlyFlag = flag.Bool("c", false, "compile the test binary but do not run it")
testVerboseFlag = flag.Bool("v", false, "verbose: print additional output") testVerboseFlag = flag.Bool("v", false, "verbose: print additional output")
@@ -1337,6 +1363,7 @@ func main() {
testRunRegexp = flag.String("run", "", "run: regexp of tests to run") testRunRegexp = flag.String("run", "", "run: regexp of tests to run")
testBenchRegexp = flag.String("bench", "", "run: regexp of benchmarks to run") testBenchRegexp = flag.String("bench", "", "run: regexp of benchmarks to run")
testBenchTime = flag.String("benchtime", "", "run each benchmark for duration `d`") testBenchTime = flag.String("benchtime", "", "run each benchmark for duration `d`")
testBenchMem = flag.Bool("benchmem", false, "show memory stats for benchmarks")
} }
// Early command processing, before commands are interpreted by the Go flag // Early command processing, before commands are interpreted by the Go flag
@@ -1377,12 +1404,14 @@ func main() {
GOARCH: goenv.Get("GOARCH"), GOARCH: goenv.Get("GOARCH"),
GOARM: goenv.Get("GOARM"), GOARM: goenv.Get("GOARM"),
Target: *target, Target: *target,
StackSize: stackSize,
Opt: *opt, Opt: *opt,
GC: *gc, GC: *gc,
PanicStrategy: *panicStrategy, PanicStrategy: *panicStrategy,
Scheduler: *scheduler, Scheduler: *scheduler,
Serial: *serial, Serial: *serial,
Work: *work, Work: *work,
InterpTimeout: *interpTimeout,
PrintIR: *printIR, PrintIR: *printIR,
DumpSSA: *dumpSSA, DumpSSA: *dumpSSA,
VerifyIR: *verifyIR, VerifyIR: *verifyIR,
@@ -1391,13 +1420,15 @@ func main() {
PrintSizes: *printSize, PrintSizes: *printSize,
PrintStacks: *printStacks, PrintStacks: *printStacks,
PrintAllocs: printAllocs, PrintAllocs: printAllocs,
Tags: *tags, Tags: []string(tags),
GlobalValues: globalVarValues, GlobalValues: globalVarValues,
WasmAbi: *wasmAbi, WasmAbi: *wasmAbi,
Programmer: *programmer, Programmer: *programmer,
OpenOCDCommands: ocdCommands, OpenOCDCommands: ocdCommands,
LLVMFeatures: *llvmFeatures, LLVMFeatures: *llvmFeatures,
PrintJSON: flagJSON, PrintJSON: flagJSON,
Monitor: *monitor,
BaudRate: *baudrate,
} }
if *printCommands { if *printCommands {
options.PrintCommands = printCommand options.PrintCommands = printCommand
@@ -1465,7 +1496,7 @@ func main() {
fmt.Fprintf(os.Stderr, "Unknown library: %s\n", name) fmt.Fprintf(os.Stderr, "Unknown library: %s\n", name)
os.Exit(1) os.Exit(1)
} }
tmpdir, err := ioutil.TempDir("", "tinygo*") tmpdir, err := os.MkdirTemp("", "tinygo*")
if err != nil { if err != nil {
handleCompilerError(err) handleCompilerError(err)
} }
@@ -1566,7 +1597,7 @@ func main() {
defer close(buf.done) defer close(buf.done)
stdout := (*testStdout)(buf) stdout := (*testStdout)(buf)
stderr := (*testStderr)(buf) stderr := (*testStderr)(buf)
passed, err := Test(pkgName, stdout, stderr, options, *testCompileOnlyFlag, *testVerboseFlag, *testShortFlag, *testRunRegexp, *testBenchRegexp, *testBenchTime, outpath) passed, err := Test(pkgName, stdout, stderr, options, *testCompileOnlyFlag, *testVerboseFlag, *testShortFlag, *testRunRegexp, *testBenchRegexp, *testBenchTime, *testBenchMem, outpath)
if err != nil { if err != nil {
printCompilerError(func(args ...interface{}) { printCompilerError(func(args ...interface{}) {
fmt.Fprintln(stderr, args...) fmt.Fprintln(stderr, args...)
@@ -1588,6 +1619,9 @@ func main() {
fmt.Println("FAIL") fmt.Println("FAIL")
os.Exit(1) os.Exit(1)
} }
case "monitor":
err := Monitor(*port, options)
handleCompilerError(err)
case "targets": case "targets":
dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets") dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
entries, err := ioutil.ReadDir(dir) entries, err := ioutil.ReadDir(dir)
@@ -1666,7 +1700,6 @@ func main() {
fmt.Printf("LLVM triple: %s\n", config.Triple()) fmt.Printf("LLVM triple: %s\n", config.Triple())
fmt.Printf("GOOS: %s\n", config.GOOS()) fmt.Printf("GOOS: %s\n", config.GOOS())
fmt.Printf("GOARCH: %s\n", config.GOARCH()) fmt.Printf("GOARCH: %s\n", config.GOARCH())
fmt.Printf("GOARM: %s\n", config.GOARM())
fmt.Printf("build tags: %s\n", strings.Join(config.BuildTags(), " ")) fmt.Printf("build tags: %s\n", strings.Join(config.BuildTags(), " "))
fmt.Printf("garbage collector: %s\n", config.GC()) fmt.Printf("garbage collector: %s\n", config.GC())
fmt.Printf("scheduler: %s\n", config.Scheduler()) fmt.Printf("scheduler: %s\n", config.Scheduler())
+41 -36
View File
@@ -10,7 +10,6 @@ import (
"flag" "flag"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"reflect" "reflect"
@@ -52,6 +51,7 @@ func TestBuild(t *testing.T) {
"embed/", "embed/",
"float.go", "float.go",
"gc.go", "gc.go",
"generics.go",
"goroutines.go", "goroutines.go",
"init.go", "init.go",
"init_multi.go", "init_multi.go",
@@ -66,21 +66,10 @@ func TestBuild(t *testing.T) {
"stdlib.go", "stdlib.go",
"string.go", "string.go",
"structs.go", "structs.go",
"testing.go",
"timers.go",
"zeroalloc.go", "zeroalloc.go",
} }
_, minor, err := goenv.GetGorootVersion(goenv.Get("GOROOT"))
if err != nil {
t.Fatal("could not read version from GOROOT:", err)
}
if minor >= 17 {
tests = append(tests, "go1.17.go")
}
if minor >= 18 {
tests = append(tests, "generics.go")
tests = append(tests, "testing_go118.go")
} else {
tests = append(tests, "testing.go")
}
if *testTarget != "" { if *testTarget != "" {
// This makes it possible to run one specific test (instead of all), // This makes it possible to run one specific test (instead of all),
@@ -181,6 +170,14 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
} }
for _, name := range tests { for _, name := range tests {
if options.GOOS == "linux" && (options.GOARCH == "arm" || options.GOARCH == "386") {
switch name {
case "timers.go":
// Timer tests do not work because syscall.seek is implemented
// as Assembly in mainline Go and causes linker failure
continue
}
}
if options.Target == "simavr" { if options.Target == "simavr" {
// Not all tests are currently supported on AVR. // Not all tests are currently supported on AVR.
// Skip the ones that aren't. // Skip the ones that aren't.
@@ -193,7 +190,7 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
// Does not pass due to high mark false positive rate. // Does not pass due to high mark false positive rate.
continue continue
case "json.go", "stdlib.go", "testing.go", "testing_go118.go": case "json.go", "stdlib.go", "testing.go":
// Breaks interp. // Breaks interp.
continue continue
@@ -209,6 +206,11 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
// CGo does not work on AVR. // CGo does not work on AVR.
continue continue
case "timers.go":
// Doesn't compile:
// panic: compiler: could not store type code number inside interface type code
continue
default: default:
} }
} }
@@ -260,10 +262,11 @@ func emuCheck(t *testing.T, options compileopts.Options) {
t.Fatal("failed to load target spec:", err) t.Fatal("failed to load target spec:", err)
} }
if spec.Emulator != "" { if spec.Emulator != "" {
_, err := exec.LookPath(strings.SplitN(spec.Emulator, " ", 2)[0]) emulatorCommand := strings.SplitN(spec.Emulator, " ", 2)[0]
_, err := exec.LookPath(emulatorCommand)
if err != nil { if err != nil {
if errors.Is(err, exec.ErrNotFound) { if errors.Is(err, exec.ErrNotFound) {
t.Skipf("emulator not installed: %q", spec.Emulator[0]) t.Skipf("emulator not installed: %q", emulatorCommand)
} }
t.Errorf("searching for emulator: %v", err) t.Errorf("searching for emulator: %v", err)
@@ -275,14 +278,15 @@ func emuCheck(t *testing.T, options compileopts.Options) {
func optionsFromTarget(target string, sema chan struct{}) compileopts.Options { func optionsFromTarget(target string, sema chan struct{}) compileopts.Options {
return compileopts.Options{ return compileopts.Options{
// GOOS/GOARCH are only used if target == "" // GOOS/GOARCH are only used if target == ""
GOOS: goenv.Get("GOOS"), GOOS: goenv.Get("GOOS"),
GOARCH: goenv.Get("GOARCH"), GOARCH: goenv.Get("GOARCH"),
GOARM: goenv.Get("GOARM"), GOARM: goenv.Get("GOARM"),
Target: target, Target: target,
Semaphore: sema, Semaphore: sema,
Debug: true, InterpTimeout: 180 * time.Second,
VerifyIR: true, Debug: true,
Opt: "z", VerifyIR: true,
Opt: "z",
} }
} }
@@ -292,12 +296,13 @@ func optionsFromTarget(target string, sema chan struct{}) compileopts.Options {
func optionsFromOSARCH(osarch string, sema chan struct{}) compileopts.Options { func optionsFromOSARCH(osarch string, sema chan struct{}) compileopts.Options {
parts := strings.Split(osarch, "/") parts := strings.Split(osarch, "/")
options := compileopts.Options{ options := compileopts.Options{
GOOS: parts[0], GOOS: parts[0],
GOARCH: parts[1], GOARCH: parts[1],
Semaphore: sema, Semaphore: sema,
Debug: true, InterpTimeout: 180 * time.Second,
VerifyIR: true, Debug: true,
Opt: "z", VerifyIR: true,
Opt: "z",
} }
if options.GOARCH == "arm" { if options.GOARCH == "arm" {
options.GOARM = parts[2] options.GOARM = parts[2]
@@ -319,7 +324,7 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
if path[len(path)-1] == '/' { if path[len(path)-1] == '/' {
txtpath = path + "out.txt" txtpath = path + "out.txt"
} }
expected, err := ioutil.ReadFile(txtpath) expected, err := os.ReadFile(txtpath)
if err != nil { if err != nil {
t.Fatal("could not read expected output file:", err) t.Fatal("could not read expected output file:", err)
} }
@@ -430,7 +435,7 @@ func TestTest(t *testing.T) {
defer out.Close() defer out.Close()
opts := targ.opts opts := targ.opts
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/pass", out, out, &opts, false, false, false, "", "", "", "") passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/pass", out, out, &opts, false, false, false, "", "", "", false, "")
if err != nil { if err != nil {
t.Errorf("test error: %v", err) t.Errorf("test error: %v", err)
} }
@@ -451,7 +456,7 @@ func TestTest(t *testing.T) {
defer out.Close() defer out.Close()
opts := targ.opts opts := targ.opts
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/fail", out, out, &opts, false, false, false, "", "", "", "") passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/fail", out, out, &opts, false, false, false, "", "", "", false, "")
if err != nil { if err != nil {
t.Errorf("test error: %v", err) t.Errorf("test error: %v", err)
} }
@@ -478,7 +483,7 @@ func TestTest(t *testing.T) {
var output bytes.Buffer var output bytes.Buffer
opts := targ.opts opts := targ.opts
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/nothing", io.MultiWriter(&output, out), out, &opts, false, false, false, "", "", "", "") passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/nothing", io.MultiWriter(&output, out), out, &opts, false, false, false, "", "", "", false, "")
if err != nil { if err != nil {
t.Errorf("test error: %v", err) t.Errorf("test error: %v", err)
} }
@@ -502,7 +507,7 @@ func TestTest(t *testing.T) {
defer out.Close() defer out.Close()
opts := targ.opts opts := targ.opts
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/builderr", out, out, &opts, false, false, false, "", "", "", "") passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/builderr", out, out, &opts, false, false, false, "", "", "", false, "")
if err == nil { if err == nil {
t.Error("test did not error") t.Error("test did not error")
} }
+106
View File
@@ -0,0 +1,106 @@
package main
import (
"fmt"
"os"
"os/signal"
"time"
"github.com/mattn/go-tty"
"github.com/tinygo-org/tinygo/builder"
"github.com/tinygo-org/tinygo/compileopts"
"go.bug.st/serial"
)
// Monitor connects to the given port and reads/writes the serial port.
func Monitor(port string, options *compileopts.Options) error {
config, err := builder.NewConfig(options)
if err != nil {
return err
}
wait := 300
for i := 0; i <= wait; i++ {
port, err = getDefaultPort(port, config.Target.SerialPort)
if err != nil {
if i < wait {
time.Sleep(10 * time.Millisecond)
continue
}
return err
}
break
}
br := options.BaudRate
if br <= 0 {
br = 115200
}
wait = 300
var p serial.Port
for i := 0; i <= wait; i++ {
p, err = serial.Open(port, &serial.Mode{BaudRate: br})
if err != nil {
if i < wait {
time.Sleep(10 * time.Millisecond)
continue
}
return err
}
break
}
defer p.Close()
tty, err := tty.Open()
if err != nil {
return err
}
defer tty.Close()
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt)
defer signal.Stop(sig)
go func() {
<-sig
tty.Close()
os.Exit(0)
}()
fmt.Printf("Connected to %s. Press Ctrl-C to exit.\n", port)
errCh := make(chan error, 1)
go func() {
buf := make([]byte, 100*1024)
for {
n, err := p.Read(buf)
if err != nil {
errCh <- fmt.Errorf("read error: %w", err)
return
}
if n == 0 {
continue
}
fmt.Printf("%v", string(buf[:n]))
}
}()
go func() {
for {
r, err := tty.ReadRune()
if err != nil {
errCh <- err
return
}
if r == 0 {
continue
}
p.Write([]byte(string(r)))
}
}()
return <-errCh
}
@@ -0,0 +1,17 @@
// Package sig stubs crypto/internal/boring/sig
package sig
// BoringCrypto indicates that the BoringCrypto module is present.
func BoringCrypto() {
}
// FIPSOnly indicates that package crypto/tls/fipsonly is present.
func FIPSOnly() {
}
// StandardCrypto indicates that standard Go crypto is present.
func StandardCrypto() {
}
+1
View File
@@ -27,5 +27,6 @@ func (r *reader) Read(b []byte) (n int, err error) {
} }
// void arc4random_buf(void *buf, size_t buflen); // void arc4random_buf(void *buf, size_t buflen);
//
//export arc4random_buf //export arc4random_buf
func libc_arc4random_buf(buf unsafe.Pointer, buflen uint) func libc_arc4random_buf(buf unsafe.Pointer, buflen uint)
+2 -2
View File
@@ -1,5 +1,5 @@
//go:build stm32 || (sam && atsamd51) || (sam && atsame5x) //go:build nrf || stm32 || (sam && atsamd51) || (sam && atsame5x)
// +build stm32 sam,atsamd51 sam,atsame5x // +build nrf stm32 sam,atsamd51 sam,atsame5x
package rand package rand
+1
View File
@@ -38,5 +38,6 @@ func (r *reader) Read(b []byte) (n int, err error) {
// Cryptographically secure random number generator. // Cryptographically secure random number generator.
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/rand-s?view=msvc-170 // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/rand-s?view=msvc-170
// errno_t rand_s(unsigned int* randomValue); // errno_t rand_s(unsigned int* randomValue);
//
//export rand_s //export rand_s
func libc_rand_s(randomValue *uint32) int32 func libc_rand_s(randomValue *uint32) int32
+29 -29
View File
@@ -2,31 +2,31 @@
// //
// Original copyright: // Original copyright:
// //
// Copyright (c) 2009 - 2015 ARM LIMITED // Copyright (c) 2009 - 2015 ARM LIMITED
// //
// All rights reserved. // All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: // modification, are permitted provided that the following conditions are met:
// - Redistributions of source code must retain the above copyright // - Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer. // notice, this list of conditions and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright // - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the // notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution. // documentation and/or other materials provided with the distribution.
// - Neither the name of ARM nor the names of its contributors may be used // - Neither the name of ARM nor the names of its contributors may be used
// to endorse or promote products derived from this software without // to endorse or promote products derived from this software without
// specific prior written permission. // specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE // ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE. // POSSIBILITY OF SUCH DAMAGE.
package arm package arm
import ( import (
@@ -46,12 +46,12 @@ func Asm(asm string)
// effects, as it would otherwise be optimized away. The inline assembly string // effects, as it would otherwise be optimized away. The inline assembly string
// recognizes template values in the form {name}, like so: // recognizes template values in the form {name}, like so:
// //
// arm.AsmFull( // arm.AsmFull(
// "str {value}, {result}", // "str {value}, {result}",
// map[string]interface{}{ // map[string]interface{}{
// "value": 1 // "value": 1
// "result": &dest, // "result": &dest,
// }) // })
// //
// You can use {} in the asm string (which expands to a register) to set the // You can use {} in the asm string (which expands to a register) to set the
// return value. // return value.
+1
View File
@@ -60,5 +60,6 @@ const (
// Call a semihosting function. // Call a semihosting function.
// TODO: implement it here using inline assembly. // TODO: implement it here using inline assembly.
//
//go:linkname SemihostingCall SemihostingCall //go:linkname SemihostingCall SemihostingCall
func SemihostingCall(num int, arg uintptr) int func SemihostingCall(num int, arg uintptr) int
+6 -6
View File
@@ -9,12 +9,12 @@ func Asm(asm string)
// effects, as it would otherwise be optimized away. The inline assembly string // effects, as it would otherwise be optimized away. The inline assembly string
// recognizes template values in the form {name}, like so: // recognizes template values in the form {name}, like so:
// //
// arm.AsmFull( // arm.AsmFull(
// "str {value}, {result}", // "str {value}, {result}",
// map[string]interface{}{ // map[string]interface{}{
// "value": 1 // "value": 1
// "result": &dest, // "result": &dest,
// }) // })
// //
// You can use {} in the asm string (which expands to a register) to set the // You can use {} in the asm string (which expands to a register) to set the
// return value. // return value.
+6 -6
View File
@@ -9,12 +9,12 @@ func Asm(asm string)
// effects, as it would otherwise be optimized away. The inline assembly string // effects, as it would otherwise be optimized away. The inline assembly string
// recognizes template values in the form {name}, like so: // recognizes template values in the form {name}, like so:
// //
// arm.AsmFull( // arm.AsmFull(
// "str {value}, {result}", // "str {value}, {result}",
// map[string]interface{}{ // map[string]interface{}{
// "value": 1 // "value": 1
// "result": &dest, // "result": &dest,
// }) // })
// //
// You can use {} in the asm string (which expands to a register) to set the // You can use {} in the asm string (which expands to a register) to set the
// return value. // return value.
+6 -6
View File
@@ -9,12 +9,12 @@ func Asm(asm string)
// effects, as it would otherwise be optimized away. The inline assembly string // effects, as it would otherwise be optimized away. The inline assembly string
// recognizes template values in the form {name}, like so: // recognizes template values in the form {name}, like so:
// //
// avr.AsmFull( // avr.AsmFull(
// "str {value}, {result}", // "str {value}, {result}",
// map[string]interface{}{ // map[string]interface{}{
// "value": 1 // "value": 1
// "result": &dest, // "result": &dest,
// }) // })
// //
// You can use {} in the asm string (which expands to a register) to set the // You can use {} in the asm string (which expands to a register) to set the
// return value. // return value.
+6 -6
View File
@@ -9,12 +9,12 @@ func Asm(asm string)
// effects, as it would otherwise be optimized away. The inline assembly string // effects, as it would otherwise be optimized away. The inline assembly string
// recognizes template values in the form {name}, like so: // recognizes template values in the form {name}, like so:
// //
// arm.AsmFull( // arm.AsmFull(
// "st {value}, {result}", // "st {value}, {result}",
// map[string]interface{}{ // map[string]interface{}{
// "value": 1 // "value": 1
// "result": &dest, // "result": &dest,
// }) // })
// //
// You can use {} in the asm string (which expands to a register) to set the // You can use {} in the asm string (which expands to a register) to set the
// return value. // return value.
-49
View File
@@ -1,49 +0,0 @@
// Reads multiple rp2040 ADC channels concurrently. Including the internal temperature sensor
package main
import (
"fmt"
"machine"
"time"
)
type celsius float32
func (c celsius) String() string {
return fmt.Sprintf("%4.1f℃", c)
}
// rp2040 ADC is 12 bits. Reading are shifted <<4 to fill the 16-bit range.
var adcReading [3]uint16
func readADC(a machine.ADC, w time.Duration, i int) {
for {
adcReading[i] = a.Get()
time.Sleep(w)
}
}
func main() {
machine.InitADC()
a0 := machine.ADC{machine.ADC0} // GPIO26 input
a1 := machine.ADC{machine.ADC1} // GPIO27 input
a2 := machine.ADC{machine.ADC2} // GPIO28 input
t := machine.ADC_TEMP_SENSOR // Internal Temperature sensor
// Configure sets the GPIOs to PinAnalog mode
a0.Configure(machine.ADCConfig{})
a1.Configure(machine.ADCConfig{})
a2.Configure(machine.ADCConfig{})
// Configure powers on the temperature sensor
t.Configure(machine.ADCConfig{})
// Safe to read concurrently
go readADC(a0, 10*time.Millisecond, 0)
go readADC(a1, 17*time.Millisecond, 1)
go readADC(a2, 29*time.Millisecond, 2)
for {
fmt.Printf("ADC0: %5d ADC1: %5d ADC2: %5d Temp: %v\n\r", adcReading[0], adcReading[1], adcReading[2], celsius(float32(t.ReadTemperature())/1000))
time.Sleep(1000 * time.Millisecond)
}
}
-1
View File
@@ -1,6 +1,5 @@
// Example using the i2s hardware interface on the Adafruit Circuit Playground Express // Example using the i2s hardware interface on the Adafruit Circuit Playground Express
// to read data from the onboard MEMS microphone. // to read data from the onboard MEMS microphone.
//
package main package main
import ( import (
+23
View File
@@ -0,0 +1,23 @@
// Read the internal temperature sensor of the chip.
package main
import (
"fmt"
"machine"
"time"
)
type celsius float32
func (c celsius) String() string {
return fmt.Sprintf("%4.1f℃", c)
}
func main() {
for {
temp := celsius(float32(machine.ReadTemperature()) / 1000)
println("temperature:", temp.String())
time.Sleep(time.Second)
}
}
+1 -1
View File
@@ -24,7 +24,7 @@ main: clean wasm_exec
cp ./main/index.html ./html/ cp ./main/index.html ./html/
wasm_exec: wasm_exec:
cp ../../../targets/wasm_exec.js ./html/ cp `tinygo env TINYGOROOT`/targets/wasm_exec.js ./html/
clean: clean:
rm -rf ./html rm -rf ./html
+9 -11
View File
@@ -21,12 +21,14 @@ $ tinygo build -o ./wasm.wasm -target wasm ./main/main.go
This creates a `wasm.wasm` file, which we can load in JavaScript and execute in This creates a `wasm.wasm` file, which we can load in JavaScript and execute in
a browser. a browser.
This examples folder contains two examples that can be built using `make`: Next, choose which example you want to use:
* [callback](callback): Defines and configures callbacks in Wasm.
```bash * [export](export): Defines callbacks in Wasm, but configures them in JavaScript.
$ make export * [invoke](invoke): Invokes a function defined in JavaScript from Wasm.
``` * [main](main): Prints a message to the JavaScript console from Wasm.
* [slices](slices): Splits an Array defined in JavaScript from Wasm.
Let's say you chose [main](main), you'd build it like so:
```bash ```bash
$ make main $ make main
``` ```
@@ -42,12 +44,8 @@ Serving ./html on http://localhost:8080
Use your web browser to visit http://localhost:8080. Use your web browser to visit http://localhost:8080.
* The wasm "export" example displays a simple math equation using HTML, with * Tip: Open the browser development tools (e.g. Right-click, Inspect in
the result calculated dynamically using WebAssembly. Changing any of the FireFox) to see console output.
values on the left hand side triggers the exported wasm `update` function to
recalculate the result.
* The wasm "main" example uses `println` to write to your browser JavaScript
console. You may need to open the browser development tools console to see it.
## How it works ## How it works
+2
View File
@@ -8,10 +8,12 @@ import (
var a, b int var a, b int
func main() { func main() {
wait := make(chan struct{}, 0)
document := js.Global().Get("document") document := js.Global().Get("document")
document.Call("getElementById", "a").Set("oninput", updater(&a)) document.Call("getElementById", "a").Set("oninput", updater(&a))
document.Call("getElementById", "b").Set("oninput", updater(&b)) document.Call("getElementById", "b").Set("oninput", updater(&b))
update() update()
<-wait
} }
func updater(n *int) js.Func { func updater(n *int) js.Func {
-2
View File
@@ -1,2 +0,0 @@
internal/itoa is new to go as of 1.17.
This directory should be removed when tinygo drops support for go 1.16.
-33
View File
@@ -1,33 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Simple conversions to avoid depending on strconv.
package itoa
// Itoa converts val to a decimal string.
func Itoa(val int) string {
if val < 0 {
return "-" + Uitoa(uint(-val))
}
return Uitoa(uint(val))
}
// Uitoa converts val to a decimal string.
func Uitoa(val uint) string {
if val == 0 { // avoid string allocation
return "0"
}
var buf [20]byte // big enough for 64bit value base 10
i := len(buf) - 1
for val >= 10 {
q := val / 10
buf[i] = byte('0' + val - q*10)
i--
val = q
}
// val < 10
buf[i] = byte('0' + val)
return string(buf[i:])
}
-40
View File
@@ -1,40 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package itoa_test
import (
"fmt"
"internal/itoa"
"math"
"testing"
)
var (
minInt64 int64 = math.MinInt64
maxInt64 int64 = math.MaxInt64
maxUint64 uint64 = math.MaxUint64
)
func TestItoa(t *testing.T) {
tests := []int{int(minInt64), math.MinInt32, -999, -100, -1, 0, 1, 100, 999, math.MaxInt32, int(maxInt64)}
for _, tt := range tests {
got := itoa.Itoa(tt)
want := fmt.Sprint(tt)
if want != got {
t.Fatalf("Itoa(%d) = %s, want %s", tt, got, want)
}
}
}
func TestUitoa(t *testing.T) {
tests := []uint{0, 1, 100, 999, math.MaxUint32, uint(maxUint64)}
for _, tt := range tests {
got := itoa.Uitoa(tt)
want := fmt.Sprint(tt)
if want != got {
t.Fatalf("Uitoa(%d) = %s, want %s", tt, got, want)
}
}
}
+4
View File
@@ -2,12 +2,16 @@
.functype start_unwind (i32) -> () .functype start_unwind (i32) -> ()
.import_module start_unwind, asyncify .import_module start_unwind, asyncify
.import_name start_unwind, start_unwind
.functype stop_unwind () -> () .functype stop_unwind () -> ()
.import_module stop_unwind, asyncify .import_module stop_unwind, asyncify
.import_name stop_unwind, stop_unwind
.functype start_rewind (i32) -> () .functype start_rewind (i32) -> ()
.import_module start_rewind, asyncify .import_module start_rewind, asyncify
.import_name start_rewind, start_rewind
.functype stop_rewind () -> () .functype stop_rewind () -> ()
.import_module stop_rewind, asyncify .import_module stop_rewind, asyncify
.import_name stop_rewind, stop_rewind
.global tinygo_unwind .global tinygo_unwind
.hidden tinygo_unwind .hidden tinygo_unwind
+1
View File
@@ -89,6 +89,7 @@ func swapTask(oldStack uintptr, newStack *uintptr)
// startTask is a small wrapper function that sets up the first (and only) // startTask is a small wrapper function that sets up the first (and only)
// argument to the new goroutine and makes sure it is exited when the goroutine // argument to the new goroutine and makes sure it is exited when the goroutine
// finishes. // finishes.
//
//go:extern tinygo_startTask //go:extern tinygo_startTask
var startTask [0]uint8 var startTask [0]uint8
+28 -2
View File
@@ -1,5 +1,8 @@
// Windows on amd64 has a slightly different ABI than other (*nix) systems. // Windows on amd64 has a slightly different ABI than other (*nix) systems.
// Therefore, assembly functions need to be tweaked slightly. // Therefore, assembly functions need to be tweaked slightly.
//
// The calling convention is described here:
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170
.section .text.tinygo_startTask,"ax" .section .text.tinygo_startTask,"ax"
.global tinygo_startTask .global tinygo_startTask
@@ -17,8 +20,9 @@ tinygo_startTask:
// Branch to the "goroutine start" function. // Branch to the "goroutine start" function.
callq *%r12 callq *%r12
// After return, exit this goroutine. This is a tail call. // After return, exit this goroutine.
jmp tinygo_pause // This has to be a call, not a jump, to keep the stack correctly aligned.
callq tinygo_pause
.global tinygo_swapTask .global tinygo_swapTask
.section .text.tinygo_swapTask,"ax" .section .text.tinygo_swapTask,"ax"
@@ -35,6 +39,17 @@ tinygo_swapTask:
pushq %rsi pushq %rsi
pushq %rdi pushq %rdi
pushq %rbp pushq %rbp
sub $160, %rsp
movaps %xmm6, 144(%rsp)
movaps %xmm7, 128(%rsp)
movaps %xmm8, 112(%rsp)
movaps %xmm9, 96(%rsp)
movaps %xmm10, 80(%rsp)
movaps %xmm11, 64(%rsp)
movaps %xmm12, 48(%rsp)
movaps %xmm13, 32(%rsp)
movaps %xmm14, 16(%rsp)
movaps %xmm15, 0(%rsp)
pushq %rbx pushq %rbx
// Save the current stack pointer in oldStack. // Save the current stack pointer in oldStack.
@@ -45,6 +60,17 @@ tinygo_swapTask:
// Load saved register from the new stack. // Load saved register from the new stack.
popq %rbx popq %rbx
movaps 0(%rsp), %xmm15
movaps 16(%rsp), %xmm14
movaps 32(%rsp), %xmm13
movaps 48(%rsp), %xmm12
movaps 64(%rsp), %xmm11
movaps 80(%rsp), %xmm10
movaps 96(%rsp), %xmm9
movaps 112(%rsp), %xmm8
movaps 128(%rsp), %xmm7
movaps 144(%rsp), %xmm6
add $160, %rsp
popq %rbp popq %rbp
popq %rdi popq %rdi
popq %rsi popq %rsi
+27 -8
View File
@@ -13,15 +13,34 @@ var systemStack uintptr
// calleeSavedRegs is the list of registers that must be saved and restored when // calleeSavedRegs is the list of registers that must be saved and restored when
// switching between tasks. Also see task_stack_amd64_windows.S that relies on // switching between tasks. Also see task_stack_amd64_windows.S that relies on
// the exact layout of this struct. // the exact layout of this struct.
// The calling convention is described here:
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170
// Most importantly, these are the registers we need to save/restore:
//
// > The x64 ABI considers registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14,
// > R15, and XMM6-XMM15 nonvolatile. They must be saved and restored by a
// > function that uses them.
type calleeSavedRegs struct { type calleeSavedRegs struct {
rbx uintptr // Note: rbx is placed here so that the stack is correctly aligned when
rbp uintptr // loading/storing the xmm registers.
rdi uintptr rbx uintptr
rsi uintptr xmm15 [2]uint64
r12 uintptr xmm14 [2]uint64
r13 uintptr xmm13 [2]uint64
r14 uintptr xmm12 [2]uint64
r15 uintptr xmm11 [2]uint64
xmm10 [2]uint64
xmm9 [2]uint64
xmm8 [2]uint64
xmm7 [2]uint64
xmm6 [2]uint64
rbp uintptr
rdi uintptr
rsi uintptr
r12 uintptr
r13 uintptr
r14 uintptr
r15 uintptr
pc uintptr pc uintptr
} }
+1
View File
@@ -29,6 +29,7 @@ type calleeSavedRegs struct {
// archInit runs architecture-specific setup for the goroutine startup. // archInit runs architecture-specific setup for the goroutine startup.
// Note: adding //go:noinline to work around an AVR backend bug. // Note: adding //go:noinline to work around an AVR backend bug.
//
//go:noinline //go:noinline
func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) { func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
// Store the initial sp for the startTask function (implemented in assembly). // Store the initial sp for the startTask function (implemented in assembly).
+1 -2
View File
@@ -4,11 +4,10 @@
// This contains the pin mappings for the Arduino MKR1000 board. // This contains the pin mappings for the Arduino MKR1000 board.
// //
// For more information, see: https://store.arduino.cc/usa/arduino-mkr1000-with-headers-mounted // For more information, see: https://store.arduino.cc/usa/arduino-mkr1000-with-headers-mounted
//
package machine package machine
// used to reset into bootloader // used to reset into bootloader
const RESET_MAGIC_VALUE = 0x07738135 const resetMagicValue = 0x07738135
// GPIO Pins // GPIO Pins
const ( const (
+1 -2
View File
@@ -4,11 +4,10 @@
// This contains the pin mappings for the Arduino MKR WiFi 1010 board. // This contains the pin mappings for the Arduino MKR WiFi 1010 board.
// //
// For more information, see: https://store.arduino.cc/usa/mkr-wifi-1010 // For more information, see: https://store.arduino.cc/usa/mkr-wifi-1010
//
package machine package machine
// used to reset into bootloader // used to reset into bootloader
const RESET_MAGIC_VALUE = 0x07738135 const resetMagicValue = 0x07738135
// GPIO Pins // GPIO Pins
const ( const (
+1 -2
View File
@@ -4,11 +4,10 @@
// This contains the pin mappings for the Arduino Nano33 IoT board. // This contains the pin mappings for the Arduino Nano33 IoT board.
// //
// For more information, see: https://store.arduino.cc/nano-33-iot // For more information, see: https://store.arduino.cc/nano-33-iot
//
package machine package machine
// used to reset into bootloader // used to reset into bootloader
const RESET_MAGIC_VALUE = 0x07738135 const resetMagicValue = 0x07738135
// GPIO Pins // GPIO Pins
const ( const (
+1 -1
View File
@@ -4,7 +4,7 @@
package machine package machine
// used to reset into bootloader // used to reset into bootloader
const RESET_MAGIC_VALUE = 0x07738135 const resetMagicValue = 0x07738135
// GPIO Pins - Digital Low // GPIO Pins - Digital Low
const ( const (
+6 -6
View File
@@ -12,9 +12,9 @@ const (
const ( const (
PB0 = portB + 0 PB0 = portB + 0
PB1 = portB + 1 PB1 = portB + 1 // peripherals: Timer1 channel A
PB2 = portB + 2 PB2 = portB + 2 // peripherals: Timer1 channel B
PB3 = portB + 3 PB3 = portB + 3 // peripherals: Timer2 channel A
PB4 = portB + 4 PB4 = portB + 4
PB5 = portB + 5 PB5 = portB + 5
PB6 = portB + 6 PB6 = portB + 6
@@ -30,9 +30,9 @@ const (
PD0 = portD + 0 PD0 = portD + 0
PD1 = portD + 1 PD1 = portD + 1
PD2 = portD + 2 PD2 = portD + 2
PD3 = portD + 3 PD3 = portD + 3 // peripherals: Timer2 channel B
PD4 = portD + 4 PD4 = portD + 4
PD5 = portD + 5 PD5 = portD + 5 // peripherals: Timer0 channel B
PD6 = portD + 6 PD6 = portD + 6 // peripherals: Timer0 channel A
PD7 = portD + 7 PD7 = portD + 7
) )
+34 -34
View File
@@ -10,38 +10,38 @@ func CPUFrequency() uint32 {
// Hardware pins // Hardware pins
const ( const (
PA00 Pin = 0 PA00 Pin = 0 // peripherals: TCC2 channel 0
PA01 Pin = 1 PA01 Pin = 1 // peripherals: TCC2 channel 1
PA02 Pin = 2 PA02 Pin = 2
PA03 Pin = 3 PA03 Pin = 3
PA04 Pin = 4 PA04 Pin = 4 // peripherals: TCC0 channel 0
PA05 Pin = 5 PA05 Pin = 5 // peripherals: TCC0 channel 1
PA06 Pin = 6 PA06 Pin = 6 // peripherals: TCC1 channel 0
PA07 Pin = 7 PA07 Pin = 7 // peripherals: TCC1 channel 1
PA08 Pin = 8 PA08 Pin = 8 // peripherals: TCC0 channel 0, TCC1 channel 2
PA09 Pin = 9 PA09 Pin = 9 // peripherals: TCC0 channel 1, TCC1 channel 3
PA10 Pin = 10 PA10 Pin = 10 // peripherals: TCC1 channel 0, TCC0 channel 2
PA11 Pin = 11 PA11 Pin = 11 // peripherals: TCC1 channel 1, TCC0 channel 3
PA12 Pin = 12 PA12 Pin = 12 // peripherals: TCC2 channel 0, TCC0 channel 2
PA13 Pin = 13 PA13 Pin = 13 // peripherals: TCC2 channel 1, TCC0 channel 3
PA14 Pin = 14 PA14 Pin = 14 // peripherals: TCC0 channel 0
PA15 Pin = 15 PA15 Pin = 15 // peripherals: TCC0 channel 1
PA16 Pin = 16 PA16 Pin = 16 // peripherals: TCC2 channel 0, TCC0 channel 2
PA17 Pin = 17 PA17 Pin = 17 // peripherals: TCC2 channel 1, TCC0 channel 3
PA18 Pin = 18 PA18 Pin = 18 // peripherals: TCC0 channel 2
PA19 Pin = 19 PA19 Pin = 19 // peripherals: TCC0 channel 3
PA20 Pin = 20 PA20 Pin = 20 // peripherals: TCC0 channel 2
PA21 Pin = 21 PA21 Pin = 21 // peripherals: TCC0 channel 3
PA22 Pin = 22 PA22 Pin = 22 // peripherals: TCC0 channel 0
PA23 Pin = 23 PA23 Pin = 23 // peripherals: TCC0 channel 1
PA24 Pin = 24 PA24 Pin = 24 // peripherals: TCC1 channel 2
PA25 Pin = 25 PA25 Pin = 25 // peripherals: TCC1 channel 3
PA26 Pin = 26 PA26 Pin = 26
PA27 Pin = 27 PA27 Pin = 27
PA28 Pin = 28 PA28 Pin = 28
PA29 Pin = 29 PA29 Pin = 29
PA30 Pin = 30 PA30 Pin = 30 // peripherals: TCC1 channel 0
PA31 Pin = 31 PA31 Pin = 31 // peripherals: TCC1 channel 1
PB00 Pin = 32 PB00 Pin = 32
PB01 Pin = 33 PB01 Pin = 33
PB02 Pin = 34 PB02 Pin = 34
@@ -52,14 +52,14 @@ const (
PB07 Pin = 39 PB07 Pin = 39
PB08 Pin = 40 PB08 Pin = 40
PB09 Pin = 41 PB09 Pin = 41
PB10 Pin = 42 PB10 Pin = 42 // peripherals: TCC0 channel 0
PB11 Pin = 43 PB11 Pin = 43 // peripherals: TCC0 channel 1
PB12 Pin = 44 PB12 Pin = 44 // peripherals: TCC0 channel 2
PB13 Pin = 45 PB13 Pin = 45 // peripherals: TCC0 channel 3
PB14 Pin = 46 PB14 Pin = 46
PB15 Pin = 47 PB15 Pin = 47
PB16 Pin = 48 PB16 Pin = 48 // peripherals: TCC0 channel 0
PB17 Pin = 49 PB17 Pin = 49 // peripherals: TCC0 channel 1
PB18 Pin = 50 PB18 Pin = 50
PB19 Pin = 51 PB19 Pin = 51
PB20 Pin = 52 PB20 Pin = 52
@@ -72,6 +72,6 @@ const (
PB27 Pin = 59 PB27 Pin = 59
PB28 Pin = 60 PB28 Pin = 60
PB29 Pin = 61 PB29 Pin = 61
PB30 Pin = 62 PB30 Pin = 62 // peripherals: TCC0 channel 0, TCC1 channel 2
PB31 Pin = 63 PB31 Pin = 63 // peripherals: TCC0 channel 1, TCC1 channel 3
) )

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