Compare commits

...

406 Commits

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

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

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

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

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

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

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

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

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

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

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

Makes 1.18 tests happier.

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

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

Works around this error:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Includes smoke test from upstream.

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

windows is hard, so leaving that for later.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Some notes on this commit:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

With this commit, it works just fine:

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

Supporting `-scheduler=none` has some benefits:

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

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

I've also changed the assert-test-linux job a bit to so that the tests
that are more likely to break and the tests that are only run in
assert-test-linux are run first.
2021-11-17 14:52:32 +01:00
677 changed files with 21154 additions and 7459 deletions
+9 -347
View File
@@ -6,36 +6,6 @@ commands:
- run:
name: "Pull submodules"
command: git submodule update --init
install-node:
steps:
- run:
name: "Install node.js"
command: |
wget https://nodejs.org/dist/v10.15.1/node-v10.15.1-linux-x64.tar.xz
sudo tar -C /usr/local -xf node-v10.15.1-linux-x64.tar.xz
sudo ln -s /usr/local/node-v10.15.1-linux-x64/bin/node /usr/bin/node
rm node-v10.15.1-linux-x64.tar.xz
install-chrome:
steps:
- run:
name: "Install Chrome"
command: |
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb
install-wasmtime:
steps:
- run:
name: "Install wasmtime"
command: |
curl https://wasmtime.dev/install.sh -sSf | bash
sudo ln -s ~/.wasmtime/bin/wasmtime /usr/local/bin/wasmtime
install-cmake:
steps:
- run:
name: "Install CMake"
command: |
wget https://github.com/Kitware/CMake/releases/download/v3.21.4/cmake-3.21.4-linux-x86_64.tar.gz
sudo tar --strip-components=1 -C /usr/local -xf cmake-3.21.4-linux-x86_64.tar.gz
install-xtensa-toolchain:
parameters:
variant:
@@ -52,15 +22,16 @@ commands:
steps:
- restore_cache:
keys:
- llvm-source-11-v2
- llvm-source-14-v1
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-11-v2
key: llvm-source-14-v1
paths:
- llvm-project/clang/lib/Headers
- llvm-project/clang/include
- llvm-project/compiler-rt
- llvm-project/lld/include
- llvm-project/llvm/include
hack-ninja-jobs:
@@ -83,31 +54,6 @@ commands:
key: binaryen-linux-v1
paths:
- build/wasm-opt
build-binaryen-linux-stretch:
steps:
- restore_cache:
keys:
- binaryen-linux-stretch-v1
- run:
name: "Build Binaryen"
command: |
CC=$PWD/llvm-build/bin/clang make binaryen
- save_cache:
key: binaryen-linux-stretch-v1
paths:
- build/wasm-opt
build-wasi-libc:
steps:
- restore_cache:
keys:
- wasi-libc-sysroot-v4
- run:
name: "Build wasi-libc"
command: make wasi-libc
- save_cache:
key: wasi-libc-sysroot-v4
paths:
- lib/wasi-libc/sysroot
test-linux:
parameters:
llvm:
@@ -140,10 +86,10 @@ commands:
- run: go install -tags=llvm<<parameters.llvm>> .
- restore_cache:
keys:
- wasi-libc-sysroot-systemclang-v3
- wasi-libc-sysroot-systemclang-v5
- run: make wasi-libc
- save_cache:
key: wasi-libc-sysroot-systemclang-v3
key: wasi-libc-sysroot-systemclang-v5
paths:
- lib/wasi-libc/sysroot
- run: make gen-device -j4
@@ -154,262 +100,6 @@ commands:
- ~/.cache/go-build
- /go/pkg/mod
- run: make fmt-check
assert-test-linux:
steps:
- checkout
- submodules
- run:
name: "Install apt dependencies"
command: |
sudo apt-get update
sudo apt-get install --no-install-recommends \
libgnutls30 libssl1.0.2 \
qemu-system-arm \
qemu-user \
gcc-avr \
avr-libc \
ninja-build \
python3
- install-node
- install-chrome
- install-wasmtime
- install-cmake
- hack-ninja-jobs
- install-xtensa-toolchain:
variant: "linux-amd64"
- restore_cache:
keys:
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-v2-{{ checksum "go.mod" }}
- llvm-source-linux
- restore_cache:
keys:
- llvm-build-11-linux-v4-assert
- run:
name: "Build LLVM"
command: |
if [ ! -f llvm-build/lib/liblldELF.a ]
then
# fetch LLVM source (may only have headers right now)
rm -rf llvm-project
make llvm-source
# build!
make ASSERT=1 llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
fi
- save_cache:
key: llvm-build-11-linux-v4-assert
paths:
llvm-build
- build-binaryen-linux-stretch
- run:
name: "Build TinyGo"
command: |
make ASSERT=1
echo 'export PATH=$(pwd)/build:$PATH' >> $BASH_ENV
- build-wasi-libc
- run:
name: "Test TinyGo"
command: make ASSERT=1 test
no_output_timeout: 20m
environment:
# Note: -p=2 limits parallelism to two jobs at a time, which is
# necessary to keep memory consumption down and avoid OOM (for a
# 2CPU/4GB executor).
GOFLAGS: -p=2
- save_cache:
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths:
- ~/.cache/go-build
- /go/pkg/mod
- run: make gen-device -j4
- run: make smoketest
- run: make tinygo-test
- run: make wasmtest
build-linux:
steps:
- checkout
- submodules
- run:
name: "Install apt dependencies"
command: |
sudo apt-get update
sudo apt-get install --no-install-recommends \
libgnutls30 libssl1.0.2 \
ninja-build \
python3
- install-cmake
- hack-ninja-jobs
- restore_cache:
keys:
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-v2-{{ checksum "go.mod" }}
- llvm-source-linux
- restore_cache:
keys:
- llvm-build-11-linux-v4-noassert
- run:
name: "Build LLVM"
command: |
if [ ! -f llvm-build/lib/liblldELF.a ]
then
# fetch LLVM source (may only have headers right now)
rm -rf llvm-project
make llvm-source
# build!
make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
fi
- save_cache:
key: llvm-build-11-linux-v4-noassert
paths:
llvm-build
- build-binaryen-linux-stretch
- build-wasi-libc
- run:
name: "Install fpm"
command: |
sudo apt-get install ruby ruby-dev
sudo gem install --no-document fpm
- run:
name: "Build TinyGo release"
command: |
make release deb -j3
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
cp -p build/release.deb /tmp/tinygo_amd64.deb
- persist_to_workspace:
root: /tmp
paths:
- tinygo.linux-amd64.tar.gz
- store_artifacts:
path: /tmp/tinygo.linux-amd64.tar.gz
- store_artifacts:
path: /tmp/tinygo_amd64.deb
- save_cache:
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths:
- ~/.cache/go-build
- /go/pkg/mod
test-linux-build:
# Now run the smoke tests for the generated binary.
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- run:
name: "Install apt dependencies"
command: |
sudo apt-get update
sudo apt-get install --no-install-recommends \
gcc-avr \
avr-libc
- install-xtensa-toolchain:
variant: "linux-amd64"
- run:
name: "Extract release tarball"
command: |
mkdir -p ~/lib
tar -C ~/lib -xf /tmp/workspace/tinygo.linux-amd64.tar.gz
ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo
tinygo version
- run: make smoketest
build-macos:
steps:
- checkout
- submodules
- run:
name: "Install dependencies"
command: |
curl https://dl.google.com/go/go1.17.darwin-amd64.tar.gz -o go1.17.darwin-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.17.darwin-amd64.tar.gz
ln -s /usr/local/go/bin/go /usr/local/bin/go
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu cmake ninja
- install-xtensa-toolchain:
variant: "macos"
- restore_cache:
keys:
- go-cache-macos-v3-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-macos-v3-{{ checksum "go.mod" }}
- restore_cache:
keys:
- llvm-source-11-macos-v3
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-11-macos-v3
paths:
- llvm-project/clang/lib/Headers
- llvm-project/clang/include
- llvm-project/lld/include
- llvm-project/llvm/include
- restore_cache:
keys:
- llvm-build-11-macos-v5
- run:
name: "Build LLVM"
command: |
if [ ! -f llvm-build/lib/liblldELF.a ]
then
# fetch LLVM source (may only have headers right now)
rm -rf llvm-project
make llvm-source
# build!
make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
fi
- save_cache:
key: llvm-build-11-macos-v5
paths:
llvm-build
- restore_cache:
keys:
- binaryen-macos-v1
- run:
name: "Build Binaryen"
command: |
if [ ! -f build/wasm-opt ]
then
make binaryen
fi
- save_cache:
key: binaryen-macos-v1
paths:
- build/wasm-opt
- restore_cache:
keys:
- wasi-libc-sysroot-macos-v4
- run:
name: "Build wasi-libc"
command: make wasi-libc
- save_cache:
key: wasi-libc-sysroot-macos-v4
paths:
- lib/wasi-libc/sysroot
- run:
name: "Test TinyGo"
command: make test
no_output_timeout: 20m
- run:
name: "Build TinyGo release"
command: |
make release -j3
cp -p build/release.tar.gz /tmp/tinygo.darwin-amd64.tar.gz
- store_artifacts:
path: /tmp/tinygo.darwin-amd64.tar.gz
- run:
name: "Extract release tarball"
command: |
mkdir -p ~/lib
tar -C /usr/local/opt -xf /tmp/tinygo.darwin-amd64.tar.gz
ln -s /usr/local/opt/tinygo/bin/tinygo /usr/local/bin/tinygo
tinygo version
- run: make smoketest AVR=0
- save_cache:
key: go-cache-macos-v3-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths:
- ~/.cache/go-build
- /go/pkg/mod
jobs:
test-llvm11-go115:
@@ -418,43 +108,15 @@ jobs:
steps:
- test-linux:
llvm: "11"
test-llvm11-go116:
test-llvm12-go117:
docker:
- image: circleci/golang:1.16-buster
- image: circleci/golang:1.17-buster
steps:
- test-linux:
llvm: "11"
assert-test-linux:
docker:
- image: circleci/golang:1.17-stretch
steps:
- assert-test-linux
build-linux:
docker:
- image: circleci/golang:1.17-stretch
steps:
- build-linux
test-linux-build:
docker:
- image: cimg/go:1.17
steps:
- test-linux-build
build-macos:
macos:
xcode: "11.1.0" # macOS 10.14
steps:
- build-macos
llvm: "12"
workflows:
test-all:
jobs:
- test-llvm11-go115
- test-llvm11-go116
- build-linux
- test-linux-build:
requires:
- build-linux
- build-macos
- assert-test-linux
- test-llvm12-go117
+98
View File
@@ -0,0 +1,98 @@
name: macOS
on:
pull_request:
push:
branches:
- dev
- release
jobs:
build-macos:
name: build-macos
runs-on: macos-11
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: '1.18.1'
- name: Install Dependencies
shell: bash
run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
- name: Install Xtensa toolchain
shell: bash
run: |
curl -L https://github.com/espressif/crosstool-NG/releases/download/esp-2020r2/xtensa-esp32-elf-gcc8_2_0-esp-2020r2-macos.tar.gz -o xtensa-esp32-elf-gcc8_2_0-esp-2020r2-macos.tar.gz
sudo tar -C /usr/local -xf xtensa-esp32-elf-gcc8_2_0-esp-2020r2-macos.tar.gz
sudo ln -s /usr/local/xtensa-esp32-elf/bin/xtensa-esp32-elf-ld /usr/local/bin/xtensa-esp32-elf-ld
rm xtensa-esp32-elf-gcc8_2_0-esp-2020r2-macos.tar.gz
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Cache LLVM source
uses: actions/cache@v2
id: cache-llvm-source
with:
key: llvm-source-14-macos-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Cache LLVM build
uses: actions/cache@v2
id: cache-llvm-build
with:
key: llvm-build-14-macos-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
shell: bash
run: |
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# install dependencies
HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake ninja
# build!
make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Cache wasi-libc sysroot
uses: actions/cache@v2
id: cache-wasi-libc
with:
key: wasi-libc-sysroot-v3
path: lib/wasi-libc/sysroot
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
- name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-v -short"
- name: Build TinyGo release tarball
run: make release -j3
- name: Test stdlib packages
run: make tinygo-test
- name: Make release artifact
shell: bash
run: cp -p build/release.tar.gz build/tinygo.darwin-amd64.tar.gz
- name: Publish release artifact
# Note: this release artifact is double-zipped, see:
# https://github.com/actions/upload-artifact/issues/39
# We can essentially pick one of these:
# - have a double-zipped artifact when downloaded from the UI
# - have a very slow artifact upload
# We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v2
with:
name: release-double-zipped
path: build/tinygo.darwin-amd64.tar.gz
- name: Smoke tests
shell: bash
run: make smoketest TINYGO=$(PWD)/build/tinygo AVR=0
@@ -1,45 +0,0 @@
name: CI for tinygo-dev docker container
on:
push:
branches: [ dev, fix-docker-llvm-build ]
jobs:
push_to_registry:
name: Push Docker image to GHCR/Docker Hub
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Check out the repo
uses: actions/checkout@v2
with:
submodules: recursive
- name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: |
tinygo/tinygo-dev
ghcr.io/${{ github.repository }}/tinygo-dev
tags: |
type=sha,format=long
type=raw,value=latest
- name: Log in to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
+83
View File
@@ -0,0 +1,83 @@
# This is the Github action to build and push the tinygo/tinygo-dev Docker image.
# If you are looking for the tinygo/tinygo "release" Docker image please see
# https://github.com/tinygo-org/docker
#
name: Docker
on:
push:
branches: [ dev, fix-docker-llvm-build ]
jobs:
push_to_registry:
name: build-push-dev
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Check out the repo
uses: actions/checkout@v2
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: |
tinygo/tinygo-dev
ghcr.io/${{ github.repository }}/tinygo-dev
tags: |
type=sha,format=long
type=raw,value=latest
- name: Log in to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Trigger Drivers repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/drivers/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
- name: Trigger Bluetooth repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/bluetooth/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
- name: Trigger TinyFS repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinyfs/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
- name: Trigger TinyFont repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinyfont/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
- name: Trigger TinyDraw repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinydraw/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
+348
View File
@@ -0,0 +1,348 @@
name: Linux
on:
pull_request:
push:
branches:
- dev
- release
jobs:
build-linux:
# Build Linux binaries, ready for release.
# This intentionally uses an older Linux image, so that we compile against
# an older glibc version and therefore are compatible with a wide range of
# Linux distributions.
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Install apt dependencies
run: |
sudo apt-get install --no-install-recommends \
ninja-build
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: '1.18.1'
- name: Cache Go
uses: actions/cache@v2
with:
key: go-cache-linux-v1-${{ hashFiles('go.mod') }}
path: |
~/.cache/go-build
~/go/pkg/mod
- name: Cache LLVM source
uses: actions/cache@v2
id: cache-llvm-source
with:
key: llvm-source-14-linux-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Cache LLVM build
uses: actions/cache@v2
id: cache-llvm-build
with:
key: llvm-build-14-linux-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
run: |
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# build!
make llvm-build
# Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Cache Binaryen
uses: actions/cache@v2
id: cache-binaryen
with:
key: binaryen-linux-v1
path: build/wasm-opt
- name: Build Binaryen
if: steps.cache-binaryen.outputs.cache-hit != 'true'
run: make binaryen
- name: Cache wasi-libc
uses: actions/cache@v2
id: cache-wasi-libc
with:
key: wasi-libc-sysroot-linux-asserts-v4
path: lib/wasi-libc/sysroot
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
- name: Install fpm
run: |
sudo gem install --no-document fpm
- name: Build TinyGo release
run: |
make release deb -j3
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
cp -p build/release.deb /tmp/tinygo_amd64.deb
- name: Publish release artifact
uses: actions/upload-artifact@v2
with:
name: linux-amd64-double-zipped
path: |
/tmp/tinygo.linux-amd64.tar.gz
/tmp/tinygo_amd64.deb
test-linux-build:
# Test the binaries built in the build-linux job by running the smoke tests.
runs-on: ubuntu-latest
needs: build-linux
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: '1.18.1'
- name: Install wasmtime
run: |
curl https://wasmtime.dev/install.sh -sSf | bash
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
- name: Download release artifact
uses: actions/download-artifact@v2
with:
name: linux-amd64-double-zipped
- name: Extract release tarball
run: |
mkdir -p ~/lib
tar -C ~/lib -xf tinygo.linux-amd64.tar.gz
ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo
- name: Install apt dependencies
run: |
sudo apt-get install --no-install-recommends \
gcc-avr \
avr-libc
- name: "Install Xtensa toolchain"
run: |
curl -L https://github.com/espressif/crosstool-NG/releases/download/esp-2020r2/xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz -o xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
sudo tar -C /usr/local -xf xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
sudo ln -s /usr/local/xtensa-esp32-elf/bin/xtensa-esp32-elf-ld /usr/local/bin/xtensa-esp32-elf-ld
rm xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
- run: make tinygo-test-wasi-fast
- run: make smoketest
assert-test-linux:
# Run all tests that can run on Linux, with LLVM assertions enabled to catch
# potential bugs.
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Install apt dependencies
run: |
echo "Show cpuinfo; sometimes useful when troubleshooting"
cat /proc/cpuinfo
sudo apt-get update
sudo apt-get install --no-install-recommends \
qemu-system-arm \
qemu-system-riscv32 \
qemu-user \
gcc-avr \
avr-libc \
simavr \
ninja-build
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: '1.18.1'
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: '12'
- name: Install wasmtime
run: |
curl https://wasmtime.dev/install.sh -sSf | bash
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
uses: actions/cache@v2
id: cache-llvm-source
with:
key: llvm-source-14-linux-asserts-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Cache LLVM build
uses: actions/cache@v2
id: cache-llvm-build
with:
key: llvm-build-14-linux-asserts-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
run: |
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# build!
make llvm-build ASSERT=1
# Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Cache Binaryen
uses: actions/cache@v2
id: cache-binaryen
with:
key: binaryen-linux-asserts-v1
path: build/wasm-opt
- name: Build Binaryen
if: steps.cache-binaryen.outputs.cache-hit != 'true'
run: make binaryen
- name: Cache wasi-libc
uses: actions/cache@v2
id: cache-wasi-libc
with:
key: wasi-libc-sysroot-linux-asserts-v4
path: lib/wasi-libc/sysroot
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
- run: make gen-device -j4
- name: Test TinyGo
run: make ASSERT=1 test
- name: Build TinyGo
run: |
make ASSERT=1
echo "$(pwd)/build" >> $GITHUB_PATH
- name: Test stdlib packages
run: make tinygo-test
- name: Install Xtensa toolchain
run: |
curl -L https://github.com/espressif/crosstool-NG/releases/download/esp-2020r2/xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz -o xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
sudo tar -C /usr/local -xf xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
sudo ln -s /usr/local/xtensa-esp32-elf/bin/xtensa-esp32-elf-ld /usr/local/bin/xtensa-esp32-elf-ld
rm xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
- run: make smoketest
- run: make wasmtest
- run: make tinygo-baremetal
build-linux-arm:
# Build ARM Linux binaries, ready for release.
# This intentionally uses an older Linux image, so that we compile against
# an older glibc version and therefore are compatible with a wide range of
# Linux distributions.
# It is set to "needs: build-linux" because it modifies the release created
# in that process to avoid doing lots of duplicate work and to avoid
# complications around precompiled libraries such as compiler-rt shipped as
# part of the release tarball.
runs-on: ubuntu-18.04
needs: build-linux
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install apt dependencies
run: |
sudo apt-get install --no-install-recommends \
qemu-user \
g++-arm-linux-gnueabihf \
libc6-dev-armhf-cross
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: '1.17'
- name: Cache Go
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
uses: actions/cache@v2
id: cache-llvm-source
with:
key: llvm-source-14-linux-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Cache LLVM build
uses: actions/cache@v2
id: cache-llvm-build
with:
key: llvm-build-14-linux-arm-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
run: |
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# Install build dependencies.
sudo apt-get install --no-install-recommends ninja-build
# build!
make llvm-build CROSS=arm-linux-gnueabihf
# Remove unnecessary object files (to reduce cache size).
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Cache Binaryen
uses: actions/cache@v2
id: cache-binaryen
with:
key: binaryen-linux-arm-v1
path: build/wasm-opt
- name: Build Binaryen
if: steps.cache-binaryen.outputs.cache-hit != 'true'
run: |
sudo apt-get install --no-install-recommends ninja-build
git submodule update --init lib/binaryen
make CROSS=arm-linux-gnueabihf binaryen
- name: Install fpm
run: |
sudo gem install --no-document fpm
- name: Build TinyGo binary
run: |
make CROSS=arm-linux-gnueabihf
- name: Download amd64 release
uses: actions/download-artifact@v2
with:
name: linux-amd64-double-zipped
- name: Extract amd64 release
run: |
mkdir -p build/release
tar -xf tinygo.linux-amd64.tar.gz -C build/release tinygo
- name: Modify release
run: |
cp -p build/tinygo build/release/tinygo/bin
cp -p build/wasm-opt build/release/tinygo/bin
- name: Create arm release
run: |
make release deb RELEASEONLY=1 DEB_ARCH=armhf
cp -p build/release.tar.gz /tmp/tinygo.linux-arm.tar.gz
cp -p build/release.deb /tmp/tinygo_armhf.deb
- name: Publish release artifact
uses: actions/upload-artifact@v2
with:
name: linux-arm-double-zipped
path: |
/tmp/tinygo.linux-arm.tar.gz
/tmp/tinygo_armhf.deb
+23 -23
View File
@@ -9,33 +9,37 @@ on:
jobs:
build-windows:
runs-on: windows-2019
runs-on: windows-2022
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: '1.17'
- name: Install QEMU
go-version: '1.18.1'
- uses: brechtm/setup-scoop@v2
- name: Install Dependencies
shell: bash
run: |
choco install qemu --version=2020.06.12
echo "C:\Program Files\QEMU" >> $GITHUB_PATH
- name: Install Ninja
shell: bash
run: |
choco install ninja
scoop install ninja binaryen
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Cache Go
uses: actions/cache@v2
with:
key: go-cache-windows-v1-${{ hashFiles('go.mod') }}
path: |
~/AppData/Local/go-build
~/go/pkg/mod
- name: Cache LLVM source
uses: actions/cache@v2
id: cache-llvm-source
with:
key: llvm-source-11-windows-v1
key: llvm-source-14-windows-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/compiler-rt
llvm-project/lld/include
llvm-project/llvm/include
- name: Download LLVM source
@@ -45,7 +49,7 @@ jobs:
uses: actions/cache@v2
id: cache-llvm-build
with:
key: llvm-build-11-windows-v2
key: llvm-build-14-windows-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -62,23 +66,17 @@ jobs:
uses: actions/cache@v2
id: cache-wasi-libc
with:
key: wasi-libc-sysroot-v1
key: wasi-libc-sysroot-v3
path: lib/wasi-libc/sysroot
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
- name: Cache Binaryen
uses: actions/cache@v2
id: cache-binaryen
with:
key: binaryen-v1
path: build/binaryen
- name: Build Binaryen
if: steps.cache-binaryen.outputs.cache-hit != 'true'
run: make binaryen
- name: Install wasmtime
run: |
scoop install wasmtime
- name: Test TinyGo
shell: bash
run: make test
run: make test GOTESTFLAGS="-v -short"
- name: Build TinyGo release tarball
run: make build/release -j4
- name: Make release artifact
@@ -98,6 +96,8 @@ jobs:
path: build/release/release.zip
- name: Smoke tests
shell: bash
run: make smoketest TINYGO=build/tinygo AVR=0 XTENSA=0
run: make smoketest TINYGO=$(PWD)/build/tinygo AVR=0 XTENSA=0
- name: Test stdlib packages
run: make tinygo-test
- name: Test stdlib packages on wasi
run: make tinygo-test-wasi-fast
+4
View File
@@ -20,8 +20,12 @@ src/device/rp/*.s
vendor
llvm-build
llvm-project
build/*
# Ignore files generated by smoketest
test.bin
test.elf
test.exe
test.gba
test.hex
test.nro
+3 -4
View File
@@ -10,10 +10,6 @@
[submodule "lib/cmsis-svd"]
path = lib/cmsis-svd
url = https://github.com/tinygo-org/cmsis-svd
[submodule "lib/compiler-rt"]
path = lib/compiler-rt
url = https://github.com/llvm-mirror/compiler-rt.git
branch = release_80
[submodule "lib/wasi-libc"]
path = lib/wasi-libc
url = https://github.com/CraneStation/wasi-libc
@@ -32,3 +28,6 @@
[submodule "lib/mingw-w64"]
path = lib/mingw-w64
url = https://github.com/mingw-w64/mingw-w64.git
[submodule "lib/macos-minimal-sdk"]
path = lib/macos-minimal-sdk
url = https://github.com/aykevl/macos-minimal-sdk.git
+1 -6
View File
@@ -11,12 +11,7 @@ lld so that the binary can be easily moved between systems. It also shows how to
build a release tarball that includes this binary and all necessary extra files.
**Note**: this documentation describes how to build a statically linked release
tarball. If you want to develop TinyGo, you will probably want to follow a
different guide:
* [Linux](https://tinygo.org/getting-started/linux/#source-install)
* [macOS](https://tinygo.org/getting-started/macos/#source-install)
* [Windows](https://tinygo.org/getting-started/windows/#source-install)
tarball. If you want to help with development of TinyGo itself, you should follow the guide located at https://tinygo.org/docs/guides/build/
## Dependencies
+297
View File
@@ -1,3 +1,300 @@
0.23.0
---
* **command line**
- add `-work` flag
- add Go 1.18 support
- add LLVM 14 support
- `run`: add support for command-line parameters
- `build`: calculate default output path if `-o` is not specified
- `build`: add JSON output
- `test`: support multiple test binaries with `-c`
- `test`: support flags like `-v` on all targets (including emulated firmware)
* **compiler**
- add support for ThinLTO
- use compiler-rt from LLVM
- `builder`: prefer GNU build ID over Go build ID for caching
- `builder`: add support for cross compiling to Darwin
- `builder`: support machine outlining pass in stacksize calculation
- `builder`: disable asynchronous unwind tables
- `compileopts`: fix emulator configuration on non-amd64 Linux architectures
- `compiler`: move allocations > 256 bytes to the heap
- `compiler`: fix incorrect `unsafe.Alignof` on some 32-bit architectures
- `compiler`: accept alias for slice `cap` builtin
- `compiler`: allow slices of empty structs
- `compiler`: fix difference in aliases in interface methods
- `compiler`: make `RawSyscall` an alias for `Syscall`
- `compiler`: remove support for memory references in `AsmFull`
- `loader`: only add Clang header path for CGo
- `transform`: fix poison value in heap-to-stack transform
* **standard library**
- `internal/fuzz`: add this package as a shim
- `os`: implement readdir for darwin and linux
- `os`: add `DirFS`, which is used by many programs to access readdir.
- `os`: isWine: be compatible with older versions of wine, too
- `os`: implement `RemoveAll`
- `os`: Use a `uintptr` for `NewFile`
- `os`: add stubs for `exec.ExitError` and `ProcessState.ExitCode`
- `os`: export correct values for `DevNull` for each OS
- `os`: improve support for `Signal` by fixing various bugs
- `os`: implement `File.Fd` method
- `os`: implement `UserHomeDir`
- `os`: add `exec.ProcessState` stub
- `os`: implement `Pipe` for darwin
- `os`: define stub `ErrDeadlineExceeded`
- `reflect`: add stubs for more missing methods
- `reflect`: rename `reflect.Ptr` to `reflect.Pointer`
- `reflect`: add `Value.FieldByIndexErr` stub
- `runtime`: fix various small GC bugs
- `runtime`: use memzero for leaking collector instead of manually zeroing objects
- `runtime`: implement `memhash`
- `runtime`: implement `fastrand`
- `runtime`: add stub for `debug.ReadBuildInfo`
- `runtime`: add stub for `NumCPU`
- `runtime`: don't inline `runtime.alloc` with `-gc=leaking`
- `runtime`: add `Version`
- `runtime`: add stubs for `NumCgoCall` and `NumGoroutine`
- `runtime`: stub {Lock,Unlock}OSThread on Windows
- `runtime`: be able to deal with a very small heap
- `syscall`: make `Environ` return a copy of the environment
- `syscall`: implement getpagesize and munmap
- `syscall`: `wasi`: define `MAP_SHARED` and `PROT_READ`
- `syscall`: stub mmap(), munmap(), MAP_SHARED, PROT_READ, SIGBUS, etc. on nonhosted targets
- `syscall`: darwin: more complete list of signals
- `syscall`: `wasi`: more complete list of signals
- `syscall`: stub `WaitStatus`
- `syscall/js`: allow copyBytesTo(Go|JS) to use `Uint8ClampedArray`
- `testing`: implement `TempDir`
- `testing`: nudge type TB closer to upstream; should be a no-op change.
- `testing`: on baremetal platforms, use simpler test matcher
* **targets**
- `atsamd`: fix usbcdc initialization when `-serial=uart`
- `atsamd51`: allow higher frequency when using SPI
- `esp`: support CGo
- `esp32c3`: add support for input pin
- `esp32c3`: add support for GPIO interrupts
- `esp32c3`: add support to receive UART data
- `rp2040`: fix PWM bug at high frequency
- `rp2040`: fix some minor I2C bugs
- `rp2040`: fix incorrect inline assembly
- `rp2040`: fix spurious i2c STOP during write+read transaction
- `rp2040`: improve ADC support
- `wasi`: remove `--export-dynamic` linker flag
- `wasm`: remove heap allocator from wasi-libc
* **boards**
- `circuitplay-bluefruit`: move pin mappings so board can be compiled for WASM use in Playground
- `esp32-c3-12f`: add the ESP32-C3-12f Kit
- `m5stamp-c3`: add pin setting of UART
- `macropad-rp2040`: add the Adafruit MacroPad RP2040 board
- `nano-33-ble`: typo in LPS22HB peripheral definition and documentation (#2579)
- `teensy41`: add the Teensy 4.1 board
- `teensy40`: add ADC support
- `teensy40`: add SPI support
- `thingplus-rp2040`: add the SparkFun Thing Plus RP2040 board
- `wioterminal`: add DefaultUART
- `wioterminal`: verify written data when flashing through OpenOCD
- `xiao-ble`: add XIAO BLE nRF52840 support
0.22.0
---
* **command line**
- add asyncify to scheduler flag help
- support -run for tests
- remove FreeBSD target support
- add LLVM 12 and LLVM 13 support, use LLVM 13 by default
- add support for ARM64 MacOS
- improve help
- check /run/media as well as /media on Linux for non-debian-based distros
- `test`: set cmd.Dir even when running emulators
- `info`: add JSON output using the `-json` flag
* **compiler**
- `builder`: fix off-by-one in size calculation
- `builder`: handle concurrent library header rename
- `builder`: use flock to avoid double-compiles
- `builder`: use build ID as cache key
- `builder`: add -fno-stack-protector to musl build
- `builder`: update clang header search path to look in /usr/lib
- `builder`: explicitly disable unwind tables for ARM
- `cgo`: add support for `C.CString` and related functions
- `compiler`: fix ranging over maps with particular map types
- `compiler`: add correct debug location to init instructions
- `compiler`: fix emission of large object layouts
- `compiler`: work around AVR atomics bugs
- `compiler`: predeclare runtime.trackPointer
- `interp`: work around AVR function pointers in globals
- `interp`: run goroutine starts and checks at runtime
- `interp`: always run atomic and volatile loads/stores at runtime
- `interp`: bump timeout to 180 seconds
- `interp`: handle type assertions on nil interfaces
- `loader`: elminate goroot cache inconsistency
- `loader`: respect $GOROOT when running `go list`
- `transform`: allocate the correct amount of bytes in an alloca
- `transform`: remove switched func lowering
* **standard library**
- `crypto/rand`: show error if platform has no rng
- `device/*`: add `*_Msk` field for each bit field and avoid duplicates
- `device/*`: provide Set/Get for each register field described in the SVD files
- `internal/task`: swap stack chain when switching goroutines
- `internal/task`: remove `-scheduler=coroutines`
- `machine`: add `Device` string constant
- `net`: add bare Interface implementation
- `net`: add net.Buffers
- `os`: stub out support for some features
- `os`: obey TMPDIR on unix, TMP on Windows, etc
- `os`: implement `ReadAt`, `Mkdir`, `Remove`, `Stat`, `Lstat`, `CreateTemp`, `MkdirAll`, `Chdir`, `Chmod`, `Clearenv`, `Unsetenv`, `Setenv`, `MkdirTemp`, `Rename`, `Seek`, `ExpandEnv`, `Symlink`, `Readlink`
- `os`: implement `File.Stat`
- `os`: fix `IsNotExist` on nonexistent path
- `os`: fix opening files on WASI in read-only mode
- `os`: work around lack of `syscall.seek` on 386 and arm
- `reflect`: make sure indirect pointers are handled correctly
- `runtime`: allow comparing interfaces
- `runtime`: use LLVM intrinsic to read the stack pointer
- `runtime`: strengthen hashmap hash function for structs and arrays
- `runtime`: fix float/complex hashing
- `runtime`: fix nil map dereference
- `runtime`: add realloc implementation to GCs
- `runtime`: handle negative sleep times
- `runtime`: correct GC scan bounds
- `runtime`: remove extalloc GC
- `rumtime`: implement `__sync` libcalls as critical sections for most microcontrollers
- `runtime`: add stubs for `Func.FileLine` and `Frame.PC`
- `sync`: fix concurrent read-lock on write-locked RWMutex
- `sync`: add a package doc
- `sync`: add tests
- `syscall`: add support for `Mmap` and `Mprotect`
- `syscall`: fix array size for mmap slice creation
- `syscall`: enable `Getwd` in wasi
- `testing`: add a stub for `CoverMode`
- `testing`: support -bench option to run benchmarks matching the given pattern.
- `testing`: support b.SetBytes(); implement sub-benchmarks.
- `testing`: replace spaces with underscores in test/benchmark names, as upstream does
- `testing`: implement testing.Cleanup
- `testing`: allow filtering subbenchmarks with the `-bench` flag
- `testing`: implement `-benchtime` flag
- `testing`: print duration
- `testing`: allow filtering of subtests using `-run`
* **targets**
- `all`: change LLVM features to match vanilla Clang
- `avr`: use interrupt-based timer which is much more accurate
- `nrf`: fix races in I2C
- `samd51`: implement TRNG for randomness
- `stm32`: pull-up on I2C lines
- `stm32`: fix timeout for i2c comms
- `stm32f4`, `stm32f103`: initial implementation for ADC
- `stm32f4`, `stm32f7`, `stm32l0x2`, `stm32l4`, `stm32l5`, `stm32wl`: TRNG implementation in crypto/rand
- `stm32wl`: add I2C support
- `windows`: add support for the `-size=` flag
- `wasm`: add support for `tinygo test`
- `wasi`, `wasm`: raise default stack size to 16 KiB
* **boards**
- add M5Stack
- add lorae5 (stm32wle) support
- add Generic Node Sensor Edition
- add STM32F469 Discovery
- add M5Stamp C3
- add Blues Wireless Swan
- `bluepill`: add definitions for ADC pins
- `stm32f4disco`: add definitions for ADC pins
- `stm32l552ze`: use supported stlink interface
- `microbit-v2`: add some pin definitions
0.21.0
---
* **command line**
- drop support for LLVM 10
- `build`: drop support for LLVM targets in the -target flag
- `build`: fix paths in error messages on Windows
- `build`: add -p flag to set parallelism
- `lldb`: implement `tinygo lldb` subcommand
- `test`: use emulator exit code instead of parsing test output
- `test`: pass testing arguments to wasmtime
* **compiler**
- use -opt flag for optimization level in CFlags (-Os, etc)
- `builder`: improve accuracy of the -size=full flag
- `builder`: hardcode some more frame sizes for __aeabi_* functions
- `builder`: add support for -size= flag for WebAssembly
- `cgo`: fix line/column reporting in syntax error messages
- `cgo`: support function definitions in CGo headers
- `cgo`: implement rudimentary C array decaying
- `cgo`: add support for stdio in picolibc and wasi-libc
- `cgo`: run CGo parser per file, not per CGo fragment
- `compiler`: fix unintentionally exported math functions
- `compiler`: properly implement div and rem operations
- `compiler`: add support for recursive function types
- `compiler`: add support for the `go` keyword on interface methods
- `compiler`: add minsize attribute for -Oz
- `compiler`: add "target-cpu" and "target-features" attributes
- `compiler`: fix indices into strings and arrays
- `compiler`: fix string compare functions
- `interp`: simplify some code to avoid some errors
- `interp`: support recursive globals (like linked lists) in globals
- `interp`: support constant globals
- `interp`: fix reverting of extractvalue/insertvalue with multiple indices
- `transform`: work around renamed return type after merging LLVM modules
* **standard library**
- `internal/bytealg`: fix indexing error in Compare()
- `machine`: support Pin.Get() function when the pin is configured as output
- `net`, `syscall`: Reduce code duplication by switching to internal/itoa.
- `os`: don't try to read executable path on baremetal
- `os`: implement Getwd
- `os`: add File.WriteString and File.WriteAt
- `reflect`: fix type.Size() to account for struct padding
- `reflect`: don't construct an interface-in-interface value
- `reflect`: implement Value.Elem() for interface values
- `reflect`: fix Value.Index() in a specific case
- `reflect`: add support for DeepEqual
- `runtime`: add another set of invalid unicode runes to encodeUTF8()
- `runtime`: only initialize os.runtime_args when needed
- `runtime`: only use CRLF on baremetal systems for println
- `runtime/debug`: stub `debug.SetMaxStack`
- `runtime/debug`: stub `debug.Stack`
- `testing`: add a stub for t.Parallel()
- `testing`: add support for -test.short flag
- `testing`: stub B.ReportAllocs()
- `testing`: add `testing.Verbose`
- `testing`: stub `testing.AllocsPerRun`
* **targets**
- fix gen-device-svd to handle 64-bit values
- add CPU and Features property to all targets
- match LLVM triple to the one Clang uses
- `atsam`: simplify definition of SERCOM UART, I2C and SPI peripherals
- `atsam`: move I2S0 to machine file
- `esp32`: fix SPI configuration
- `esp32c3`: add support for GDB debugging
- `esp32c3`: add support for CPU interrupts
- `esp32c3`: use tasks scheduler by default
- `fe310`: increase CPU frequency from 16MHz to 320MHz
- `fe310`: add support for bit banging drivers
- `linux`: build static binaries using musl
- `linux`: reduce binary size by calling `write` instead of `putchar`
- `linux`: add support for GOARM
- `riscv`: implement 32-bit atomic operations
- `riscv`: align the heap to 16 bytes
- `riscv`: switch to tasks-based scheduler
- `rp2040`: add CPUFrequency()
- `rp2040`: improve I2C baud rate configuration
- `rp2040`: add pin interrupt API
- `rp2040`: refactor PWM code and fix Period calculation
- `stm32f103`: fix SPI
- `stm32f103`: make SPI frequency selection more flexible
- `qemu`: signal correct exit code to QEMU
- `wasi`: run C/C++ constructors at startup
- `wasm`: ensure heapptr is aligned
- `wasm`: update wasi-libc dependency
- `wasm`: wasi: use asyncify
- `wasm`: support `-scheduler=none`
- `windows`: add support for Windows (amd64 only for now)
* **boards**
- `feather-stm32f405`, `feather-rp2040`: add I2C pin names
- `m5stack-core2`: add M5Stack Core2
- `nano-33-ble`: SoftDevice s140v7 support
- `nano-33-ble`: add constants for more on-board pins
0.20.0
---
+1 -52
View File
@@ -1,52 +1 @@
# How to contribute
Thank you for your interest in improving TinyGo.
We would like your help to make this project better, so we appreciate any contributions. See if one of the following descriptions matches your situation:
### New to TinyGo
We'd love to get your feedback on getting started with TinyGo. Run into any difficulty, confusion, or anything else? You are not alone. We want to know about your experience, so we can help the next people. Please open a Github issue with your questions, or you can also get in touch directly with us on our Slack channel at [https://gophers.slack.com/messages/CDJD3SUP6](https://gophers.slack.com/messages/CDJD3SUP6).
### Something in TinyGo is not working as you expect
Please open a Github issue with your problem, and we will be happy to assist.
### Something in Go that you want/need does not appear to be in TinyGo
We probably have not implemented it yet. Please take a look at our [Roadmap](https://github.com/tinygo-org/tinygo/wiki/Roadmap). Your pull request adding the functionality to TinyGo would be greatly appreciated.
Please open a Github issue. We want to help, and also make sure that there is no duplications of efforts. Sometimes what you need is already being worked on by someone else.
A long tail of small (and large) language features haven't been implemented yet. In almost all cases, the compiler will show a `todo:` error from `compiler/compiler.go` when you try to use it. You can try implementing it, or open a bug report with a small code sample that fails to compile.
### Some specific hardware you want to use does not appear to be in TinyGo
As above, we probably have not implemented it yet. Your contribution adding the hardware support to TinyGo would be greatly appreciated.
Please start by opening a Github issue. We want to help you to help us to help you.
Lots of targets/boards are still unsupported. Adding an architecture often requires a few compiler changes, but if the architecture is supported you can try implementing support for a new chip or board in `src/runtime`. For details, see [this wiki entry on adding archs/chips/boards](https://github.com/tinygo-org/tinygo/wiki/Adding-a-new-board).
Microcontrollers have lots of peripherals (I2C, SPI, ADC, etc.) and many don't have an implementation yet in the `machine` package. Adding support for new peripherals is very useful.
## How to use our Github repository
The `release` branch of this repo will always have the latest released version of TinyGo. All of the active development work for the next release will take place in the `dev` branch. TinyGo will use semantic versioning and will create a tag/release for each release.
Here is how to contribute back some code or documentation:
- Fork repo
- Create a feature branch off of the `dev` branch
- Make some useful change
- Make sure the tests still pass
- Submit a pull request against the `dev` branch.
- Be kind
## How to run tests
To run the tests:
```
make test
```
Please take a look at our [Contributing](https://tinygo.org/docs/guides/contributing/) page on our web site for details. Thank you.
+38 -68
View File
@@ -1,80 +1,50 @@
# TinyGo base stage installs the most recent Go 1.17.x, LLVM 11 and the TinyGo compiler itself.
FROM golang:1.17 AS tinygo-base
# tinygo-llvm stage obtains the llvm source for TinyGo
FROM golang:1.18 AS tinygo-llvm
RUN wget -O- https://apt.llvm.org/llvm-snapshot.gpg.key| apt-key add - && \
echo "deb http://apt.llvm.org/bullseye/ llvm-toolchain-bullseye-11 main" >> /etc/apt/sources.list && \
apt-get update && \
apt-get install -y llvm-11-dev libclang-11-dev lld-11 git
RUN apt-get update && \
apt-get install -y apt-utils make cmake clang-11 binutils-avr gcc-avr avr-libc ninja-build
COPY ./Makefile /tinygo/Makefile
RUN cd /tinygo/ && \
make llvm-source
# tinygo-llvm-build stage build the custom llvm with xtensa support
FROM tinygo-llvm AS tinygo-llvm-build
RUN cd /tinygo/ && \
make llvm-build
# tinygo-xtensa stage installs tools needed for ESP32
FROM tinygo-llvm-build AS tinygo-xtensa
ARG xtensa_version="1.22.0-80-g6c4433a-5.2.0"
RUN cd /tmp/ && \
wget -q https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-${xtensa_version}.tar.gz && \
tar xzf xtensa-esp32-elf-linux64-${xtensa_version}.tar.gz && \
cp ./xtensa-esp32-elf/bin/xtensa-esp32-elf-ld /usr/local/bin/ && \
rm -rf /tmp/xtensa*
# tinygo-compiler stage builds the compiler itself
FROM tinygo-xtensa AS tinygo-compiler
COPY . /tinygo
# remove submodules directories and re-init them to fix any hard-coded paths
# after copying the tinygo directory in the previous step.
# update submodules
RUN cd /tinygo/ && \
rm -rf ./lib/* && \
rm -rf ./lib/*/ && \
git submodule sync && \
git submodule update --init --recursive --force
COPY ./lib/picolibc-stdio.c /tinygo/lib/picolibc-stdio.c
RUN cd /tinygo/ && \
make
# tinygo-tools stage installs the needed dependencies to compile TinyGo programs for all platforms.
FROM tinygo-compiler AS tinygo-tools
RUN cd /tinygo/ && \
go install /tinygo/
# tinygo-wasm stage installs the needed dependencies to compile TinyGo programs for WASM.
FROM tinygo-base AS tinygo-wasm
COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
COPY --from=tinygo-base /tinygo/src /tinygo/src
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
RUN cd /tinygo/ && \
apt-get update && \
apt-get install -y make clang-11 libllvm11 lld-11 cmake ninja-build && \
mkdir build && \
make wasi-libc binaryen
# tinygo-avr stage installs the needed dependencies to compile TinyGo programs for AVR microcontrollers.
FROM tinygo-base AS tinygo-avr
COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
COPY --from=tinygo-base /tinygo/src /tinygo/src
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
COPY --from=tinygo-base /tinygo/Makefile /tinygo/
COPY --from=tinygo-base /tinygo/tools /tinygo/tools
COPY --from=tinygo-base /tinygo/lib /tinygo/lib
RUN cd /tinygo/ && \
apt-get update && \
apt-get install -y apt-utils make binutils-avr gcc-avr avr-libc && \
make gen-device-avr && \
apt-get autoremove -y && \
apt-get clean
# tinygo-arm stage installs the needed dependencies to compile TinyGo programs for ARM microcontrollers.
FROM tinygo-base AS tinygo-arm
COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
COPY --from=tinygo-base /tinygo/src /tinygo/src
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
COPY --from=tinygo-base /tinygo/Makefile /tinygo/
COPY --from=tinygo-base /tinygo/tools /tinygo/tools
COPY --from=tinygo-base /tinygo/lib /tinygo/lib
RUN cd /tinygo/ && \
apt-get update && \
apt-get install -y apt-utils make clang-11 && \
make gen-device-nrf && make gen-device-stm32
# tinygo-all stage installs the needed dependencies to compile TinyGo programs for all platforms.
FROM tinygo-wasm AS tinygo-all
COPY --from=tinygo-base /tinygo/Makefile /tinygo/
COPY --from=tinygo-base /tinygo/tools /tinygo/tools
COPY --from=tinygo-base /tinygo/lib /tinygo/lib
RUN cd /tinygo/ && \
apt-get update && \
apt-get install -y apt-utils make clang-11 binutils-avr gcc-avr avr-libc && \
make gen-device
make wasi-libc binaryen && \
make gen-device -j4 && \
cp build/* $GOPATH/bin/
CMD ["tinygo"]
+2 -2
View File
@@ -1,7 +1,7 @@
Copyright (c) 2018-2021 TinyGo Authors. All rights reserved.
Copyright (c) 2018-2022 The TinyGo Authors. All rights reserved.
TinyGo includes portions of the Go standard library.
Copyright (c) 2009-2021 The Go Authors. All rights reserved.
Copyright (c) 2009-2022 The Go Authors. All rights reserved.
TinyGo includes portions of LLVM, which is under the Apache License v2.0 with
LLVM Exceptions. See https://llvm.org/LICENSE.txt for license information.
+213 -49
View File
@@ -9,20 +9,34 @@ CLANG_SRC ?= $(LLVM_PROJECTDIR)/clang
LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
# Try to autodetect LLVM build tools.
detect = $(shell command -v $(1) 2> /dev/null && echo $(1))
CLANG ?= $(word 1,$(abspath $(call detect,llvm-build/bin/clang))$(call detect,clang-11)$(call detect,clang))
LLVM_AR ?= $(word 1,$(abspath $(call detect,llvm-build/bin/llvm-ar))$(call detect,llvm-ar-11)$(call detect,llvm-ar))
LLVM_NM ?= $(word 1,$(abspath $(call detect,llvm-build/bin/llvm-nm))$(call detect,llvm-nm-11)$(call detect,llvm-nm))
# Versions are listed here in descending priority order.
LLVM_VERSIONS = 14 13 12 11
errifempty = $(if $(1),$(1),$(error $(2)))
detect = $(shell which $(call errifempty,$(firstword $(foreach p,$(2),$(shell command -v $(p) 2> /dev/null && echo $(p)))),failed to locate $(1) at any of: $(2)))
toolSearchPathsVersion = $(1)-$(2)
ifeq ($(shell uname -s),Darwin)
# Also explicitly search Brew's copy, which is not in PATH by default.
BREW_PREFIX := $(shell brew --prefix)
toolSearchPathsVersion += $(BREW_PREFIX)/opt/llvm@$(2)/bin/$(1)-$(2) $(BREW_PREFIX)/opt/llvm@$(2)/bin/$(1)
endif
# First search for a custom built copy, then move on to explicitly version-tagged binaries, then just see if the tool is in path with its normal name.
findLLVMTool = $(call detect,$(1),$(abspath llvm-build/bin/$(1)) $(foreach ver,$(LLVM_VERSIONS),$(call toolSearchPathsVersion,$(1),$(ver))) $(1))
CLANG ?= $(call findLLVMTool,clang)
LLVM_AR ?= $(call findLLVMTool,llvm-ar)
LLVM_NM ?= $(call findLLVMTool,llvm-nm)
# Go binary and GOROOT to select
GO ?= go
export GOROOT = $(shell $(GO) env GOROOT)
# Flags to pass to go test.
GOTESTFLAGS ?= -v
# md5sum binary
MD5SUM = md5sum
# tinygo binary for tests
TINYGO ?= $(word 1,$(call detect,tinygo)$(call detect,build/tinygo))
TINYGO ?= $(call detect,tinygo,tinygo $(CURDIR)/build/tinygo)
# Use CCACHE for LLVM if possible
ifneq (, $(shell command -v ccache 2> /dev/null))
@@ -36,6 +50,29 @@ else
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=OFF'
endif
# Cross compiling support.
ifneq ($(CROSS),)
CC = $(CROSS)-gcc
CXX = $(CROSS)-g++
LLVM_OPTION += \
-DCMAKE_C_COMPILER=$(CC) \
-DCMAKE_CXX_COMPILER=$(CXX) \
-DLLVM_DEFAULT_TARGET_TRIPLE=$(CROSS) \
-DCROSS_TOOLCHAIN_FLAGS_NATIVE="-UCMAKE_C_COMPILER;-UCMAKE_CXX_COMPILER"
ifeq ($(CROSS), arm-linux-gnueabihf)
# Assume we're building on a Debian-like distro, with QEMU installed.
LLVM_CONFIG_PREFIX = qemu-arm -L /usr/arm-linux-gnueabihf/
# The CMAKE_SYSTEM_NAME flag triggers cross compilation mode.
LLVM_OPTION += \
-DCMAKE_SYSTEM_NAME=Linux \
-DLLVM_TARGET_ARCH=ARM
GOENVFLAGS = GOARCH=arm CC=$(CC) CXX=$(CXX) CGO_ENABLED=1
BINARYEN_OPTION += -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX)
else
$(error Unknown cross compilation target: $(CROSS))
endif
endif
.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-nxp gen-device-avr gen-device-rp
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf debuginfopdb executionengine frontendopenmp instrumentation interpreter ipo irreader libdriver linker lto mc mcjit objcarcopts option profiledata scalaropts support target windowsmanifest
@@ -54,20 +91,20 @@ ifeq ($(OS),Windows_NT)
CGO_LDFLAGS += -static -static-libgcc -static-libstdc++
CGO_LDFLAGS_EXTRA += -lversion
BINARYEN_OPTION += -DCMAKE_EXE_LINKER_FLAGS='-static-libgcc -static-libstdc++'
LIBCLANG_NAME = libclang
USE_SYSTEM_BINARYEN ?= 1
else ifeq ($(shell uname -s),Darwin)
MD5SUM = md5
LIBCLANG_NAME = clang
CGO_LDFLAGS += -lxar
USE_SYSTEM_BINARYEN ?= 1
else ifeq ($(shell uname -s),FreeBSD)
MD5SUM = md5
LIBCLANG_NAME = clang
START_GROUP = -Wl,--start-group
END_GROUP = -Wl,--end-group
else
LIBCLANG_NAME = clang
START_GROUP = -Wl,--start-group
END_GROUP = -Wl,--end-group
endif
@@ -77,11 +114,14 @@ CLANG_LIB_NAMES = clangAnalysis clangAST clangASTMatchers clangBasic clangCodeGe
CLANG_LIBS = $(START_GROUP) $(addprefix -l,$(CLANG_LIB_NAMES)) $(END_GROUP) -lstdc++
# Libraries that should be linked in for the statically linked LLD.
LLD_LIB_NAMES = lldCOFF lldCommon lldCore lldDriver lldELF lldMachO lldMinGW lldReaderWriter lldWasm lldYAML
LLD_LIB_NAMES = lldCOFF lldCommon lldELF lldMachO lldMinGW lldWasm
LLD_LIBS = $(START_GROUP) $(addprefix -l,$(LLD_LIB_NAMES)) $(END_GROUP)
# Other libraries that are needed to link TinyGo.
EXTRA_LIB_NAMES = LLVMInterpreter
EXTRA_LIB_NAMES = LLVMInterpreter LLVMMCA LLVMX86TargetMCA
# All libraries to be built and linked with the tinygo binary (lib/lib*.a).
LIB_NAMES = clang $(CLANG_LIB_NAMES) $(LLD_LIB_NAMES) $(EXTRA_LIB_NAMES)
# These build targets appear to be the only ones necessary to build all TinyGo
# dependencies. Only building a subset significantly speeds up rebuilding LLVM.
@@ -89,16 +129,15 @@ EXTRA_LIB_NAMES = LLVMInterpreter
# library path (for ninja).
# This list also includes a few tools that are necessary as part of the full
# TinyGo build.
NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm $(addprefix lib/lib,$(addsuffix .a,$(LIBCLANG_NAME) $(CLANG_LIB_NAMES) $(LLD_LIB_NAMES) $(EXTRA_LIB_NAMES)))
NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm $(addprefix lib/lib,$(addsuffix .a,$(LIB_NAMES)))
# For static linking.
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
CGO_CPPFLAGS+=$(shell $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
CGO_CPPFLAGS+=$(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
CGO_CXXFLAGS=-std=c++14
CGO_LDFLAGS+=$(abspath $(LLVM_BUILDDIR))/lib/lib$(LIBCLANG_NAME).a -L$(abspath $(LLVM_BUILDDIR)/lib) $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
CGO_LDFLAGS+=-L$(abspath $(LLVM_BUILDDIR)/lib) -lclang $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
endif
clean:
@rm -rf build
@@ -159,7 +198,7 @@ gen-device-rp: build/gen-device-svd
# Get LLVM sources.
$(LLVM_PROJECTDIR)/llvm:
git clone -b xtensa_release_11.0.0 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
git clone -b xtensa_release_14.0.0-patched --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
llvm-source: $(LLVM_PROJECTDIR)/llvm
# Configure LLVM.
@@ -171,56 +210,74 @@ $(LLVM_BUILDDIR)/build.ninja: llvm-source
$(LLVM_BUILDDIR): $(LLVM_BUILDDIR)/build.ninja
cd $(LLVM_BUILDDIR) && ninja $(NINJA_BUILD_TARGETS)
ifneq ($(USE_SYSTEM_BINARYEN),1)
# Build Binaryen
.PHONY: binaryen
binaryen: build/wasm-opt
build/wasm-opt:
cd lib/binaryen && cmake -G Ninja . -DBUILD_STATIC_LIB=ON $(BINARYEN_OPTION) && ninja
cp lib/binaryen/bin/wasm-opt build/wasm-opt
binaryen: build/wasm-opt$(EXE)
build/wasm-opt$(EXE):
mkdir -p build
cd lib/binaryen && cmake -G Ninja . -DBUILD_STATIC_LIB=ON $(BINARYEN_OPTION) && ninja bin/wasm-opt$(EXE)
cp lib/binaryen/bin/wasm-opt$(EXE) build/wasm-opt$(EXE)
endif
# Build wasi-libc sysroot
.PHONY: wasi-libc
wasi-libc: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a
lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
cd lib/wasi-libc && make -j4 WASM_CFLAGS="-O2 -g -DNDEBUG" WASM_CC=$(CLANG) WASM_AR=$(LLVM_AR) WASM_NM=$(LLVM_NM)
cd lib/wasi-libc && make -j4 WASM_CFLAGS="-O2 -g -DNDEBUG" MALLOC_IMPL=none WASM_CC=$(CLANG) WASM_AR=$(LLVM_AR) WASM_NM=$(LLVM_NM)
# Build the Go compiler.
tinygo:
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " make llvm-source"; echo " make $(LLVM_BUILDDIR)"; exit 1; fi
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X main.gitSha1=`git rev-parse --short HEAD`" .
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
test: wasi-libc
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test -v -timeout=20m -buildmode exe -tags byollvm ./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 ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
TEST_PACKAGES = \
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
TEST_PACKAGES_SLOW = \
compress/bzip2 \
crypto/dsa \
index/suffixarray \
# Standard library packages that pass tests quickly on darwin, linux, wasi, and windows
TEST_PACKAGES_FAST = \
compress/zlib \
container/heap \
container/list \
container/ring \
crypto/des \
crypto/dsa \
crypto/elliptic/internal/fiat \
crypto/internal/subtle \
crypto/md5 \
crypto/rc4 \
crypto/sha1 \
crypto/sha256 \
crypto/sha512 \
debug/macho \
encoding \
encoding/ascii85 \
encoding/base32 \
encoding/csv \
encoding/hex \
go/scanner \
hash \
hash/adler32 \
hash/fnv \
hash/crc64 \
hash/fnv \
html \
index/suffixarray \
internal/itoa \
internal/profile \
math \
math/cmplx \
net \
net/http/internal/ascii \
net/mail \
os \
path \
reflect \
sync \
testing \
testing/iotest \
text/scanner \
@@ -228,15 +285,91 @@ TEST_PACKAGES = \
unicode/utf16 \
unicode/utf8 \
# archive/zip 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
# 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
TEST_PACKAGES_LINUX := \
archive/zip \
compress/flate \
compress/lzw \
debug/dwarf \
debug/plan9obj \
io/fs \
testing/fstest
TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
TEST_PACKAGES_WINDOWS := \
compress/lzw
# Report platforms on which each standard library package is known to pass tests
jointmp := $(shell echo /tmp/join.$$$$)
report-stdlib-tests-pass:
@for t in $(TEST_PACKAGES_DARWIN); do echo "$$t darwin"; done | sort > $(jointmp).darwin
@for t in $(TEST_PACKAGES_LINUX); do echo "$$t linux"; done | sort > $(jointmp).linux
@for t in $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW); do echo "$$t darwin linux wasi windows"; done | sort > $(jointmp).portable
@join -a1 -a2 $(jointmp).darwin $(jointmp).linux | \
join -a1 -a2 - $(jointmp).portable
@rm $(jointmp).*
# Standard library packages that pass tests quickly on the current platform
ifeq ($(shell uname),Darwin)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_DARWIN)
endif
ifeq ($(shell uname),Linux)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_LINUX)
endif
ifeq ($(OS),Windows_NT)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
endif
# Test known-working standard library packages.
# TODO: parallelize, and only show failing tests (no implied -v flag).
.PHONY: tinygo-test
tinygo-test:
$(TINYGO) test $(TEST_PACKAGES)
$(TINYGO) test $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
tinygo-test-fast:
$(TINYGO) test $(TEST_PACKAGES_HOST)
tinygo-bench:
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
tinygo-bench-fast:
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST)
# Same thing, except for wasi rather than the current platform.
tinygo-test-wasi:
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
tinygo-test-wasi-fast:
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST)
tinygo-bench-wasi:
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
tinygo-bench-wasi-fast:
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST)
# Test external packages in a large corpus.
test-corpus:
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml
test-corpus-fast:
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus -short . -corpus=testdata/corpus.yaml
test-corpus-wasi: wasi-libc
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml -target=wasi
tinygo-baremetal:
# Regression tests that run on a baremetal target and don't fit in either main_test.go or smoketest.
# regression test for #2666: e.g. encoding/hex must pass on baremetal
$(TINYGO) test -target cortex-m-qemu encoding/hex
.PHONY: smoketest
smoketest:
$(TINYGO) version
# compile-only platform-independent examples
cd tests/text/template/smoke && $(TINYGO) test -c && rm -f smoke.test
# regression test for #2563
cd tests/os/smoke && $(TINYGO) test -c -target=pybadge && rm smoke.test
# test all examples (except pwm)
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky1
@$(MD5SUM) test.hex
@@ -269,6 +402,7 @@ smoketest:
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
@$(MD5SUM) test.hex
# test simulated boards on play.tinygo.org
ifneq ($(WASM), 0)
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
@$(MD5SUM) test.wasm
$(TINYGO) build -size short -o test.wasm -tags=hifive1b examples/blinky1
@@ -281,6 +415,9 @@ smoketest:
@$(MD5SUM) test.wasm
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_express examples/blinky1
@$(MD5SUM) test.wasm
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_bluefruit examples/blinky1
@$(MD5SUM) test.wasm
endif
# test all targets/boards
$(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1
@$(MD5SUM) test.hex
@@ -368,6 +505,8 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=qtpy examples/serial
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy41 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy40 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy36 examples/blinky1
@@ -394,6 +533,8 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=macropad-rp2040 examples/blinky1
@$(MD5SUM) test.hex
# test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex
@@ -418,6 +559,8 @@ ifneq ($(STM32), 0)
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-l552ze examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-wl55jc examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky2
@@ -426,6 +569,12 @@ ifneq ($(STM32), 0)
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco-1 examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f469disco examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=lorae5 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=swan examples/blinky1
@$(MD5SUM) test.hex
endif
ifneq ($(AVR), 0)
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
@@ -454,17 +603,23 @@ ifneq ($(XTENSA), 0)
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/serial
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target m5stack examples/serial
@$(MD5SUM) test.bin
endif
$(TINYGO) build -size short -o test.bin -target=esp32c3 examples/serial
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/serial
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=hifive1-qemu examples/serial
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
@$(MD5SUM) test.hex
ifneq ($(WASM), 0)
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
endif
# test various compiler flags
$(TINYGO) build -size short -o test.hex -target=pca10040 -gc=none -scheduler=none examples/blinky1
@$(MD5SUM) test.hex
@@ -477,7 +632,8 @@ endif
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
@$(MD5SUM) test.hex
GOOS=linux GOARCH=arm $(TINYGO) build -size short -o test.elf ./testdata/cgo
GOOS=windows GOARCH=amd64 $(TINYGO) build -o test.exe ./testdata/cgo
GOOS=windows GOARCH=amd64 $(TINYGO) build -size short -o test.exe ./testdata/cgo
GOOS=darwin GOARCH=amd64 $(TINYGO) build -o test ./testdata/cgo
ifneq ($(OS),Windows_NT)
# TODO: this does not yet work on Windows. Somehow, unused functions are
# not garbage collected.
@@ -488,11 +644,11 @@ endif
wasmtest:
$(GO) test ./tests/wasm
build/release: tinygo gen-device wasi-libc binaryen
build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binaryen)
@mkdir -p build/release/tinygo/bin
@mkdir -p build/release/tinygo/lib/clang/include
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
@mkdir -p build/release/tinygo/lib/compiler-rt/lib
@mkdir -p build/release/tinygo/lib/macos-minimal-sdk
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
@mkdir -p build/release/tinygo/lib/musl/arch
@@ -502,18 +658,18 @@ build/release: tinygo gen-device wasi-libc binaryen
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libc
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libm
@mkdir -p build/release/tinygo/lib/wasi-libc
@mkdir -p build/release/tinygo/pkg/armv6m-unknown-unknown-eabi
@mkdir -p build/release/tinygo/pkg/armv7m-unknown-unknown-eabi
@mkdir -p build/release/tinygo/pkg/armv7em-unknown-unknown-eabi
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus
@mkdir -p build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4
@echo copying source files
@cp -p build/tinygo$(EXE) build/release/tinygo/bin
ifneq ($(USE_SYSTEM_BINARYEN),1)
@cp -p build/wasm-opt$(EXE) build/release/tinygo/bin
endif
@cp -p $(abspath $(CLANG_SRC))/lib/Headers/*.h build/release/tinygo/lib/clang/include
@cp -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/CMSIS
@cp -rp lib/CMSIS/README.md build/release/tinygo/lib/CMSIS
@cp -rp lib/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt/lib
@cp -rp lib/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt
@cp -rp lib/compiler-rt/README.txt build/release/tinygo/lib/compiler-rt
@cp -rp lib/macos-minimal-sdk/* build/release/tinygo/lib/macos-minimal-sdk
@cp -rp lib/musl/arch/aarch64 build/release/tinygo/lib/musl/arch
@cp -rp lib/musl/arch/arm build/release/tinygo/lib/musl/arch
@cp -rp lib/musl/arch/generic build/release/tinygo/lib/musl/arch
@@ -549,21 +705,29 @@ build/release: tinygo gen-device wasi-libc binaryen
@cp -rp lib/picolibc/newlib/libm/common build/release/tinygo/lib/picolibc/newlib/libm
@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 llvm-project/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt-builtins
@cp -rp llvm-project/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
@cp -rp src build/release/tinygo/src
@cp -rp targets build/release/tinygo/targets
./build/tinygo build-library -target=armv6m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv6m-unknown-unknown-eabi/compiler-rt compiler-rt
./build/tinygo build-library -target=armv7m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7m-unknown-unknown-eabi/compiler-rt compiler-rt
./build/tinygo build-library -target=armv7em-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7em-unknown-unknown-eabi/compiler-rt compiler-rt
./build/tinygo build-library -target=armv6m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv6m-unknown-unknown-eabi/picolibc picolibc
./build/tinygo build-library -target=armv7m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7m-unknown-unknown-eabi/picolibc picolibc
./build/tinygo build-library -target=armv7em-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7em-unknown-unknown-eabi/picolibc picolibc
./build/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/compiler-rt compiler-rt
./build/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/compiler-rt compiler-rt
./build/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/compiler-rt compiler-rt
./build/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/picolibc picolibc
./build/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/picolibc picolibc
./build/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/picolibc picolibc
release: build/release
release:
tar -czf build/release.tar.gz -C build/release tinygo
deb: build/release
DEB_ARCH ?= native
deb:
@mkdir -p build/release-deb/usr/local/bin
@mkdir -p build/release-deb/usr/local/lib
cp -ar build/release/tinygo build/release-deb/usr/local/lib/tinygo
ln -sf ../lib/tinygo/bin/tinygo build/release-deb/usr/local/bin/tinygo
fpm -f -s dir -t deb -n tinygo -v $(shell grep "const Version = " goenv/version.go | awk '{print $$NF}') -m '@tinygo-org' --description='TinyGo is a Go compiler for small places.' --license='BSD 3-Clause' --url=https://tinygo.org/ --deb-changelog CHANGELOG.md -p build/release.deb -C ./build/release-deb
fpm -f -s dir -t deb -n tinygo -a $(DEB_ARCH) -v $(shell grep "const Version = " goenv/version.go | awk '{print $$NF}') -m '@tinygo-org' --description='TinyGo is a Go compiler for small places.' --license='BSD 3-Clause' --url=https://tinygo.org/ --deb-changelog CHANGELOG.md -p build/release.deb -C ./build/release-deb
ifneq ($(RELEASEONLY), 1)
release: build/release
deb: build/release
endif
+21 -8
View File
@@ -1,6 +1,6 @@
# TinyGo - Go compiler for small places
[![CircleCI](https://circleci.com/gh/tinygo-org/tinygo/tree/dev.svg?style=svg)](https://circleci.com/gh/tinygo-org/tinygo/tree/dev) [![Build Status](https://dev.azure.com/tinygo/tinygo/_apis/build/status/tinygo-CI?branchName=dev)](https://dev.azure.com/tinygo/tinygo/_build/latest?definitionId=1&branchName=dev)
[![Linux](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml) [![macOS](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml) [![Windows](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml) [![Docker](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml) [![CircleCI](https://circleci.com/gh/tinygo-org/tinygo/tree/dev.svg?style=svg)](https://circleci.com/gh/tinygo-org/tinygo/tree/dev)
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (Wasm), and command-line tools.
@@ -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.
The following 71 microcontroller boards are currently supported:
The following 85 microcontroller boards are currently supported:
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
@@ -59,6 +59,7 @@ The following 71 microcontroller boards are currently supported:
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
* [Adafruit ItsyBitsy M4](https://www.adafruit.com/product/3800)
* [Adafruit ItsyBitsy nRF52840](https://www.adafruit.com/product/4481)
* [Adafruit MacroPad RP2040](https://www.adafruit.com/product/5100)
* [Adafruit Matrix Portal M4](https://www.adafruit.com/product/4745)
* [Adafruit Metro M4 Express Airlift](https://www.adafruit.com/product/4000)
* [Adafruit PyBadge](https://www.adafruit.com/product/4200)
@@ -79,12 +80,18 @@ The following 71 microcontroller boards are currently supported:
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
* [BBC micro:bit](https://microbit.org/)
* [BBC micro:bit v2](https://microbit.org/new-microbit/)
* [blues wireless Swan](https://blues.io/products/swan/)
* [Digispark](http://digistump.com/products/1)
* [Dragino LoRaWAN GPS Tracker LGT-92](http://www.dragino.com/products/lora-lorawan-end-node/item/142-lgt-92.html)
* [ESP32](https://www.espressif.com/en/products/socs/esp32)
* [ESP8266](https://www.espressif.com/en/products/socs/esp8266)
* [ESP32 - Core board](https://www.espressif.com/en/products/socs/esp32)
* [ESP32 - mini32](https://www.espressif.com/en/products/socs/esp32)
* [ESP32-C3-12f](https://www.espressif.com/en/products/socs/esp32-c3)
* [ESP8266 - d1mini](https://www.espressif.com/en/products/socs/esp8266)
* [ESP8266 - NodeMCU](https://www.espressif.com/en/products/socs/esp8266)
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
* [M5Stack](https://docs.m5stack.com/en/core/basic)
* [M5Stack Core2](https://shop.m5stack.com/products/m5stack-core2-esp32-iot-development-kit)
* [M5Stamp C3](https://docs.m5stack.com/en/core/stamp_c3)
* [Makerdiary nRF52840-MDK](https://wiki.makerdiary.com/nrf52840-mdk/)
* [Makerdiary nRF52840-MDK USB Dongle](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/)
* [Microchip SAM E54 Xplained Pro](https://www.microchip.com/developmenttools/productdetails/atsame54-xpro)
@@ -101,21 +108,28 @@ The following 71 microcontroller boards are currently supported:
* [PineTime DevKit](https://www.pine64.org/pinetime/)
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
* [PJRC Teensy 4.1](https://www.pjrc.com/store/teensy41.html)
* [ProductivityOpen P1AM-100](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html)
* [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/)
* [Raytac MDBT50Q-RX Dongle (with TinyUF2 bootloader)](https://www.adafruit.com/product/5199)
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
* [Seeed XIAO BLE](https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.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)
* [SiFIve HiFive1](https://www.sifive.com/boards/hifive1)
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
* [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1)
* [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" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
* [ST Micro "Nucleo" L031K6](https://www.st.com/ja/evaluation-tools/nucleo-l031k6.html)
* [ST Micro "Nucleo" L432KC](https://www.st.com/ja/evaluation-tools/nucleo-l432kc.html)
* [ST Micro "Nucleo" L552ZE](https://www.st.com/en/evaluation-tools/nucleo-l552ze-q.html)
* [ST Micro "Nucleo" WL55JC](https://www.st.com/en/evaluation-tools/nucleo-wl55jc.html)
* [ST Micro STM32F103XX "Bluepill"](https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill)
* [ST Micro STM32F407 "Discovery"](https://www.st.com/en/evaluation-tools/stm32f4discovery.html)
* [ST Micro STM32F469 "Discovery"](https://www.st.com/content/st_com/en/products/evaluation-tools/product-evaluation-tools/mcu-mpu-eval-tools/stm32-mcu-mpu-eval-tools/stm32-discovery-kits/32f469idiscovery.html)
* [X9 Pro smartwatch](https://github.com/curtpw/nRF5x-device-reverse-engineering/tree/master/X9-nrf52832-activity-tracker/)
* [The Things Industries Generic Node Sensor Edition](https://www.genericnode.com/docs/sensor-edition/)
For more information, see [this list of boards](https://tinygo.org/microcontrollers/). Pull requests for additional support are welcome!
@@ -142,7 +156,7 @@ should arrive fairly quickly (under 1 min): https://invite.slack.golangbridge.or
Your contributions are welcome!
Please take a look at our [CONTRIBUTING.md](./CONTRIBUTING.md) document for details.
Please take a look at our [Contributing](https://tinygo.org/docs/guides/contributing/) page on our web site for details.
## Project Scope
@@ -156,7 +170,6 @@ Goals:
Non-goals:
* Using more than one core.
* Be efficient while using zillions of goroutines. However, good goroutine support is certainly a goal.
* Be as fast as `gc`. However, LLVM will probably be better at optimizing certain things so TinyGo might actually turn out to be faster for number crunching.
* Be able to compile every Go program out there.
-2
View File
@@ -1,2 +0,0 @@
*
!.gitignore
+139 -40
View File
@@ -23,7 +23,7 @@ import (
"strconv"
"strings"
"github.com/tinygo-org/tinygo/cgo"
"github.com/gofrs/flock"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/compiler"
"github.com/tinygo-org/tinygo/goenv"
@@ -37,14 +37,25 @@ import (
// BuildResult is the output of a build. This includes the binary itself and
// some other metadata that is obtained while building the binary.
type BuildResult struct {
// The executable directly from the linker, usually including debug
// information. Used for GDB for example.
Executable string
// A path to the output binary. It will be removed after Build returns, so
// if it should be kept it must be copied or moved away.
// It is often the same as Executable, but differs if the output format is
// .hex for example (instead of the usual ELF).
Binary string
// The directory of the main package. This is useful for testing as the test
// binary must be run in the directory of the tested package.
MainDir string
// The root of the Go module tree. This is used for running tests in emulator
// that restrict file system access to allow them to grant access to the entire
// source tree they're likely to need to read testdata from.
ModuleRoot string
// ImportPath is the import path of the main package. This is useful for
// correctly printing test results: the import path isn't always the same as
// the path listed on the command line.
@@ -63,9 +74,8 @@ type BuildResult struct {
// implementation of an imported package changes.
type packageAction struct {
ImportPath string
CGoVersion int // cgo.Version
CompilerVersion int // compiler.Version
InterpVersion int // interp.Version
CompilerBuildID string
TinyGoVersion string
LLVMVersion string
Config *compiler.Config
CFlags []string
@@ -83,12 +93,32 @@ type packageAction struct {
// The error value may be of type *MultiError. Callers will likely want to check
// for this case and print such errors individually.
func Build(pkgName, outpath string, config *compileopts.Config, action func(BuildResult) error) error {
// Read the build ID of the tinygo binary.
// Used as a cache key for package builds.
compilerBuildID, err := ReadBuildID()
if err != nil {
return err
}
// Create a temporary directory for intermediary files.
dir, err := ioutil.TempDir("", "tinygo")
if err != nil {
return err
}
defer os.RemoveAll(dir)
if config.Options.Work {
fmt.Printf("WORK=%s\n", dir)
} else {
defer os.RemoveAll(dir)
}
// Look up the build cache directory, which is used to speed up incremental
// builds.
cacheDir := goenv.Get("GOCACHE")
if cacheDir == "off" {
// Use temporary build directory instead, effectively disabling the
// build cache.
cacheDir = dir
}
// Check for a libc dependency.
// As a side effect, this also creates the headers for the given libc, if
@@ -96,18 +126,23 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
root := goenv.Get("TINYGOROOT")
var libcDependencies []*compileJob
switch config.Target.Libc {
case "darwin-libSystem":
job := makeDarwinLibSystemJob(config, dir)
libcDependencies = append(libcDependencies, job)
case "musl":
job, err := Musl.load(config, dir)
job, unlock, err := Musl.load(config, dir)
if err != nil {
return err
}
defer unlock()
libcDependencies = append(libcDependencies, dummyCompileJob(filepath.Join(filepath.Dir(job.result), "crt1.o")))
libcDependencies = append(libcDependencies, job)
case "picolibc":
libcJob, err := Picolibc.load(config, dir)
libcJob, unlock, err := Picolibc.load(config, dir)
if err != nil {
return err
}
defer unlock()
libcDependencies = append(libcDependencies, libcJob)
case "wasi-libc":
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
@@ -116,10 +151,11 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
}
libcDependencies = append(libcDependencies, dummyCompileJob(path))
case "mingw-w64":
_, err := MinGW.load(config, dir)
_, unlock, err := MinGW.load(config, dir)
if err != nil {
return err
}
unlock()
libcDependencies = append(libcDependencies, makeMinGWExtraLibs(dir)...)
case "":
// no library specified, so nothing to do
@@ -139,7 +175,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
SizeLevel: sizeLevel,
Scheduler: config.Scheduler(),
FuncImplementation: config.FuncImplementation(),
AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.Target.DefaultStackSize,
NeedsStackObjects: config.NeedsStackObjects(),
@@ -175,6 +210,21 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
var packageJobs []*compileJob
packageBitcodePaths := make(map[string]string)
packageActionIDs := make(map[string]string)
if config.Options.GlobalValues["runtime"]["buildVersion"] == "" {
version := goenv.Version
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
version += "-" + goenv.GitSha1
}
if config.Options.GlobalValues == nil {
config.Options.GlobalValues = make(map[string]map[string]string)
}
if config.Options.GlobalValues["runtime"] == nil {
config.Options.GlobalValues["runtime"] = make(map[string]string)
}
config.Options.GlobalValues["runtime"]["buildVersion"] = version
}
for _, pkg := range lprogram.Sorted() {
pkg := pkg // necessary to avoid a race condition
@@ -188,9 +238,8 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// the parameters for the build.
actionID := packageAction{
ImportPath: pkg.ImportPath,
CGoVersion: cgo.Version,
CompilerVersion: compiler.Version,
InterpVersion: interp.Version,
CompilerBuildID: string(compilerBuildID),
TinyGoVersion: goenv.Version,
LLVMVersion: llvm.Version,
Config: compilerConfig,
CFlags: pkg.CFlags,
@@ -219,26 +268,22 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Determine the path of the bitcode file (which is a serialized version
// of a LLVM module).
cacheDir := goenv.Get("GOCACHE")
if cacheDir == "off" {
// Use temporary build directory instead, effectively disabling the
// build cache.
cacheDir = dir
}
bitcodePath := filepath.Join(cacheDir, "pkg-"+hex.EncodeToString(hash[:])+".bc")
packageBitcodePaths[pkg.ImportPath] = bitcodePath
// Check whether this package has been compiled before, and if so don't
// compile it again.
if _, err := os.Stat(bitcodePath); err == nil {
// Already cached, don't recreate this package.
continue
}
// The package has not yet been compiled, so create a job to do so.
job := &compileJob{
description: "compile package " + pkg.ImportPath,
run: func(*compileJob) error {
// Acquire a lock (if supported).
unlock := lock(bitcodePath + ".lock")
defer unlock()
if _, err := os.Stat(bitcodePath); err == nil {
// Already cached, don't recreate this package.
return nil
}
// Compile AST to IR. The compiler.CompilePackage function will
// build the SSA as needed.
mod, errs := compiler.CompilePackage(pkg.ImportPath, pkg, program.Package(pkg.Pkg), machine, compilerConfig, config.DumpSSA())
@@ -395,7 +440,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Load and link all the bitcode files. This does not yet optimize
// anything, it only links the bitcode files together.
ctx := llvm.NewContext()
mod = ctx.NewModule("")
mod = ctx.NewModule("main")
for _, pkg := range lprogram.Sorted() {
pkgMod, err := ctx.ParseBitcodeFile(packageBitcodePaths[pkg.ImportPath])
if err != nil {
@@ -414,7 +459,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
llvmInitFn.SetUnnamedAddr(true)
transform.AddStandardAttributes(llvmInitFn, config)
llvmInitFn.Param(0).SetName("context")
llvmInitFn.Param(1).SetName("parentHandle")
block := mod.Context().AddBasicBlock(llvmInitFn, "entry")
irbuilder := mod.Context().NewBuilder()
defer irbuilder.Dispose()
@@ -425,7 +469,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
if pkgInit.IsNil() {
panic("init not found for " + pkg.Pkg.Path())
}
irbuilder.CreateCall(pkgInit, []llvm.Value{llvm.Undef(i8ptrType), llvm.Undef(i8ptrType)}, "")
irbuilder.CreateCall(pkgInit, []llvm.Value{llvm.Undef(i8ptrType)}, "")
}
irbuilder.CreateRetVoid()
@@ -479,7 +523,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
outext := filepath.Ext(outpath)
if outext == ".o" || outext == ".bc" || outext == ".ll" {
// Run jobs to produce the LLVM module.
err := runJobs(programJob, config.Options.Parallelism)
err := runJobs(programJob, config.Options.Semaphore)
if err != nil {
return err
}
@@ -492,8 +536,14 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
}
return ioutil.WriteFile(outpath, llvmBuf.Bytes(), 0666)
case ".bc":
data := llvm.WriteBitcodeToMemoryBuffer(mod).Bytes()
return ioutil.WriteFile(outpath, data, 0666)
var buf llvm.MemoryBuffer
if config.UseThinLTO() {
buf = llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
} else {
buf = llvm.WriteBitcodeToMemoryBuffer(mod)
}
defer buf.Dispose()
return ioutil.WriteFile(outpath, buf.Bytes(), 0666)
case ".ll":
data := []byte(mod.String())
return ioutil.WriteFile(outpath, data, 0666)
@@ -513,10 +563,17 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
dependencies: []*compileJob{programJob},
result: objfile,
run: func(*compileJob) error {
llvmBuf, err := machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
if err != nil {
return err
var llvmBuf llvm.MemoryBuffer
if config.UseThinLTO() {
llvmBuf = llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
} else {
var err error
llvmBuf, err = machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
if err != nil {
return err
}
}
defer llvmBuf.Dispose()
return ioutil.WriteFile(objfile, llvmBuf.Bytes(), 0666)
},
}
@@ -533,10 +590,11 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Add compiler-rt dependency if needed. Usually this is a simple load from
// a cache.
if config.Target.RTLib == "compiler-rt" {
job, err := CompilerRT.load(config, dir)
job, unlock, err := CompilerRT.load(config, dir)
if err != nil {
return err
}
defer unlock()
linkerDependencies = append(linkerDependencies, job)
}
@@ -548,7 +606,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
job := &compileJob{
description: "compile extra file " + path,
run: func(job *compileJob) error {
result, err := compileAndCacheCFile(abspath, dir, config.CFlags(), config.Options.PrintCommands)
result, err := compileAndCacheCFile(abspath, dir, config.CFlags(), config.UseThinLTO(), config.Options.PrintCommands)
job.result = result
return err
},
@@ -566,7 +624,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
job := &compileJob{
description: "compile CGo file " + abspath,
run: func(job *compileJob) error {
result, err := compileAndCacheCFile(abspath, dir, pkg.CFlags, config.Options.PrintCommands)
result, err := compileAndCacheCFile(abspath, dir, pkg.CFlags, config.UseThinLTO(), config.Options.PrintCommands)
job.result = result
return err
},
@@ -635,6 +693,24 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
if config.Options.PrintCommands != nil {
config.Options.PrintCommands(config.Target.Linker, ldflags...)
}
if config.UseThinLTO() {
ldflags = append(ldflags,
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"),
"-plugin-opt=mcpu="+config.CPU(),
"-plugin-opt=O"+strconv.Itoa(optLevel),
"-plugin-opt=thinlto")
if config.CodeModel() != "default" {
ldflags = append(ldflags,
"-mllvm", "-code-model="+config.CodeModel())
}
if sizeLevel >= 2 {
// Workaround with roughly the same effect as
// https://reviews.llvm.org/D119342.
// Can hopefully be removed in LLVM 15.
ldflags = append(ldflags,
"-mllvm", "--rotation-max-header-size=0")
}
}
err = link(config.Target.Linker, ldflags...)
if err != nil {
return &commandError{"failed to link", executable, err}
@@ -740,7 +816,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Run all jobs to compile and link the program.
// Do this now (instead of after elf-to-hex and similar conversions) as it
// is simpler and cannot be parallelized.
err = runJobs(linkJob, config.Options.Parallelism)
err = runJobs(linkJob, config.Options.Semaphore)
if err != nil {
return err
}
@@ -765,7 +841,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
if err != nil {
return err
}
case "esp32", "esp32c3", "esp8266":
case "esp32", "esp32-img", "esp32c3", "esp8266":
// Special format for the ESP family of chips (parsed by the ROM
// bootloader).
tmppath = filepath.Join(dir, "main"+outext)
@@ -788,9 +864,19 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
default:
return fmt.Errorf("unknown output binary format: %s", outputBinaryFormat)
}
// If there's a module root, use that.
moduleroot := lprogram.MainPkg().Module.Dir
if moduleroot == "" {
// if not, just the regular root
moduleroot = lprogram.MainPkg().Root
}
return action(BuildResult{
Executable: executable,
Binary: tmppath,
MainDir: lprogram.MainPkg().Dir,
ModuleRoot: moduleroot,
ImportPath: lprogram.MainPkg().ImportPath,
})
}
@@ -816,7 +902,7 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
}
}
if config.GOOS() != "darwin" {
if config.GOOS() != "darwin" && !config.UseThinLTO() {
transform.ApplyFunctionSections(mod) // -ffunction-sections
}
@@ -1181,3 +1267,16 @@ func patchRP2040BootCRC(executable string) error {
// Update the .boot2 section to included the CRC
return replaceElfSection(executable, ".boot2", bytes)
}
// lock may acquire a lock at the specified path.
// It returns a function to release the lock.
// If flock is not supported, it does nothing.
func lock(path string) func() {
flock := flock.New(path)
err := flock.Lock()
if err != nil {
return func() {}
}
return func() { flock.Close() }
}
+12 -7
View File
@@ -5,6 +5,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/tinygo-org/tinygo/compileopts"
@@ -60,7 +61,11 @@ func TestClangAttributes(t *testing.T) {
{GOOS: "darwin", GOARCH: "arm64"},
{GOOS: "windows", GOARCH: "amd64"},
} {
t.Run("GOOS="+options.GOOS+",GOARCH="+options.GOARCH, func(t *testing.T) {
name := "GOOS=" + options.GOOS + ",GOARCH=" + options.GOARCH
if options.GOARCH == "arm" {
name += ",GOARM=" + options.GOARM
}
t.Run(name, func(t *testing.T) {
testClangAttributes(t, options)
})
}
@@ -131,12 +136,12 @@ func testClangAttributes(t *testing.T, options *compileopts.Options) {
t.Errorf("target has CPU %#v but Clang makes it CPU %#v", config.CPU(), cpu)
}
if features != config.Features() {
if llvm.Version != "11.0.0" {
// This needs to be removed once we switch to LLVM 12.
// LLVM 11.0.0 uses a different "target-features" string than LLVM
// 11.1.0 for Thumb targets. The Xtensa fork is still based on LLVM
// 11.0.0, so we need to skip this check on that version.
t.Errorf("target has LLVM features %#v but Clang makes it %#v", config.Features(), features)
if hasBuiltinTools || runtime.GOOS != "linux" {
// Skip this step when using an external Clang invocation on Linux.
// The reason is that Debian has patched Clang in a way that
// modifies the LLVM features string, changing lots of FPU/float
// related flags. We want to test vanilla Clang, not Debian Clang.
t.Errorf("target has LLVM features\n\t%#v\nbut Clang makes it\n\t%#v", config.Features(), features)
}
}
}
+103
View File
@@ -0,0 +1,103 @@
package builder
import (
"bytes"
"debug/elf"
"debug/macho"
"encoding/binary"
"fmt"
"io"
"os"
"runtime"
)
// ReadBuildID reads the build ID from the currently running executable.
func ReadBuildID() ([]byte, error) {
executable, err := os.Executable()
if err != nil {
return nil, err
}
f, err := os.Open(executable)
if err != nil {
return nil, err
}
defer f.Close()
switch runtime.GOOS {
case "linux", "freebsd":
// Read the GNU build id section. (Not sure about FreeBSD though...)
file, err := elf.NewFile(f)
if err != nil {
return nil, err
}
var gnuID, goID []byte
for _, section := range file.Sections {
if section.Type != elf.SHT_NOTE ||
(section.Name != ".note.gnu.build-id" && section.Name != ".note.go.buildid") {
continue
}
buf := make([]byte, section.Size)
n, err := section.ReadAt(buf, 0)
if uint64(n) != section.Size || err != nil {
return nil, fmt.Errorf("could not read build id: %w", err)
}
if section.Name == ".note.gnu.build-id" {
gnuID = buf
} else {
goID = buf
}
}
if gnuID != nil {
return gnuID, nil
} else if goID != nil {
return goID, nil
}
case "darwin":
// Read the LC_UUID load command, which contains the equivalent of a
// build ID.
file, err := macho.NewFile(f)
if err != nil {
return nil, err
}
for _, load := range file.Loads {
// Unfortunately, the debug/macho package doesn't support the
// LC_UUID command directly. So we have to read it from
// macho.LoadBytes.
load, ok := load.(macho.LoadBytes)
if !ok {
continue
}
raw := load.Raw()
command := binary.LittleEndian.Uint32(raw)
if command != 0x1b {
// Looking for the LC_UUID load command.
// LC_UUID is defined here as 0x1b:
// https://opensource.apple.com/source/xnu/xnu-4570.71.2/EXTERNAL_HEADERS/mach-o/loader.h.auto.html
continue
}
return raw[4:], nil
}
default:
// On other platforms (such as Windows) there isn't such a convenient
// build ID. Luckily, Go does have an equivalent of the build ID, which
// is stored as a special symbol named go.buildid. You can read it
// using `go tool buildid`, but the code below extracts it directly
// from the binary.
// Unfortunately, because of stripping with the -w flag, no symbol
// table might be available. Therefore, we have to scan the binary
// directly. Luckily the build ID is always at the start of the file.
// For details, see:
// https://github.com/golang/go/blob/master/src/cmd/internal/buildid/buildid.go
fileStart := make([]byte, 4096)
_, err := io.ReadFull(f, fileStart)
index := bytes.Index(fileStart, []byte("\xff Go build ID: \""))
if index < 0 || index > len(fileStart)-103 {
return nil, fmt.Errorf("could not find build id in %s", err)
}
buf := fileStart[index : index+103]
if bytes.HasPrefix(buf, []byte("\xff Go build ID: \"")) && bytes.HasSuffix(buf, []byte("\"\n \xff")) {
return buf[len("\xff Go build ID: \"") : len(buf)-1], nil
}
}
return nil, fmt.Errorf("could not find build ID in %s", executable)
}
+14 -1
View File
@@ -1,7 +1,11 @@
package builder
import (
"os"
"path/filepath"
"strings"
"github.com/tinygo-org/tinygo/goenv"
)
// These are the GENERIC_SOURCES according to CMakeList.txt.
@@ -72,6 +76,7 @@ var genericBuiltins = []string{
"floatunsisf.c",
"floatuntidf.c",
"floatuntisf.c",
"fp_mode.c",
//"int_util.c",
"lshrdi3.c",
"lshrti3.c",
@@ -161,7 +166,15 @@ var CompilerRT = Library{
cflags: func(target, headerPath string) []string {
return []string{"-Werror", "-Wall", "-std=c11", "-nostdlibinc"}
},
sourceDir: "lib/compiler-rt/lib/builtins",
sourceDir: func() string {
llvmDir := filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project/compiler-rt/lib/builtins")
if _, err := os.Stat(llvmDir); err == nil {
// Release build.
return llvmDir
}
// Development build.
return filepath.Join(goenv.Get("TINYGOROOT"), "lib/compiler-rt-builtins")
},
librarySources: func(target string) []string {
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
+18 -6
View File
@@ -56,13 +56,22 @@ import (
// depfile but without invalidating its name. For this reason, the depfile is
// written on each new compilation (even when it seems unnecessary). However, it
// could in rare cases lead to a stale file fetched from the cache.
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands func(string, ...string)) (string, error) {
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool, printCommands func(string, ...string)) (string, error) {
// Hash input file.
fileHash, err := hashFile(abspath)
if err != nil {
return "", err
}
// Acquire a lock (if supported).
unlock := lock(filepath.Join(goenv.Get("GOCACHE"), fileHash+".c.lock"))
defer unlock()
ext := ".o"
if thinlto {
ext = ".bc"
}
// Create cache key for the dependencies file.
buf, err := json.Marshal(struct {
Path string
@@ -95,7 +104,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
}
// Obtain hashes of all the files listed as a dependency.
outpath, err := makeCFileCachePath(dependencies, depfileNameHash)
outpath, err := makeCFileCachePath(dependencies, depfileNameHash, ext)
if err == nil {
if _, err := os.Stat(outpath); err == nil {
return outpath, nil
@@ -108,7 +117,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
return "", err
}
objTmpFile, err := ioutil.TempFile(goenv.Get("GOCACHE"), "tmp-*.o")
objTmpFile, err := ioutil.TempFile(goenv.Get("GOCACHE"), "tmp-*"+ext)
if err != nil {
return "", err
}
@@ -120,6 +129,9 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
depTmpFile.Close()
flags := append([]string{}, cflags...) // copy cflags
flags = append(flags, "-MD", "-MV", "-MTdeps", "-MF", depTmpFile.Name()) // autogenerate dependencies
if thinlto {
flags = append(flags, "-flto=thin")
}
flags = append(flags, "-c", "-o", objTmpFile.Name(), abspath)
if strings.ToLower(filepath.Ext(abspath)) == ".s" {
// If this is an assembly file (.s or .S, lowercase or uppercase), then
@@ -177,7 +189,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
}
// Move temporary object file to final location.
outpath, err := makeCFileCachePath(dependencySlice, depfileNameHash)
outpath, err := makeCFileCachePath(dependencySlice, depfileNameHash, ext)
if err != nil {
return "", err
}
@@ -192,7 +204,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
// Create a cache path (a path in GOCACHE) to store the output of a compiler
// job. This path is based on the dep file name (which is a hash of metadata
// including compiler flags) and the hash of all input files in the paths slice.
func makeCFileCachePath(paths []string, depfileNameHash string) (string, error) {
func makeCFileCachePath(paths []string, depfileNameHash, ext string) (string, error) {
// Hash all input files.
fileHashes := make(map[string]string, len(paths))
for _, path := range paths {
@@ -217,7 +229,7 @@ func makeCFileCachePath(paths []string, depfileNameHash string) (string, error)
outFileNameBuf := sha512.Sum512_224(buf)
cacheKey := hex.EncodeToString(outFileNameBuf[:])
outpath := filepath.Join(goenv.Get("GOCACHE"), "obj-"+cacheKey+".o")
outpath := filepath.Join(goenv.Get("GOCACHE"), "obj-"+cacheKey+ext)
return outpath, nil
}
+44 -40
View File
@@ -38,6 +38,7 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
@@ -51,7 +52,6 @@
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
@@ -115,29 +115,25 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Any DebugInfoKind implies GenDwarfForAssembly.
Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
OPT_compress_debug_sections_EQ)) {
if (A->getOption().getID() == OPT_compress_debug_sections) {
// TODO: be more clever about the compression type auto-detection
Opts.CompressDebugSections = llvm::DebugCompressionType::GNU;
} else {
Opts.CompressDebugSections =
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
.Case("none", llvm::DebugCompressionType::None)
.Case("zlib", llvm::DebugCompressionType::Z)
.Case("zlib-gnu", llvm::DebugCompressionType::GNU)
.Default(llvm::DebugCompressionType::None);
}
if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections_EQ)) {
Opts.CompressDebugSections =
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
.Case("none", llvm::DebugCompressionType::None)
.Case("zlib", llvm::DebugCompressionType::Z)
.Default(llvm::DebugCompressionType::None);
}
Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
Opts.DwarfDebugFlags =
std::string(Args.getLastArgValue(OPT_dwarf_debug_flags));
Opts.DwarfDebugProducer =
std::string(Args.getLastArgValue(OPT_dwarf_debug_producer));
Opts.DebugCompilationDir =
std::string(Args.getLastArgValue(OPT_fdebug_compilation_dir));
if (const Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ,
options::OPT_fdebug_compilation_dir_EQ))
Opts.DebugCompilationDir = A->getValue();
Opts.MainFileName = std::string(Args.getLastArgValue(OPT_main_file_name));
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
@@ -219,7 +215,7 @@ getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
std::error_code EC;
auto Out = std::make_unique<raw_fd_ostream>(
Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_Text));
Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_TextWithCRLF));
if (EC) {
Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
return nullptr;
@@ -228,7 +224,8 @@ getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
return Out;
}
bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
DiagnosticsEngine &Diags) {
// Get the target specific parser.
std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error);
@@ -236,7 +233,7 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
MemoryBuffer::getFileOrSTDIN(Opts.InputFile);
MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
if (std::error_code EC = Buffer.getError()) {
Error = EC.message();
@@ -277,11 +274,15 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
if (!Opts.SplitDwarfOutput.empty())
DwoOS = getOutputStream(Opts.SplitDwarfOutput, Diags, IsBinary);
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
// Build up the feature string from the target feature list.
std::string FS = llvm::join(Opts.Features, ",");
MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr, &MCOptions);
std::unique_ptr<MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
assert(STI && "Unable to create subtarget info!");
MCContext Ctx(Triple(Opts.Triple), MAI.get(), MRI.get(), STI.get(), &SrcMgr,
&MCOptions);
bool PIC = false;
if (Opts.RelocationModel == "static") {
@@ -294,7 +295,12 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
PIC = false;
}
MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, Ctx);
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
std::unique_ptr<MCObjectFileInfo> MOFI(
TheTarget->createMCObjectFileInfo(Ctx, PIC));
Ctx.setObjectFileInfo(MOFI.get());
if (Opts.SaveTemporaryLabels)
Ctx.setAllowTemporaryLabels(false);
if (Opts.GenDwarfForAssembly)
@@ -316,19 +322,16 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
if (!Opts.MainFileName.empty())
Ctx.setMainFileName(StringRef(Opts.MainFileName));
Ctx.setDwarfFormat(Opts.Dwarf64 ? dwarf::DWARF64 : dwarf::DWARF32);
Ctx.setDwarfVersion(Opts.DwarfVersion);
if (Opts.GenDwarfForAssembly)
Ctx.setGenDwarfRootFile(Opts.InputFile,
SrcMgr.getMemoryBuffer(BufferIndex)->getBuffer());
// Build up the feature string from the target feature list.
std::string FS = llvm::join(Opts.Features, ",");
std::unique_ptr<MCStreamer> Str;
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
std::unique_ptr<MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
assert(MCII && "Unable to create instruction info!");
raw_pwrite_stream *Out = FDOS.get();
std::unique_ptr<buffer_ostream> BOS;
@@ -367,6 +370,8 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
std::unique_ptr<MCAsmBackend> MAB(
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
assert(MAB && "Unable to create asm backend!");
std::unique_ptr<MCObjectWriter> OW =
DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS)
: MAB->createObjectWriter(*Out);
@@ -376,13 +381,12 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
/*DWARFMustBeAtTheEnd*/ true));
Str.get()->InitSections(Opts.NoExecStack);
Str.get()->initSections(Opts.NoExecStack, *STI);
}
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
// is emitted in __LLVM,__asm section if the object file is MachO format.
if (Opts.EmbedBitcode && Ctx.getObjectFileInfo()->getObjectFileType() ==
MCObjectFileInfo::IsMachO) {
if (Opts.EmbedBitcode && Ctx.getObjectFileType() == MCContext::IsMachO) {
MCSection *AsmLabel = Ctx.getMachOSection(
"__LLVM", "__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly());
Str.get()->SwitchSection(AsmLabel);
@@ -419,12 +423,12 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
Failed = Parser->Run(Opts.NoInitialTextSection);
}
// Close Streamer first.
// It might have a reference to the output stream.
Str.reset();
// Close the output stream early.
BOS.reset();
FDOS.reset();
return Failed;
}
bool ExecuteAssembler(AssemblerInvocation &Opts,
DiagnosticsEngine &Diags) {
bool Failed = ExecuteAssemblerImpl(Opts, Diags);
// Delete output file if there were errors.
if (Failed) {
@@ -437,7 +441,7 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
return Failed;
}
static void LLVMErrorHandler(void *UserData, const std::string &Message,
static void LLVMErrorHandler(void *UserData, const char *Message,
bool GenCrashDiag) {
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
@@ -472,7 +476,7 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
return 1;
if (Asm.ShowHelp) {
getDriverOptTable().PrintHelp(
getDriverOptTable().printHelp(
llvm::outs(), "clang -cc1as [options] file...",
"Clang Integrated Assembler",
/*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,
+2
View File
@@ -39,6 +39,7 @@ struct AssemblerInvocation {
unsigned SaveTemporaryLabels : 1;
unsigned GenDwarfForAssembly : 1;
unsigned RelaxELFRelocations : 1;
unsigned Dwarf64 : 1;
unsigned DwarfVersion;
std::string DwarfDebugFlags;
std::string DwarfDebugProducer;
@@ -108,6 +109,7 @@ public:
FatalWarnings = 0;
NoWarn = 0;
IncrementalLinkerCompatible = 0;
Dwarf64 = 0;
DwarfVersion = 0;
EmbedBitcode = 0;
}
+11 -1
View File
@@ -2,6 +2,7 @@ package builder
import (
"errors"
"fmt"
"os"
"os/exec"
"runtime"
@@ -25,7 +26,16 @@ func init() {
// Add the path to a Homebrew-installed LLVM for ease of use (no need to
// manually set $PATH).
if runtime.GOOS == "darwin" {
prefix := "/usr/local/opt/llvm@" + llvmMajor + "/bin/"
var prefix string
switch runtime.GOARCH {
case "amd64":
prefix = "/usr/local/opt/llvm@" + llvmMajor + "/bin/"
case "arm64":
prefix = "/opt/homebrew/opt/llvm@" + llvmMajor + "/bin/"
default:
// unknown GOARCH
panic(fmt.Sprintf("unknown GOARCH: %s on darwin", runtime.GOARCH))
}
commands["clang"] = append(commands["clang"], prefix+"clang-"+llvmMajor)
commands["ld.lld"] = append(commands["ld.lld"], prefix+"ld.lld")
commands["wasm-ld"] = append(commands["wasm-ld"], prefix+"wasm-ld")
+2 -2
View File
@@ -33,8 +33,8 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
if err != nil {
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
}
if major != 1 || minor < 15 || minor > 17 {
return nil, fmt.Errorf("requires go version 1.15 through 1.17, got go%d.%d", major, minor)
if major != 1 || minor < 15 || minor > 18 {
return nil, fmt.Errorf("requires go version 1.15 through 1.18, got go%d.%d", major, minor)
}
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
+63
View File
@@ -0,0 +1,63 @@
package builder
import (
"path/filepath"
"strings"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
"tinygo.org/x/go-llvm"
)
// Create a job that builds a Darwin libSystem.dylib stub library. This library
// contains all the symbols needed so that we can link against it, but it
// doesn't contain any real symbol implementations.
func makeDarwinLibSystemJob(config *compileopts.Config, tmpdir string) *compileJob {
return &compileJob{
description: "compile Darwin libSystem.dylib",
run: func(job *compileJob) (err error) {
arch := strings.Split(config.Triple(), "-")[0]
job.result = filepath.Join(tmpdir, "libSystem.dylib")
objpath := filepath.Join(tmpdir, "libSystem.o")
inpath := filepath.Join(goenv.Get("TINYGOROOT"), "lib/macos-minimal-sdk/src", arch, "libSystem.s")
// Compile assembly file to object file.
flags := []string{
"-nostdlib",
"--target=" + config.Triple(),
"-c",
"-o", objpath,
inpath,
}
if config.Options.PrintCommands != nil {
config.Options.PrintCommands("clang", flags...)
}
err = runCCompiler(flags...)
if err != nil {
return err
}
// Link object file to dynamic library.
platformVersion := strings.TrimPrefix(strings.Split(config.Triple(), "-")[2], "macosx")
flavor := "darwin"
if strings.Split(llvm.Version, ".")[0] < "13" {
flavor = "darwinnew" // needed on LLVM 12 and below
}
flags = []string{
"-flavor", flavor,
"-demangle",
"-dynamic",
"-dylib",
"-arch", arch,
"-platform_version", "macos", platformVersion, platformVersion,
"-install_name", "/usr/lib/libSystem.B.dylib",
"-o", job.result,
objpath,
}
if config.Options.PrintCommands != nil {
config.Options.PrintCommands("ld.lld", flags...)
}
return link("ld.lld", flags...)
},
}
}
+14
View File
@@ -84,6 +84,20 @@ func getClangHeaderPath(TINYGOROOT string) string {
}
}
// On Arch Linux, the clang executable is stored in /usr/bin rather than being symlinked from there.
// Search directly in /usr/lib for clang.
if matches, err := filepath.Glob("/usr/lib/clang/" + llvmMajor + ".*.*"); err == nil {
// Check for the highest version first.
sort.Strings(matches)
for i := len(matches) - 1; i >= 0; i-- {
path := filepath.Join(matches[i], "include")
_, err := os.Stat(filepath.Join(path, "stdint.h"))
if err == nil {
return path
}
}
}
// Could not find it.
return ""
}
+30 -3
View File
@@ -15,6 +15,7 @@ import (
"fmt"
"io/ioutil"
"sort"
"strings"
)
type espImageSegment struct {
@@ -78,15 +79,31 @@ func makeESPFirmareImage(infile, outfile, format string) error {
// An added benefit is that we don't need to check for errors all the time.
outf := &bytes.Buffer{}
// Separate esp32 and esp32-img. The -img suffix indicates we should make an
// image, not just a binary to be flashed at 0x1000 for example.
chip := format
makeImage := false
if strings.HasSuffix(format, "-img") {
makeImage = true
chip = format[:len(format)-len("-img")]
}
if makeImage {
// The bootloader starts at 0x1000, or 4096.
// TinyGo doesn't use a separate bootloader and runs the entire
// application in the bootloader location.
outf.Write(make([]byte, 4096))
}
// Chip IDs. Source:
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L22
chip_id := map[string]uint16{
"esp32": 0x0000,
"esp32c3": 0x0005,
}[format]
}[chip]
// Image header.
switch format {
switch chip {
case "esp32", "esp32c3":
// Header format:
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
@@ -155,12 +172,22 @@ func makeESPFirmareImage(infile, outfile, format string) error {
outf.Write(make([]byte, 15-outf.Len()%16))
outf.WriteByte(checksum)
if format != "esp8266" {
if chip != "esp8266" {
// SHA256 hash (to protect against image corruption, not for security).
hash := sha256.Sum256(outf.Bytes())
outf.Write(hash[:])
}
// QEMU (or more precisely, qemu-system-xtensa from Espressif) expects the
// image to be a certain size.
if makeImage {
// Use a default image size of 4MB.
grow := 4096*1024 - outf.Len()
if grow > 0 {
outf.Write(make([]byte, grow))
}
}
// Write the image to the output file.
return ioutil.WriteFile(outfile, outf.Bytes(), 0666)
}
+114 -84
View File
@@ -4,8 +4,12 @@ package builder
// parallel while taking care of dependencies.
import (
"container/heap"
"errors"
"fmt"
"runtime"
"sort"
"strings"
"time"
)
@@ -29,7 +33,6 @@ type compileJob struct {
dependencies []*compileJob
result string // result (path)
run func(*compileJob) (err error)
state jobState
err error // error if finished
duration time.Duration // how long it took to run this job (only set after finishing)
}
@@ -44,41 +47,20 @@ func dummyCompileJob(result string) *compileJob {
}
}
// readyToRun returns whether this job is ready to run: it is itself not yet
// started and all dependencies are finished.
func (job *compileJob) readyToRun() bool {
if job.state != jobStateQueued {
// Already running or finished, so shouldn't be run again.
return false
}
// Check dependencies.
for _, dep := range job.dependencies {
if dep.state != jobStateFinished {
// A dependency is not finished, so this job has to wait until it
// is.
return false
}
}
// All conditions are satisfied.
return true
}
// runJobs runs the indicated job and all its dependencies. For every job, all
// the dependencies are run first. It returns the error of the first job that
// fails.
// It runs all jobs in the order of the dependencies slice, depth-first.
// Therefore, if some jobs are preferred to run before others, they should be
// ordered as such in the job dependencies.
func runJobs(job *compileJob, parallelism int) error {
if parallelism == 0 {
// Have a default, if the parallelism isn't set. This is useful for
func runJobs(job *compileJob, sema chan struct{}) error {
if sema == nil {
// Have a default, if the semaphore isn't set. This is useful for
// tests.
parallelism = runtime.NumCPU()
sema = make(chan struct{}, runtime.NumCPU())
}
if parallelism < 1 {
return fmt.Errorf("-p flag must be at least 1, provided -p=%d", parallelism)
if cap(sema) == 0 {
return errors.New("cannot 0 jobs at a time")
}
// Create a slice of jobs to run, where all dependencies are run in order.
@@ -97,64 +79,91 @@ func runJobs(job *compileJob, parallelism int) error {
}
addJobs(job)
// Create channels to communicate with the workers.
doneChan := make(chan *compileJob)
workerChan := make(chan *compileJob)
defer close(workerChan)
// Start a number of workers.
for i := 0; i < parallelism; i++ {
if jobRunnerDebug {
fmt.Println("## starting worker", i)
waiting := make(map[*compileJob]map[*compileJob]struct{}, len(jobs))
dependents := make(map[*compileJob][]*compileJob, len(jobs))
jidx := make(map[*compileJob]int)
var ready intHeap
for i, job := range jobs {
jidx[job] = i
if len(job.dependencies) == 0 {
// This job is ready to run.
ready.Push(i)
continue
}
// Construct a map for dependencies which the job is currently waiting on.
waitDeps := make(map[*compileJob]struct{})
waiting[job] = waitDeps
// Add the job to the dependents list of each dependency.
for _, dep := range job.dependencies {
dependents[dep] = append(dependents[dep], job)
waitDeps[dep] = struct{}{}
}
go jobWorker(workerChan, doneChan)
}
// Create a channel to accept notifications of completion.
doneChan := make(chan *compileJob)
// Send each job in the jobs slice to a worker, taking care of job
// dependencies.
numRunningJobs := 0
var totalTime time.Duration
start := time.Now()
for {
// If there are free workers, try starting a new job (if one is
// available). If it succeeds, try again to fill the entire worker pool.
if numRunningJobs < parallelism {
jobToRun := nextJob(jobs)
if jobToRun != nil {
// Start job.
for len(ready.IntSlice) > 0 || numRunningJobs != 0 {
var completed *compileJob
if len(ready.IntSlice) > 0 {
select {
case sema <- struct{}{}:
// Start a job.
job := jobs[heap.Pop(&ready).(int)]
if jobRunnerDebug {
fmt.Println("## start: ", jobToRun.description)
fmt.Println("## start: ", job.description)
}
jobToRun.state = jobStateRunning
workerChan <- jobToRun
go runJob(job, doneChan)
numRunningJobs++
continue
case completed = <-doneChan:
// A job completed.
}
} else {
// Wait for a job to complete.
completed = <-doneChan
}
// When there are no jobs running, all jobs in the jobs slice must have
// been finished. Therefore, the work is done.
if numRunningJobs == 0 {
break
}
// Wait until a job is finished.
job := <-doneChan
job.state = jobStateFinished
numRunningJobs--
totalTime += job.duration
<-sema
if jobRunnerDebug {
fmt.Println("## finished:", job.description, "(time "+job.duration.String()+")")
}
if job.err != nil {
// Wait for running jobs to finish.
if completed.err != nil {
// Wait for any current jobs to finish.
for numRunningJobs != 0 {
<-doneChan
numRunningJobs--
}
// Return error of first failing job.
return job.err
// The build failed.
return completed.err
}
// Update total run time.
totalTime += completed.duration
// Update dependent jobs.
for _, j := range dependents[completed] {
wait := waiting[j]
delete(wait, completed)
if len(wait) == 0 {
// This job is now ready to run.
ready.Push(jidx[j])
delete(waiting, j)
}
}
}
if len(waiting) != 0 {
// There is a dependency cycle preventing some jobs from running.
return errDependencyCycle{waiting}
}
// Some statistics, if debugging.
@@ -171,29 +180,50 @@ func runJobs(job *compileJob, parallelism int) error {
return nil
}
// nextJob returns the first ready-to-run job.
// This is an implementation detail of runJobs.
func nextJob(jobs []*compileJob) *compileJob {
for _, job := range jobs {
if job.readyToRun() {
return job
}
}
return nil
type errDependencyCycle struct {
waiting map[*compileJob]map[*compileJob]struct{}
}
// jobWorker is the goroutine that runs received jobs.
// This is an implementation detail of runJobs.
func jobWorker(workerChan, doneChan chan *compileJob) {
for job := range workerChan {
start := time.Now()
if job.run != nil {
err := job.run(job)
if err != nil {
job.err = err
}
func (err errDependencyCycle) Error() string {
waits := make([]string, 0, len(err.waiting))
for j, wait := range err.waiting {
deps := make([]string, 0, len(wait))
for dep := range wait {
deps = append(deps, dep.description)
}
job.duration = time.Since(start)
doneChan <- job
sort.Strings(deps)
waits = append(waits, fmt.Sprintf("\t%s is waiting for [%s]",
j.description, strings.Join(deps, ", "),
))
}
sort.Strings(waits)
return "deadlock:\n" + strings.Join(waits, "\n")
}
type intHeap struct {
sort.IntSlice
}
func (h *intHeap) Push(x interface{}) {
h.IntSlice = append(h.IntSlice, x.(int))
}
func (h *intHeap) Pop() interface{} {
x := h.IntSlice[len(h.IntSlice)-1]
h.IntSlice = h.IntSlice[:len(h.IntSlice)-1]
return x
}
// runJob runs a compile job and notifies doneChan of completion.
func runJob(job *compileJob, doneChan chan *compileJob) {
start := time.Now()
if job.run != nil {
err := job.run(job)
if err != nil {
job.err = err
}
}
job.duration = time.Since(start)
doneChan <- job
}
+69 -17
View File
@@ -4,7 +4,9 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
@@ -22,8 +24,8 @@ type Library struct {
// cflags returns the C flags specific to this library
cflags func(target, headerPath string) []string
// The source directory, relative to TINYGOROOT.
sourceDir string
// The source directory.
sourceDir func() string
// The source files, relative to sourceDir.
librarySources func(target string) []string
@@ -36,11 +38,12 @@ type Library struct {
// The resulting directory may be stored in the provided tmpdir, which is
// expected to be removed after the Load call.
func (l *Library) Load(config *compileopts.Config, tmpdir string) (dir string, err error) {
job, err := l.load(config, tmpdir)
job, unlock, err := l.load(config, tmpdir)
if err != nil {
return "", err
}
err = runJobs(job, config.Options.Parallelism)
defer unlock()
err = runJobs(job, config.Options.Semaphore)
return filepath.Dir(job.result), err
}
@@ -52,28 +55,38 @@ func (l *Library) Load(config *compileopts.Config, tmpdir string) (dir string, e
// output archive file, it is expected to be removed after use.
// As a side effect, this call creates the library header files if they didn't
// exist yet.
func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJob, err error) {
func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJob, abortLock func(), err error) {
outdir, precompiled := config.LibcPath(l.name)
archiveFilePath := filepath.Join(outdir, "lib.a")
if precompiled {
// Found a precompiled library for this OS/architecture. Return the path
// directly.
return dummyCompileJob(archiveFilePath), nil
return dummyCompileJob(archiveFilePath), func() {}, nil
}
// Create a lock on the output (if supported).
// This is a bit messy, but avoids a deadlock because it is ordered consistently with other library loads within a build.
outname := filepath.Base(outdir)
unlock := lock(filepath.Join(goenv.Get("GOCACHE"), outname+".lock"))
var ok bool
defer func() {
if !ok {
unlock()
}
}()
// Try to fetch this library from the cache.
if _, err := os.Stat(archiveFilePath); err == nil {
return dummyCompileJob(archiveFilePath), nil
return dummyCompileJob(archiveFilePath), func() {}, nil
}
// Cache miss, build it now.
// Create the destination directory where the components of this library
// (lib.a file, include directory) are placed.
outname := filepath.Base(outdir)
err = os.MkdirAll(filepath.Join(goenv.Get("GOCACHE"), outname), 0o777)
if err != nil {
// Could not create directory (and not because it already exists).
return nil, err
return nil, nil, err
}
// Make headers if needed.
@@ -83,16 +96,36 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
if _, err = os.Stat(headerPath); err != nil {
temporaryHeaderPath, err := ioutil.TempDir(outdir, "include.tmp*")
if err != nil {
return nil, err
return nil, nil, err
}
defer os.RemoveAll(temporaryHeaderPath)
err = l.makeHeaders(target, temporaryHeaderPath)
if err != nil {
return nil, err
return nil, nil, err
}
err = os.Chmod(temporaryHeaderPath, 0o755) // TempDir uses 0o700 by default
if err != nil {
return nil, nil, err
}
err = os.Rename(temporaryHeaderPath, headerPath)
if err != nil {
return nil, err
switch {
case os.IsExist(err):
// Another invocation of TinyGo also seems to have already created the headers.
case runtime.GOOS == "windows" && os.IsPermission(err):
// On Windows, a rename with a destination directory that already
// exists does not result in an IsExist error, but rather in an
// access denied error. To be sure, check for this case by checking
// whether the target directory exists.
if _, err := os.Stat(headerPath); err == nil {
break
}
fallthrough
default:
return nil, nil, err
}
}
}
}
@@ -101,7 +134,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
dir := filepath.Join(tmpdir, "build-lib-"+l.name)
err = os.Mkdir(dir, 0777)
if err != nil {
return nil, err
return nil, nil, err
}
// Precalculate the flags to the compiler invocation.
@@ -120,7 +153,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
}
}
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft")
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
}
if strings.HasPrefix(target, "riscv32-") {
args = append(args, "-march=rv32imac", "-mabi=ilp32", "-fforce-enable-int128")
@@ -128,6 +161,14 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
if strings.HasPrefix(target, "riscv64-") {
args = append(args, "-march=rv64gc", "-mabi=lp64")
}
if strings.HasPrefix(target, "xtensa") {
// Hack to work around an issue in the Xtensa port:
// https://github.com/espressif/llvm-project/issues/52
// Hopefully this will be fixed soon (LLVM 14).
args = append(args, "-D__ELF__")
}
var once sync.Once
// Create job to put all the object files in a single archive. This archive
// file is the (static) library file.
@@ -136,6 +177,8 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
description: "ar " + l.name + "/lib.a",
result: filepath.Join(goenv.Get("GOCACHE"), outname, "lib.a"),
run: func(*compileJob) error {
defer once.Do(unlock)
// Create an archive of all object files.
f, err := ioutil.TempFile(outdir, "libc.a.tmp*")
if err != nil {
@@ -149,11 +192,17 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
if err != nil {
return err
}
err = os.Chmod(f.Name(), 0o644) // TempFile uses 0o600 by default
if err != nil {
return err
}
// Store this archive in the cache.
return os.Rename(f.Name(), archiveFilePath)
},
}
sourceDir := l.sourceDir()
// Create jobs to compile all sources. These jobs are depended upon by the
// archive job above, so must be run first.
for _, path := range l.librarySources(target) {
@@ -162,7 +211,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
for strings.HasPrefix(cleanpath, "../") {
cleanpath = cleanpath[3:]
}
srcpath := filepath.Join(goenv.Get("TINYGOROOT"), l.sourceDir, path)
srcpath := filepath.Join(sourceDir, path)
objpath := filepath.Join(dir, cleanpath+".o")
os.MkdirAll(filepath.Dir(objpath), 0o777)
objs = append(objs, objpath)
@@ -186,7 +235,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
// (It could be done in parallel with creating the ar file, but it probably
// won't make much of a difference in speed).
if l.crt1Source != "" {
srcpath := filepath.Join(goenv.Get("TINYGOROOT"), l.sourceDir, l.crt1Source)
srcpath := filepath.Join(sourceDir, l.crt1Source)
job.dependencies = append(job.dependencies, &compileJob{
description: "compile " + srcpath,
run: func(*compileJob) error {
@@ -207,5 +256,8 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
})
}
return job, nil
ok = true
return job, func() {
once.Do(unlock)
}, nil
}
+8 -3
View File
@@ -8,17 +8,22 @@ extern "C" {
bool tinygo_link_elf(int argc, char **argv) {
std::vector<const char*> args(argv, argv + argc);
return lld::elf::link(args, false, llvm::outs(), llvm::errs());
return lld::elf::link(args, llvm::outs(), llvm::errs(), false, false);
}
bool tinygo_link_macho(int argc, char **argv) {
std::vector<const char*> args(argv, argv + argc);
return lld::macho::link(args, llvm::outs(), llvm::errs(), false, false);
}
bool tinygo_link_mingw(int argc, char **argv) {
std::vector<const char*> args(argv, argv + argc);
return lld::mingw::link(args, false, llvm::outs(), llvm::errs());
return lld::mingw::link(args, llvm::outs(), llvm::errs(), false, false);
}
bool tinygo_link_wasm(int argc, char **argv) {
std::vector<const char*> args(argv, argv + argc);
return lld::wasm::link(args, false, llvm::outs(), llvm::errs());
return lld::wasm::link(args, llvm::outs(), llvm::errs(), false, false);
}
} // external "C"
+1
View File
@@ -26,6 +26,7 @@ var MinGW = Library{
_, err = io.Copy(outf, inf)
return err
},
sourceDir: func() string { return "" }, // unused
cflags: func(target, headerPath string) []string {
// No flags necessary because there are no files to compile.
return nil
+2 -1
View File
@@ -101,9 +101,10 @@ var Musl = Library{
"-I" + muslDir + "/src/internal",
"-I" + headerPath,
"-I" + muslDir + "/include",
"-fno-stack-protector",
}
},
sourceDir: "lib/musl/src",
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/musl/src") },
librarySources: func(target string) []string {
arch := compileopts.MuslArchitecture(target)
globs := []string{
+2 -2
View File
@@ -28,12 +28,12 @@ var Picolibc = Library{
"-DHAVE_ALIAS_ATTRIBUTE",
"-DTINY_STDIO",
"-nostdlibinc",
"-Xclang", "-internal-isystem", "-Xclang", picolibcDir + "/include",
"-isystem", picolibcDir + "/include",
"-I" + picolibcDir + "/tinystdio",
"-I" + headerPath,
}
},
sourceDir: "lib/picolibc/newlib/libc",
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib/libc") },
librarySources: func(target string) []string {
return picolibcSources
},
+84 -3
View File
@@ -4,6 +4,7 @@ import (
"bytes"
"debug/dwarf"
"debug/elf"
"debug/pe"
"encoding/binary"
"fmt"
"io"
@@ -96,6 +97,17 @@ const (
memoryStack
)
func (t memoryType) String() string {
return [...]string{
0: "-",
memoryCode: "code",
memoryData: "data",
memoryROData: "rodata",
memoryBSS: "bss",
memoryStack: "stack",
}[t]
}
// Regular expressions to match particular symbol names. These are not stored as
// DWARF variables because they have no mapping to source code global variables.
var (
@@ -356,6 +368,72 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
})
}
}
} else if file, err := pe.NewFile(f); err == nil {
// Read DWARF information. The error is intentionally ignored.
data, _ := file.DWARF()
if data != nil {
addresses, err = readProgramSizeFromDWARF(data, 0)
if err != nil {
// However, _do_ report an error here. Something must have gone
// wrong while trying to parse DWARF data.
return nil, err
}
}
// Read COFF sections.
optionalHeader := file.OptionalHeader.(*pe.OptionalHeader64)
for _, section := range file.Sections {
// For more information:
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_section_header
const (
IMAGE_SCN_CNT_CODE = 0x00000020
IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040
IMAGE_SCN_MEM_DISCARDABLE = 0x02000000
IMAGE_SCN_MEM_READ = 0x40000000
IMAGE_SCN_MEM_WRITE = 0x80000000
)
if section.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
// Debug sections, etc.
continue
}
address := uint64(section.VirtualAddress) + optionalHeader.ImageBase
if section.Characteristics&IMAGE_SCN_CNT_CODE != 0 {
// .text
sections = append(sections, memorySection{
Address: address,
Size: uint64(section.VirtualSize),
Type: memoryCode,
})
} else if section.Characteristics&IMAGE_SCN_CNT_INITIALIZED_DATA != 0 {
if section.Characteristics&IMAGE_SCN_MEM_WRITE != 0 {
// .data
sections = append(sections, memorySection{
Address: address,
Size: uint64(section.Size),
Type: memoryData,
})
if section.Size < section.VirtualSize {
// Equivalent of a .bss section.
// Note: because of how the PE/COFF format is
// structured, not all zero-initialized data is marked
// as such. A portion may be at the end of the .data
// section and is thus marked as initialized data.
sections = append(sections, memorySection{
Address: address + uint64(section.Size),
Size: uint64(section.VirtualSize) - uint64(section.Size),
Type: memoryBSS,
})
}
} else if section.Characteristics&IMAGE_SCN_MEM_READ != 0 {
// .rdata, .buildid, .pdata
sections = append(sections, memorySection{
Address: address,
Size: uint64(section.VirtualSize),
Type: memoryROData,
})
}
}
}
} else if file, err := wasm.Parse(f); err == nil {
// File is in WebAssembly format.
@@ -513,8 +591,11 @@ func readSection(section memorySection, addresses []addressLine, addSize func(st
// section. We start at the beginning.
addr := section.Address
sectionEnd := section.Address + section.Size
if sizesDebug {
fmt.Printf("%08x..%08x %5d: %s\n", addr, sectionEnd, section.Size, section.Type)
}
for _, line := range addresses {
if line.Address < section.Address || line.Address+line.Length >= sectionEnd {
if line.Address < section.Address || line.Address+line.Length > sectionEnd {
// Check that this line is entirely within the section.
// Don't bother dealing with line entries that cross sections (that
// seems rather unlikely anyway).
@@ -525,7 +606,7 @@ func readSection(section memorySection, addresses []addressLine, addSize func(st
// previous line entry.
addSize("(unknown)", line.Address-addr, false)
if sizesDebug {
fmt.Printf("%08x..%08x %4d: unknown (gap)\n", addr, line.Address, line.Address-addr)
fmt.Printf("%08x..%08x %5d: unknown (gap)\n", addr, line.Address, line.Address-addr)
}
}
if addr > line.Address+line.Length {
@@ -550,7 +631,7 @@ func readSection(section memorySection, addresses []addressLine, addSize func(st
// There is a gap at the end of the section.
addSize("(unknown)", sectionEnd-addr, false)
if sizesDebug {
fmt.Printf("%08x..%08x %4d: unknown (end)\n", addr, sectionEnd, sectionEnd-addr)
fmt.Printf("%08x..%08x %5d: unknown (end)\n", addr, sectionEnd, sectionEnd-addr)
}
}
}
+11 -2
View File
@@ -1,3 +1,4 @@
//go:build byollvm
// +build byollvm
package builder
@@ -13,6 +14,7 @@ import (
#include <stdlib.h>
bool tinygo_clang_driver(int argc, char **argv);
bool tinygo_link_elf(int argc, char **argv);
bool tinygo_link_macho(int argc, char **argv);
bool tinygo_link_mingw(int argc, char **argv);
bool tinygo_link_wasm(int argc, char **argv);
*/
@@ -26,8 +28,13 @@ const hasBuiltinTools = true
// linking statically with LLVM (with the byollvm build tag).
func RunTool(tool string, args ...string) error {
linker := "elf"
if tool == "ld.lld" && len(args) >= 2 && args[0] == "-m" && args[1] == "i386pep" {
linker = "mingw"
if tool == "ld.lld" && len(args) >= 2 {
if args[0] == "-m" && args[1] == "i386pep" {
linker = "mingw"
} else if args[0] == "-flavor" {
linker = args[1]
args = args[2:]
}
}
args = append([]string{"tinygo:" + tool}, args...)
@@ -47,6 +54,8 @@ func RunTool(tool string, args ...string) error {
ok = C.tinygo_clang_driver(C.int(len(args)), (**C.char)(buf))
case "ld.lld":
switch linker {
case "darwin", "darwinnew": // darwinnew is only needed for LLVM 12 and below
ok = C.tinygo_link_macho(C.int(len(args)), (**C.char)(buf))
case "elf":
ok = C.tinygo_link_elf(C.int(len(args)), (**C.char)(buf))
case "mingw":
+1
View File
@@ -1,3 +1,4 @@
//go:build !byollvm
// +build !byollvm
package builder
+83 -67
View File
@@ -14,6 +14,7 @@ package cgo
import (
"fmt"
"go/ast"
"go/parser"
"go/scanner"
"go/token"
"path/filepath"
@@ -25,12 +26,6 @@ import (
"golang.org/x/tools/go/ast/astutil"
)
// Version of the cgo package. It must be incremented whenever the cgo package
// is changed in a way that affects the output so that cached package builds
// will be invalidated.
// This version is independent of the TinyGo version number.
const Version = 1 // last change: run libclang once per Go file
// cgoPackage holds all CGo-related information of a package.
type cgoPackage struct {
generated *ast.File
@@ -162,6 +157,39 @@ typedef long long _Cgo_longlong;
typedef unsigned long long _Cgo_ulonglong;
`
// First part of the generated Go file. Written here as Go because that's much
// easier than constructing the entire AST in memory.
// The string/bytes functions below implement C.CString etc. To make sure the
// runtime doesn't need to know the C int type, lengths are converted to uintptr
// first.
// These functions will be modified to get a "C." prefix, so the source below
// doesn't reflect the final AST.
const generatedGoFilePrefix = `
import "unsafe"
var _ unsafe.Pointer
//go:linkname C.CString runtime.cgo_CString
func CString(string) *C.char
//go:linkname C.GoString runtime.cgo_GoString
func GoString(*C.char) string
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func __GoStringN(*C.char, uintptr) string
func GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func __GoBytes(unsafe.Pointer, uintptr) []byte
func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
`
// Process extracts `import "C"` statements from the AST, parses the comment
// with libclang, and modifies the AST to use this information. It returns a
// newly created *ast.File that should be added to the list of to-be-parsed
@@ -169,7 +197,7 @@ typedef unsigned long long _Cgo_ulonglong;
// 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
// returns these in the []error slice but still modifies the AST.
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string, clangHeaders string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
p := &cgoPackage{
currentDir: dir,
fset: fset,
@@ -202,58 +230,31 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
p.packageDir = filepath.Dir(packagePath)
// Construct a new in-memory AST for CGo declarations of this package.
unsafeImport := &ast.ImportSpec{
Path: &ast.BasicLit{
ValuePos: p.generatedPos,
Kind: token.STRING,
Value: "\"unsafe\"",
},
EndPos: p.generatedPos,
// The first part is written as Go code that is then parsed, but more code
// is added later to the AST to declare functions, globals, etc.
goCode := "package " + files[0].Name.Name + "\n\n" + generatedGoFilePrefix
p.generated, err = parser.ParseFile(fset, dir+"/!cgo.go", goCode, parser.ParseComments)
if err != nil {
// This is always a bug in the cgo package.
panic("unexpected error: " + err.Error())
}
p.generated = &ast.File{
Package: p.generatedPos,
Name: &ast.Ident{
NamePos: p.generatedPos,
Name: files[0].Name.Name,
},
Decls: []ast.Decl{
// import "unsafe"
&ast.GenDecl{
TokPos: p.generatedPos,
Tok: token.IMPORT,
Specs: []ast.Spec{
unsafeImport,
},
},
// var _ unsafe.Pointer
// This avoids type errors when the unsafe package is never used.
&ast.GenDecl{
Tok: token.VAR,
Specs: []ast.Spec{
&ast.ValueSpec{
Names: []*ast.Ident{
{
Name: "_",
Obj: &ast.Object{
Kind: ast.Var,
Name: "_",
},
},
},
Type: &ast.SelectorExpr{
X: &ast.Ident{
Name: "unsafe",
},
Sel: &ast.Ident{
Name: "Pointer",
},
},
},
},
},
},
Imports: []*ast.ImportSpec{unsafeImport},
// If the Comments field is not set to nil, the fmt package will get
// confused about where comments should go.
p.generated.Comments = nil
// Adjust some of the functions in there.
for _, decl := range p.generated.Decls {
switch decl := decl.(type) {
case *ast.FuncDecl:
switch decl.Name.Name {
case "CString", "GoString", "GoStringN", "__GoStringN", "GoBytes", "__GoBytes":
// Adjust the name to have a "C." prefix so it is correctly
// resolved.
decl.Name.Name = "C." + decl.Name.Name
}
}
}
// Patch some types, for example *C.char in C.CString.
astutil.Apply(p.generated, p.walker, nil)
// Find all C.* symbols.
for _, f := range files {
@@ -332,6 +333,9 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
// have better alternatives anyway.
cflagsForCGo := append([]string{"-D_FORTIFY_SOURCE=0"}, cflags...)
cflagsForCGo = append(cflagsForCGo, p.cflags...)
if clangHeaders != "" {
cflagsForCGo = append(cflagsForCGo, "-isystem", clangHeaders)
}
// Process CGo imports for each file.
for i, f := range files {
@@ -496,6 +500,14 @@ func (p *cgoPackage) addFuncDecls() {
}
args := make([]*ast.Field, len(fn.args))
decl := &ast.FuncDecl{
Doc: &ast.CommentGroup{
List: []*ast.Comment{
{
Slash: fn.pos - 1,
Text: "//export " + name,
},
},
},
Name: &ast.Ident{
NamePos: fn.pos,
Name: "C." + name,
@@ -512,14 +524,10 @@ func (p *cgoPackage) addFuncDecls() {
},
}
if fn.variadic {
decl.Doc = &ast.CommentGroup{
List: []*ast.Comment{
{
Slash: fn.pos,
Text: "//go:variadic",
},
},
}
decl.Doc.List = append(decl.Doc.List, &ast.Comment{
Slash: fn.pos - 1,
Text: "//go:variadic",
})
}
obj.Decl = decl
for i, arg := range fn.args {
@@ -652,13 +660,21 @@ func (p *cgoPackage) addVarDecls() {
}
sort.Strings(names)
for _, name := range names {
global := p.globals[name]
gen := &ast.GenDecl{
TokPos: token.NoPos,
TokPos: global.pos,
Tok: token.VAR,
Lparen: token.NoPos,
Rparen: token.NoPos,
Doc: &ast.CommentGroup{
List: []*ast.Comment{
{
Slash: global.pos - 1,
Text: "//go:extern " + name,
},
},
},
}
global := p.globals[name]
obj := &ast.Object{
Kind: ast.Var,
Name: "C." + name,
+9 -2
View File
@@ -30,7 +30,14 @@ func normalizeResult(result string) string {
func TestCGo(t *testing.T) {
var cflags = []string{"--target=armv6m-unknown-unknown-eabi"}
for _, name := range []string{"basic", "errors", "types", "flags", "const"} {
for _, name := range []string{
"basic",
"errors",
"types",
"symbols",
"flags",
"const",
} {
name := name // avoid a race condition
t.Run(name, func(t *testing.T) {
// Skip tests that require specific Go version.
@@ -56,7 +63,7 @@ func TestCGo(t *testing.T) {
}
// Process the AST with CGo.
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags)
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags, "")
// Check the AST for type errors.
var typecheckErrors []error
+1 -1
View File
@@ -16,7 +16,7 @@ import (
)
/*
#include <clang-c/Index.h> // if this fails, install libclang-11-dev
#include <clang-c/Index.h> // If this fails, libclang headers aren't available. Please take a look here: https://tinygo.org/docs/guides/build/
#include <stdlib.h>
#include <stdint.h>
-13
View File
@@ -1,13 +0,0 @@
// +build !byollvm
package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-11/include
#cgo darwin CFLAGS: -I/usr/local/opt/llvm@11/include
#cgo freebsd CFLAGS: -I/usr/local/llvm11/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-11/lib -lclang
#cgo darwin LDFLAGS: -L/usr/local/opt/llvm@11/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm11/lib -lclang
*/
import "C"
+16
View File
@@ -0,0 +1,16 @@
//go:build !byollvm && llvm11
// +build !byollvm,llvm11
package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-11/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@11/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@11/include
#cgo freebsd CFLAGS: -I/usr/local/llvm11/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-11/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@11/lib -lclang -lffi
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@11/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm11/lib -lclang
*/
import "C"
+16
View File
@@ -0,0 +1,16 @@
//go:build !byollvm && llvm12
// +build !byollvm,llvm12
package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-12/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@12/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@12/include
#cgo freebsd CFLAGS: -I/usr/local/llvm12/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-12/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@12/lib -lclang -lffi
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@12/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm12/lib -lclang
*/
import "C"
+16
View File
@@ -0,0 +1,16 @@
//go:build !byollvm && !llvm11 && !llvm12 && !llvm14
// +build !byollvm,!llvm11,!llvm12,!llvm14
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"
+16
View File
@@ -0,0 +1,16 @@
//go:build !byollvm && llvm14
// +build !byollvm,llvm14
package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-14/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@14/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@14/include
#cgo freebsd CFLAGS: -I/usr/local/llvm14/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-14/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@14/lib -lclang -lffi
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@14/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm14/lib -lclang
*/
import "C"
+1 -1
View File
@@ -3,7 +3,7 @@
// are slightly different from the ones defined in libclang.go, but they
// should be ABI compatible.
#include <clang-c/Index.h> // if this fails, install libclang-11-dev
#include <clang-c/Index.h> // If this fails, libclang headers aren't available. Please take a look here: https://tinygo.org/docs/guides/build/
CXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu) {
return clang_getTranslationUnitCursor(tu);
+20
View File
@@ -4,6 +4,26 @@ import "unsafe"
var _ unsafe.Pointer
//go:linkname C.CString runtime.cgo_CString
func C.CString(string) *C.char
//go:linkname C.GoString runtime.cgo_GoString
func C.GoString(*C.char) string
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func C.__GoStringN(*C.char, uintptr) string
func C.GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
type C.int16_t = int16
type C.int32_t = int32
type C.int64_t = int64
+20
View File
@@ -4,6 +4,26 @@ import "unsafe"
var _ unsafe.Pointer
//go:linkname C.CString runtime.cgo_CString
func C.CString(string) *C.char
//go:linkname C.GoString runtime.cgo_GoString
func C.GoString(*C.char) string
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func C.__GoStringN(*C.char, uintptr) string
func C.GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
const C.bar = C.foo
const C.foo = 3
+20
View File
@@ -18,6 +18,26 @@ import "unsafe"
var _ unsafe.Pointer
//go:linkname C.CString runtime.cgo_CString
func C.CString(string) *C.char
//go:linkname C.GoString runtime.cgo_GoString
func C.GoString(*C.char) string
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func C.__GoStringN(*C.char, uintptr) string
func C.GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
const C.SOME_CONST_3 = 1234
type C.int16_t = int16
+20
View File
@@ -9,6 +9,26 @@ import "unsafe"
var _ unsafe.Pointer
//go:linkname C.CString runtime.cgo_CString
func C.CString(string) *C.char
//go:linkname C.GoString runtime.cgo_GoString
func C.GoString(*C.char) string
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func C.__GoStringN(*C.char, uintptr) string
func C.GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
const C.BAR = 3
const C.FOO_H = 1
+23
View File
@@ -0,0 +1,23 @@
package main
/*
// Function signatures.
int foo(int a, int b);
void variadic0();
void variadic2(int x, int y, ...);
// Global variable signatures.
extern int someValue;
*/
import "C"
// Test function signatures.
func accessFunctions() {
C.foo(3, 4)
C.variadic0()
C.variadic2(3, 5)
}
func accessGlobals() {
_ = C.someValue
}
+64
View File
@@ -0,0 +1,64 @@
package main
import "unsafe"
var _ unsafe.Pointer
//go:linkname C.CString runtime.cgo_CString
func C.CString(string) *C.char
//go:linkname C.GoString runtime.cgo_GoString
func C.GoString(*C.char) string
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func C.__GoStringN(*C.char, uintptr) string
func C.GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
//export foo
func C.foo(a C.int, b C.int) C.int
//export variadic0
//go:variadic
func C.variadic0()
//export variadic2
//go:variadic
func C.variadic2(x C.int, y C.int)
var C.foo$funcaddr unsafe.Pointer
var C.variadic0$funcaddr unsafe.Pointer
var C.variadic2$funcaddr unsafe.Pointer
//go:extern someValue
var C.someValue C.int
type C.int16_t = int16
type C.int32_t = int32
type C.int64_t = int64
type C.int8_t = int8
type C.uint16_t = uint16
type C.uint32_t = uint32
type C.uint64_t = uint64
type C.uint8_t = uint8
type C.uintptr_t = uintptr
type C.char uint8
type C.int int32
type C.long int32
type C.longlong int64
type C.schar int8
type C.short int16
type C.uchar uint8
type C.uint uint32
type C.ulong uint32
type C.ulonglong uint64
type C.ushort uint16
-10
View File
@@ -104,10 +104,6 @@ typedef struct {
unsigned char e : 3;
// Note that C++ allows bitfields bigger than the underlying type.
} bitfield_t;
// Function signatures.
void variadic0();
void variadic2(int x, int y, ...);
*/
import "C"
@@ -171,9 +167,3 @@ func accessUnion() {
var _ *C.int = union2d.unionfield_i()
var _ *[2]float64 = union2d.unionfield_d()
}
// Test function signatures.
func accessFunctions() {
C.variadic0()
C.variadic2(3, 5)
}
+19 -4
View File
@@ -4,10 +4,25 @@ import "unsafe"
var _ unsafe.Pointer
func C.variadic0() //go:variadic
func C.variadic2(x C.int, y C.int) //go:variadic
var C.variadic0$funcaddr unsafe.Pointer
var C.variadic2$funcaddr unsafe.Pointer
//go:linkname C.CString runtime.cgo_CString
func C.CString(string) *C.char
//go:linkname C.GoString runtime.cgo_GoString
func C.GoString(*C.char) string
//go:linkname C.__GoStringN runtime.cgo_GoStringN
func C.__GoStringN(*C.char, uintptr) string
func C.GoStringN(cstr *C.char, length C.int) string {
return C.__GoStringN(cstr, uintptr(length))
}
//go:linkname C.__GoBytes runtime.cgo_GoBytes
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length))
}
const C.option2A = 20
const C.optionA = 0
+123 -44
View File
@@ -10,6 +10,7 @@ import (
"regexp"
"strings"
"github.com/google/shlex"
"github.com/tinygo-org/tinygo/goenv"
)
@@ -85,7 +86,7 @@ func (c *Config) CgoEnabled() bool {
}
// GC returns the garbage collection strategy in use on this platform. Valid
// values are "none", "leaking", "extalloc", and "conservative".
// values are "none", "leaking", and "conservative".
func (c *Config) GC() string {
if c.Options.GC != "" {
return c.Options.GC
@@ -100,7 +101,7 @@ func (c *Config) GC() string {
// that can be traced by the garbage collector.
func (c *Config) NeedsStackObjects() bool {
switch c.GC() {
case "conservative", "extalloc":
case "conservative":
for _, tag := range c.BuildTags() {
if tag == "tinygo.wasm" {
return true
@@ -114,7 +115,7 @@ func (c *Config) NeedsStackObjects() bool {
}
// Scheduler returns the scheduler implementation. Valid values are "none",
//"coroutines" and "tasks".
// "asyncify" and "tasks".
func (c *Config) Scheduler() string {
if c.Options.Scheduler != "" {
return c.Options.Scheduler
@@ -122,8 +123,8 @@ func (c *Config) Scheduler() string {
if c.Target.Scheduler != "" {
return c.Target.Scheduler
}
// Fall back to coroutines, which are supported everywhere.
return "coroutines"
// Fall back to none.
return "none"
}
// Serial returns the serial implementation for this build configuration: uart,
@@ -159,31 +160,6 @@ func (c *Config) OptLevels() (optLevel, sizeLevel int, inlinerThreshold uint) {
}
}
// FuncImplementation picks an appropriate func value implementation for the
// target.
func (c *Config) FuncImplementation() string {
switch c.Scheduler() {
case "tasks", "asyncify":
// A func value is implemented as a pair of pointers:
// {context, function pointer}
// where the context may be a pointer to a heap-allocated struct
// containing the free variables, or it may be undef if the function
// being pointed to doesn't need a context. The function pointer is a
// regular function pointer.
return "doubleword"
case "none", "coroutines":
// As "doubleword", but with the function pointer replaced by a unique
// ID per function signature. Function values are called by using a
// switch statement and choosing which function to call.
// Pick the switch implementation with the coroutines scheduler, as it
// allows the use of blocking inside a function that is used as a func
// value.
return "switch"
default:
panic("unknown scheduler type")
}
}
// PanicStrategy returns the panic strategy selected for this target. Valid
// values are "print" (print the panic value, then exit) or "trap" (issue a trap
// instruction).
@@ -201,6 +177,34 @@ func (c *Config) AutomaticStackSize() bool {
return false
}
// UseThinLTO returns whether ThinLTO should be used for the given target. Some
// targets (such as wasm) are not yet supported.
// We should try and remove as many exceptions as possible in the future, so
// that this optimization can be applied in more places.
func (c *Config) UseThinLTO() bool {
parts := strings.Split(c.Triple(), "-")
if parts[0] == "wasm32" {
// wasm-ld doesn't seem to support ThinLTO yet.
return false
}
if parts[0] == "avr" || parts[0] == "xtensa" {
// These use external (GNU) linkers which might perhaps support ThinLTO
// through a plugin, but it's too much hassle to set up.
return false
}
if len(parts) >= 2 && strings.HasPrefix(parts[2], "macos") {
// We use an external linker here at the moment.
return false
}
if len(parts) >= 2 && parts[2] == "windows" {
// Linker error (undefined runtime.trackedGlobalsBitmap) when linking
// for Windows. Disable it for now until that's figured out and fixed.
return false
}
// Other architectures support ThinLTO.
return true
}
// RP2040BootPatch returns whether the RP2040 boot patch should be applied that
// calculates and patches in the checksum for the 2nd stage bootloader.
func (c *Config) RP2040BootPatch() bool {
@@ -224,8 +228,13 @@ func MuslArchitecture(triple string) string {
// a precompiled libc shipped with a TinyGo build, or a libc path in the cache
// directory (which might not yet be built).
func (c *Config) LibcPath(name string) (path string, precompiled bool) {
archname := c.Triple()
if c.CPU() != "" {
archname += "-" + c.CPU()
}
// Try to load a precompiled library.
precompiledDir := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", c.Triple(), name)
precompiledDir := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", archname, name)
if _, err := os.Stat(precompiledDir); err == nil {
// Found a precompiled library for this OS/architecture. Return the path
// directly.
@@ -234,13 +243,30 @@ func (c *Config) LibcPath(name string) (path string, precompiled bool) {
// No precompiled library found. Determine the path name that will be used
// in the build cache.
var outname string
if c.CPU() != "" {
outname = name + "-" + c.Triple() + "-" + c.CPU()
} else {
outname = name + "-" + c.Triple()
return filepath.Join(goenv.Get("GOCACHE"), name+"-"+archname), false
}
// DefaultBinaryExtension returns the default extension for binaries, such as
// .exe, .wasm, or no extension (depending on the target).
func (c *Config) DefaultBinaryExtension() string {
parts := strings.Split(c.Triple(), "-")
if parts[0] == "wasm32" {
// WebAssembly files always have the .wasm file extension.
return ".wasm"
}
return filepath.Join(goenv.Get("GOCACHE"), outname), false
if len(parts) >= 3 && parts[2] == "windows" {
// Windows uses .exe.
return ".exe"
}
if len(parts) >= 3 && parts[2] == "unknown" {
// There appears to be a convention to use the .elf file extension for
// ELF files intended for microcontrollers. I'm not aware of the origin
// of this, it's just something that is used by many projects.
// I think it's a good tradition, so let's keep it.
return ".elf"
}
// Linux, MacOS, etc, don't use a file extension. Use it as a fallback.
return ""
}
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo
@@ -251,23 +277,30 @@ func (c *Config) CFlags() []string {
cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT")))
}
switch c.Target.Libc {
case "darwin-libSystem":
root := goenv.Get("TINYGOROOT")
cflags = append(cflags,
"--sysroot="+filepath.Join(root, "lib/macos-minimal-sdk/src"),
)
case "picolibc":
root := goenv.Get("TINYGOROOT")
picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc")
path, _ := c.LibcPath("picolibc")
cflags = append(cflags,
"--sysroot="+path,
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "include"),
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "tinystdio"),
"-isystem", filepath.Join(path, "include"), // necessary for Xtensa
"-isystem", filepath.Join(picolibcDir, "include"),
"-isystem", filepath.Join(picolibcDir, "tinystdio"),
)
case "musl":
root := goenv.Get("TINYGOROOT")
path, _ := c.LibcPath("musl")
arch := MuslArchitecture(c.Triple())
cflags = append(cflags,
"--sysroot="+path,
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "musl", "arch", arch),
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "musl", "include"),
"-nostdlibinc",
"-isystem", filepath.Join(path, "include"),
"-isystem", filepath.Join(root, "lib", "musl", "arch", arch),
"-isystem", filepath.Join(root, "lib", "musl", "include"),
)
case "wasi-libc":
root := goenv.Get("TINYGOROOT")
@@ -277,8 +310,8 @@ func (c *Config) CFlags() []string {
path, _ := c.LibcPath("mingw-w64")
cflags = append(cflags,
"--sysroot="+path,
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "crt"),
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "defaults", "include"),
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "crt"),
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "defaults", "include"),
"-D_UCRT",
)
case "":
@@ -362,6 +395,13 @@ func (c *Config) BinaryFormat(ext string) string {
return c.Target.BinaryFormat
}
return "bin"
case ".img":
// Image file. Only defined for the ESP32 at the moment, where it is a
// full (runnable) image that can be used in the Espressif QEMU fork.
if c.Target.BinaryFormat != "" {
return c.Target.BinaryFormat + "-img"
}
return "bin"
case ".hex":
// Similar to bin, but includes the start address and is thus usually a
// better format.
@@ -462,6 +502,45 @@ func (c *Config) WasmAbi() string {
return c.Target.WasmAbi
}
// EmulatorName is a shorthand to get the command for this emulator, something
// like qemu-system-arm or simavr.
func (c *Config) EmulatorName() string {
parts := strings.SplitN(c.Target.Emulator, " ", 2)
if len(parts) > 1 {
return parts[0]
}
return ""
}
// EmulatorFormat returns the binary format for the emulator and the associated
// file extension. An empty string means to pass directly whatever the linker
// produces directly without conversion (usually ELF format).
func (c *Config) EmulatorFormat() (format, fileExt string) {
switch {
case strings.Contains(c.Target.Emulator, "{img}"):
return "img", ".img"
default:
return "", ""
}
}
// Emulator returns a ready-to-run command to run the given binary in an
// emulator. Give it the format (returned by EmulatorFormat()) and the path to
// the compiled binary.
func (c *Config) Emulator(format, binary string) ([]string, error) {
parts, err := shlex.Split(c.Target.Emulator)
if err != nil {
return nil, fmt.Errorf("could not parse emulator command: %w", err)
}
var emulator []string
for _, s := range parts {
s = strings.ReplaceAll(s, "{root}", goenv.Get("TINYGOROOT"))
s = strings.ReplaceAll(s, "{"+format+"}", binary)
emulator = append(emulator, s)
}
return emulator, nil
}
type TestConfig struct {
CompileTestBinary bool
// TODO: Filter the test functions to run, include verbose flag, etc
+7 -4
View File
@@ -7,8 +7,8 @@ import (
)
var (
validGCOptions = []string{"none", "leaking", "extalloc", "conservative"}
validSchedulerOptions = []string{"none", "tasks", "coroutines", "asyncify"}
validGCOptions = []string{"none", "leaking", "conservative"}
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
validSerialOptions = []string{"none", "uart", "usb"}
validPrintSizeOptions = []string{"none", "short", "full"}
validPanicStrategyOptions = []string{"print", "trap"}
@@ -28,11 +28,12 @@ type Options struct {
PanicStrategy string
Scheduler string
Serial string
Work bool // -work flag to print temporary build directory
PrintIR bool
DumpSSA bool
VerifyIR bool
PrintCommands func(cmd string, args ...string)
Parallelism int // -p flag
PrintCommands func(cmd string, args ...string) `json:"-"`
Semaphore chan struct{} `json:"-"` // -p flag controls cap
Debug bool
PrintSizes string
PrintAllocs *regexp.Regexp // regexp string
@@ -44,6 +45,8 @@ type Options struct {
Programmer string
OpenOCDCommands []string
LLVMFeatures string
Directory string
PrintJSON bool
}
// Verify performs a validation on the given options, raising an error if options are not valid.
+2 -14
View File
@@ -9,8 +9,8 @@ import (
func TestVerifyOptions(t *testing.T) {
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, extalloc, conservative`)
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, coroutines, asyncify`)
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, conservative`)
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, asyncify`)
expectedPrintSizeError := errors.New(`invalid size option 'incorrect': valid values are none, short, full`)
expectedPanicStrategyError := errors.New(`invalid panic option 'incorrect': valid values are print, trap`)
@@ -42,12 +42,6 @@ func TestVerifyOptions(t *testing.T) {
GC: "leaking",
},
},
{
name: "GCOptionExtalloc",
opts: compileopts.Options{
GC: "extalloc",
},
},
{
name: "GCOptionConservative",
opts: compileopts.Options{
@@ -73,12 +67,6 @@ func TestVerifyOptions(t *testing.T) {
Scheduler: "tasks",
},
},
{
name: "SchedulerOptionCoroutines",
opts: compileopts.Options{
Scheduler: "coroutines",
},
},
{
name: "InvalidPrintSizeOption",
opts: compileopts.Options{
+52 -26
View File
@@ -12,9 +12,11 @@ import (
"path/filepath"
"reflect"
"runtime"
"strconv"
"strings"
"github.com/tinygo-org/tinygo/goenv"
"tinygo.org/x/go-llvm"
)
// Target specification for a given target. Used for bare metal targets.
@@ -42,8 +44,8 @@ type TargetSpec struct {
LDFlags []string `json:"ldflags"`
LinkerScript string `json:"linkerscript"`
ExtraFiles []string `json:"extra-files"`
RP2040BootPatch *bool `json:"rp2040-boot-patch"` // Patch RP2040 2nd stage bootloader checksum
Emulator []string `json:"emulator" override:"copy"` // inherited Emulator must not be append
RP2040BootPatch *bool `json:"rp2040-boot-patch"` // Patch RP2040 2nd stage bootloader checksum
Emulator string `json:"emulator"`
FlashCommand string `json:"flash-command"`
GDB []string `json:"gdb"`
PortReset string `json:"flash-1200-bps-reset"`
@@ -57,6 +59,7 @@ type TargetSpec struct {
OpenOCDTarget string `json:"openocd-target"`
OpenOCDTransport string `json:"openocd-transport"`
OpenOCDCommands []string `json:"openocd-commands"`
OpenOCDVerify *bool `json:"openocd-verify"` // enable verify when flashing with openocd
JLinkDevice string `json:"jlink-device"`
CodeModel string `json:"code-model"`
RelocationModel string `json:"relocation-model"`
@@ -87,19 +90,8 @@ func (spec *TargetSpec) overrideProperties(child *TargetSpec) {
if !src.IsNil() {
dst.Set(src)
}
case reflect.Slice: // for slices...
if src.Len() > 0 { // ... if not empty ...
switch tag := field.Tag.Get("override"); tag {
case "copy":
// copy the field of child to spec
dst.Set(src)
case "append", "":
// or append the field of child to spec
dst.Set(reflect.AppendSlice(dst, src))
default:
panic("override mode must be 'copy' or 'append' (default). I don't know how to '" + tag + "'.")
}
}
case reflect.Slice: // for slices, append the field
dst.Set(reflect.AppendSlice(dst, src))
default:
panic("unknown field type : " + kind.String())
}
@@ -256,21 +248,34 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
spec.Features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
case "arm":
spec.CPU = "generic"
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
switch strings.Split(triple, "-")[0] {
case "armv5":
spec.Features = "+armv5t,+strict-align,-thumb-mode"
spec.Features = "+armv5t,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
case "armv6":
spec.Features = "+armv6,+dsp,+fp64,+strict-align,+vfp2,+vfp2sp,-thumb-mode"
spec.Features = "+armv6,+dsp,+fp64,+strict-align,+vfp2,+vfp2sp,-aes,-d32,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-neon,-sha2,-thumb-mode,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
case "armv7":
spec.Features = "+armv7-a,+dsp,+fp64,+vfp2,+vfp2sp,+vfp3d16,+vfp3d16sp,-thumb-mode"
spec.Features = "+armv7-a,+d32,+dsp,+fp64,+neon,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-aes,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-sha2,-thumb-mode,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
}
case "arm64":
spec.CPU = "generic"
spec.Features = "+neon"
}
if goos == "darwin" {
spec.CFlags = append(spec.CFlags, "-isysroot", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk")
spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip")
spec.Linker = "ld.lld"
spec.Libc = "darwin-libSystem"
arch := strings.Split(triple, "-")[0]
platformVersion := strings.TrimPrefix(strings.Split(triple, "-")[2], "macosx")
flavor := "darwin"
if strings.Split(llvm.Version, ".")[0] < "13" {
flavor = "darwinnew" // needed on LLVM 12 and below
}
spec.LDFlags = append(spec.LDFlags,
"-flavor", flavor,
"-dead_strip",
"-arch", arch,
"-platform_version", "macos", platformVersion, platformVersion,
)
} else if goos == "linux" {
spec.Linker = "ld.lld"
spec.RTLib = "compiler-rt"
@@ -279,6 +284,12 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
} else if goos == "windows" {
spec.Linker = "ld.lld"
spec.Libc = "mingw-w64"
// Note: using a medium code model, low image base and no ASLR
// because Go doesn't really need those features. ASLR patches
// around issues for unsafe languages like C/C++ that are not
// normally present in Go (without explicitly opting in).
// For more discussion:
// https://groups.google.com/g/Golang-nuts/c/Jd9tlNc6jUE/m/Zo-7zIP_m3MJ?pli=1
spec.LDFlags = append(spec.LDFlags,
"-m", "i386pep",
"-Bdynamic",
@@ -286,6 +297,12 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
"--gc-sections",
"--no-insert-timestamp",
)
llvmMajor, _ := strconv.Atoi(strings.Split(llvm.Version, ".")[0])
if llvmMajor >= 12 {
// This flag was added in LLVM 12. At the same time, LLVM 12
// switched the default from --dynamicbase to --no-dynamicbase.
spec.LDFlags = append(spec.LDFlags, "--no-dynamicbase")
}
} else {
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
}
@@ -302,16 +319,25 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
if goarch != runtime.GOARCH {
// Some educated guesses as to how to invoke helper programs.
spec.GDB = []string{"gdb-multiarch"}
if goarch == "arm" && goos == "linux" {
spec.Emulator = []string{"qemu-arm"}
}
if goarch == "arm64" && goos == "linux" {
spec.Emulator = []string{"qemu-aarch64"}
if goos == "linux" {
switch goarch {
case "386":
// amd64 can _usually_ run 32-bit programs, so skip the emulator in that case.
if runtime.GOARCH != "amd64" {
spec.Emulator = "qemu-i386 {}"
}
case "amd64":
spec.Emulator = "qemu-x86_64 {}"
case "arm":
spec.Emulator = "qemu-arm {}"
case "arm64":
spec.Emulator = "qemu-aarch64 {}"
}
}
}
if goos != runtime.GOOS {
if goos == "windows" {
spec.Emulator = []string{"wine"}
spec.Emulator = "wine {}"
}
}
return &spec, nil
-5
View File
@@ -29,7 +29,6 @@ func TestOverrideProperties(t *testing.T) {
CPU: "baseCpu",
CFlags: []string{"-base-foo", "-base-bar"},
BuildTags: []string{"bt1", "bt2"},
Emulator: []string{"be1", "be2"},
DefaultStackSize: 42,
AutoStackSize: &baseAutoStackSize,
}
@@ -38,7 +37,6 @@ func TestOverrideProperties(t *testing.T) {
GOOS: "",
CPU: "chlidCpu",
CFlags: []string{"-child-foo", "-child-bar"},
Emulator: []string{"ce1", "ce2"},
AutoStackSize: &childAutoStackSize,
DefaultStackSize: 64,
}
@@ -57,9 +55,6 @@ func TestOverrideProperties(t *testing.T) {
if !reflect.DeepEqual(base.BuildTags, []string{"bt1", "bt2"}) {
t.Errorf("Overriding failed : got %v", base.BuildTags)
}
if !reflect.DeepEqual(base.Emulator, []string{"ce1", "ce2"}) {
t.Errorf("Overriding failed : got %v", base.Emulator)
}
if *base.AutoStackSize != false {
t.Errorf("Overriding failed : got %v", base.AutoStackSize)
}
+32
View File
@@ -1,6 +1,7 @@
package compiler
import (
"fmt"
"strings"
"golang.org/x/tools/go/ssa"
@@ -16,6 +17,20 @@ func (b *builder) createAtomicOp(call *ssa.CallCommon) (llvm.Value, bool) {
case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
ptr := b.getValue(call.Args[0])
val := b.getValue(call.Args[1])
if strings.HasPrefix(b.Triple, "avr") {
// AtomicRMW does not work on AVR as intended:
// - There are some register allocation issues (fixed by https://reviews.llvm.org/D97127 which is not yet in a usable LLVM release)
// - The result is the new value instead of the old value
vType := val.Type()
name := fmt.Sprintf("__sync_fetch_and_add_%d", vType.IntTypeWidth()/8)
fn := b.mod.NamedFunction(name)
if fn.IsNil() {
fn = llvm.AddFunction(b.mod, name, llvm.FunctionType(vType, []llvm.Type{ptr.Type(), vType}, false))
}
oldVal := b.createCall(fn, []llvm.Value{ptr, val}, "")
// Return the new value, not the original value returned.
return b.CreateAdd(oldVal, val, ""), true
}
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAdd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
// Return the new value, not the original value returned by atomicrmw.
return b.CreateAdd(oldVal, val, ""), true
@@ -73,6 +88,23 @@ func (b *builder) createAtomicOp(call *ssa.CallCommon) (llvm.Value, bool) {
case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer":
ptr := b.getValue(call.Args[0])
val := b.getValue(call.Args[1])
if strings.HasPrefix(b.Triple, "avr") {
// SelectionDAGBuilder is currently missing the "are unaligned atomics allowed" check for stores.
vType := val.Type()
isPointer := vType.TypeKind() == llvm.PointerTypeKind
if isPointer {
// libcalls only supports integers, so cast to an integer.
vType = b.uintptrType
val = b.CreatePtrToInt(val, vType, "")
ptr = b.CreateBitCast(ptr, llvm.PointerType(vType, 0), "")
}
name := fmt.Sprintf("__atomic_store_%d", vType.IntTypeWidth()/8)
fn := b.mod.NamedFunction(name)
if fn.IsNil() {
fn = llvm.AddFunction(b.mod, name, llvm.FunctionType(vType, []llvm.Type{ptr.Type(), vType, b.uintptrType}, false))
}
return b.createCall(fn, []llvm.Value{ptr, val, llvm.ConstInt(b.uintptrType, 5, false)}, ""), true
}
store := b.CreateStore(val, ptr)
store.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
store.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
+1 -2
View File
@@ -40,8 +40,7 @@ func (b *builder) createRuntimeCall(fnName string, args []llvm.Value, name strin
if llvmFn.IsNil() {
panic("trying to call non-existent function: " + fn.RelString(nil))
}
args = append(args, llvm.Undef(b.i8ptrType)) // unused context parameter
args = append(args, llvm.ConstPointerNull(b.i8ptrType)) // coroutine handle
args = append(args, llvm.Undef(b.i8ptrType)) // unused context parameter
return b.createCall(llvmFn, args, name)
}
+105 -52
View File
@@ -20,11 +20,6 @@ import (
"tinygo.org/x/go-llvm"
)
// Version of the compiler pacakge. Must be incremented each time the compiler
// package changes in a way that affects the generated LLVM module.
// This version is independent of the TinyGo version number.
const Version = 25 // last change: add "target-cpu" and "target-features" attributes
func init() {
llvm.InitializeAllTargets()
llvm.InitializeAllTargetMCs()
@@ -52,7 +47,6 @@ type Config struct {
// Various compiler options that determine how code is generated.
Scheduler string
FuncImplementation string
AutomaticStackSize bool
DefaultStackSize uint64
NeedsStackObjects bool
@@ -83,6 +77,7 @@ type compilerContext struct {
diagnostics []error
astComments map[string]*ast.CommentGroup
pkg *types.Package
packageDir string // directory for this package
runtimePkg *types.Package
}
@@ -144,6 +139,8 @@ type builder struct {
deferPtr llvm.Value
difunc llvm.Metadata
dilocals map[*types.Var]llvm.Metadata
initInlinedAt llvm.Metadata // fake inlinedAt position
initPseudoFuncs map[string]llvm.Metadata // fake "inlined" functions for proper init debug locations
allDeferFuncs []interface{}
deferFuncs map[*ssa.Function]int
deferInvokeFuncs map[string]int
@@ -237,16 +234,22 @@ func Sizes(machine llvm.TargetMachine) types.Sizes {
panic("unknown pointer size")
}
// Construct a complex128 type because that's likely the type with the
// biggest alignment on most/all ABIs.
ctx := llvm.NewContext()
defer ctx.Dispose()
complex128Type := ctx.StructType([]llvm.Type{ctx.DoubleType(), ctx.DoubleType()}, false)
return &stdSizes{
IntSize: int64(intWidth / 8),
PtrSize: int64(targetData.PointerSize()),
MaxAlign: int64(targetData.PrefTypeAlignment(targetData.IntPtrType())),
MaxAlign: int64(targetData.ABITypeAlignment(complex128Type)),
}
}
// CompilePackage compiles a single package to a LLVM module.
func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package, machine llvm.TargetMachine, config *Config, dumpSSA bool) (llvm.Module, []error) {
c := newCompilerContext(moduleName, machine, config, dumpSSA)
c.packageDir = pkg.OriginalDir()
c.pkg = pkg.Pkg
c.runtimePkg = ssaPkg.Prog.ImportedPackage("runtime").Pkg
c.program = ssaPkg.Prog
@@ -271,6 +274,10 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
// Predeclare the runtime.alloc function, which is used by the wordpack
// functionality.
c.getFunction(c.program.ImportedPackage("runtime").Members["alloc"].(*ssa.Function))
if c.NeedsStackObjects {
// Predeclare trackPointer, which is used everywhere we use runtime.alloc.
c.getFunction(c.program.ImportedPackage("runtime").Members["trackPointer"].(*ssa.Function))
}
// Compile all functions, methods, and global variables in this package.
irbuilder := c.ctx.NewBuilder()
@@ -601,6 +608,51 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
}
}
// setDebugLocation sets the current debug location for the builder.
func (b *builder) setDebugLocation(pos token.Pos) {
if pos == token.NoPos {
// No debug information available for this instruction.
b.SetCurrentDebugLocation(0, 0, b.difunc, llvm.Metadata{})
return
}
position := b.program.Fset.Position(pos)
if b.fn.Synthetic == "package initializer" {
// Package initializers are treated specially, because while individual
// Go SSA instructions have file/line/col information, the parent
// function does not. LLVM doesn't store filename information per
// instruction, only per function. We work around this difference by
// creating a fake DIFunction for each Go file and say that the
// instruction really came from that (fake) function but was inlined in
// the package initializer function.
position := b.program.Fset.Position(pos)
name := filepath.Base(position.Filename)
difunc, ok := b.initPseudoFuncs[name]
if !ok {
diFuncType := b.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
File: b.getDIFile(position.Filename),
})
difunc = b.dibuilder.CreateFunction(b.getDIFile(position.Filename), llvm.DIFunction{
Name: b.fn.RelString(nil) + "#" + name,
File: b.getDIFile(position.Filename),
Line: 0,
Type: diFuncType,
LocalToUnit: true,
IsDefinition: true,
ScopeLine: 0,
Flags: llvm.FlagPrototyped,
Optimized: true,
})
b.initPseudoFuncs[name] = difunc
}
b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), difunc, b.initInlinedAt)
return
}
// Regular debug information.
b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), b.difunc, llvm.Metadata{})
}
// getLocalVariable returns a debug info entry for a local variable, which may
// either be a parameter or a regular variable. It will create a new metadata
// entry if there isn't one for the variable yet.
@@ -853,16 +905,14 @@ func (b *builder) createFunction() {
// Add debug info, if needed.
if b.Debug {
if b.fn.Synthetic == "package initializer" {
// Package initializers have no debug info. Create some fake debug
// info to at least have *something*.
filename := b.fn.Package().Pkg.Path() + "/<init>"
b.difunc = b.attachDebugInfoRaw(b.fn, b.llvmFn, "", filename, 0)
// Package initializer functions have no debug info. Create some
// fake debug info to at least have *something*.
b.difunc = b.attachDebugInfoRaw(b.fn, b.llvmFn, "", b.packageDir, 0)
} else if b.fn.Syntax() != nil {
// Create debug info file if needed.
b.difunc = b.attachDebugInfo(b.fn)
}
pos := b.program.Fset.Position(b.fn.Pos())
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
b.setDebugLocation(b.fn.Pos())
}
// Pre-create all basic blocks in the function.
@@ -874,6 +924,16 @@ func (b *builder) createFunction() {
entryBlock := b.blockEntries[b.fn.Blocks[0]]
b.SetInsertPointAtEnd(entryBlock)
if b.fn.Synthetic == "package initializer" {
b.initPseudoFuncs = make(map[string]llvm.Metadata)
// Create a fake 'inlined at' metadata node.
// See setDebugLocation for details.
alloca := b.CreateAlloca(b.uintptrType, "")
b.initInlinedAt = alloca.InstructionDebugLoc()
alloca.EraseFromParentAsInstruction()
}
// Load function parameters
llvmParamIndex := 0
for _, param := range b.fn.Params {
@@ -897,10 +957,10 @@ func (b *builder) createFunction() {
} else {
fieldOffsets := b.expandFormalParamOffsets(llvmType)
for i, field := range fields {
expr := b.dibuilder.CreateExpression([]int64{
0x1000, // DW_OP_LLVM_fragment
int64(fieldOffsets[i]) * 8, // offset in bits
int64(b.targetData.TypeAllocSize(field.Type())) * 8, // size in bits
expr := b.dibuilder.CreateExpression([]uint64{
0x1000, // DW_OP_LLVM_fragment
fieldOffsets[i] * 8, // offset in bits
b.targetData.TypeAllocSize(field.Type()) * 8, // size in bits
})
b.dibuilder.InsertValueAtEnd(field, dbgParam, expr, loc, entryBlock)
}
@@ -912,9 +972,7 @@ func (b *builder) createFunction() {
// method).
var context llvm.Value
if !b.info.exported {
parentHandle := b.llvmFn.LastParam()
parentHandle.SetName("parentHandle")
context = llvm.PrevParam(parentHandle)
context = b.llvmFn.LastParam()
context.SetName("context")
}
if len(b.fn.FreeVars) != 0 {
@@ -1068,8 +1126,7 @@ func getPos(val posser) token.Pos {
// particular Go SSA instruction.
func (b *builder) createInstruction(instr ssa.Instruction) {
if b.Debug {
pos := b.program.Fset.Position(getPos(instr))
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
b.setDebugLocation(getPos(instr))
}
switch instr := instr.(type) {
@@ -1176,7 +1233,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
case "cap":
value := argValues[0]
var llvmCap llvm.Value
switch argTypes[0].(type) {
switch argTypes[0].Underlying().(type) {
case *types.Chan:
llvmCap = b.createRuntimeCall("chanCap", []llvm.Value{value}, "cap")
case *types.Slice:
@@ -1383,7 +1440,7 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
return b.emitSV64Call(instr.Args)
case strings.HasPrefix(name, "(device/riscv.CSR)."):
return b.emitCSROperation(instr)
case strings.HasPrefix(name, "syscall.Syscall"):
case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall"):
return b.createSyscall(instr)
case strings.HasPrefix(name, "syscall.rawSyscallNoError"):
return b.createRawSyscallNoError(instr)
@@ -1412,6 +1469,14 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
case *ssa.Function:
// Regular function call. No context is necessary.
context = llvm.Undef(b.i8ptrType)
if info.variadic && len(fn.Params) == 0 {
// This matches Clang, see: https://godbolt.org/z/Gqv49xKMq
// Eventually we might be able to eliminate this special case
// entirely. For details, see:
// https://discourse.llvm.org/t/rfc-enabling-wstrict-prototypes-by-default-in-c/60521
fnType := llvm.FunctionType(callee.Type().ElementType().ReturnType(), nil, false)
callee = llvm.ConstBitCast(callee, llvm.PointerType(fnType, b.funcPtrAddrSpace))
}
case *ssa.MakeClosure:
// A call on a func value, but the callee is trivial to find. For
// example: immediately applied functions.
@@ -1451,9 +1516,6 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
// This function takes a context parameter.
// Add it to the end of the parameter list.
params = append(params, context)
// Parent coroutine handle.
params = append(params, llvm.Undef(b.i8ptrType))
}
return b.createCall(callee, params, ""), nil
@@ -1500,7 +1562,11 @@ func (c *compilerContext) maxSliceSize(elementType llvm.Type) uint64 {
// Determine the maximum allowed size for a slice. The biggest possible
// pointer (starting from 0) would be maxPointerValue*sizeof(elementType) so
// divide by the element type to get the real maximum size.
maxSize := maxPointerValue / c.targetData.TypeAllocSize(elementType)
elementSize := c.targetData.TypeAllocSize(elementType)
if elementSize == 0 {
elementSize = 1
}
maxSize := maxPointerValue / elementSize
// len(slice) is an int. Make sure the length remains small enough to fit in
// an int.
@@ -1522,8 +1588,9 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
switch expr := expr.(type) {
case *ssa.Alloc:
typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
if expr.Heap {
size := b.targetData.TypeAllocSize(typ)
size := b.targetData.TypeAllocSize(typ)
// Move all "large" allocations to the heap. This value is also transform.maxStackAlloc.
if expr.Heap || size > 256 {
// Calculate ^uintptr(0)
maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue()
if size > maxSize {
@@ -1792,20 +1859,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
if expr.IsString {
return b.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil
} else { // map
llvmKeyType := b.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
llvmValueType := b.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
mapKeyAlloca, mapKeyPtr, mapKeySize := b.createTemporaryAlloca(llvmKeyType, "range.key")
mapValueAlloca, mapValuePtr, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyPtr, mapValuePtr}, "range.next")
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
tuple = b.CreateInsertValue(tuple, ok, 0, "")
tuple = b.CreateInsertValue(tuple, b.CreateLoad(mapKeyAlloca, ""), 1, "")
tuple = b.CreateInsertValue(tuple, b.CreateLoad(mapValueAlloca, ""), 2, "")
b.emitLifetimeEnd(mapKeyPtr, mapKeySize)
b.emitLifetimeEnd(mapValuePtr, mapValueSize)
return tuple, nil
return b.createMapIteratorNext(rangeVal, llvmRangeVal, it), nil
}
case *ssa.Phi:
phi := b.CreatePHI(b.getLLVMType(expr.Type()), "")
@@ -2276,16 +2330,16 @@ func (b *builder) createBinOp(op token.Token, typ, ytyp types.Type, x, y llvm.Va
case token.NEQ: // !=
result := b.createRuntimeCall("stringEqual", []llvm.Value{x, y}, "")
return b.CreateNot(result, ""), nil
case token.LSS: // <
case token.LSS: // x < y
return b.createRuntimeCall("stringLess", []llvm.Value{x, y}, ""), nil
case token.LEQ: // <=
case token.LEQ: // x <= y becomes NOT (y < x)
result := b.createRuntimeCall("stringLess", []llvm.Value{y, x}, "")
return b.CreateNot(result, ""), nil
case token.GTR: // >
case token.GTR: // x > y becomes y < x
return b.createRuntimeCall("stringLess", []llvm.Value{y, x}, ""), nil
case token.GEQ: // x >= y becomes NOT (x < y)
result := b.createRuntimeCall("stringLess", []llvm.Value{x, y}, "")
return b.CreateNot(result, ""), nil
case token.GEQ: // >=
return b.createRuntimeCall("stringLess", []llvm.Value{y, x}, ""), nil
default:
panic("binop on string: " + op.String())
}
@@ -2802,9 +2856,8 @@ func (b *builder) createUnOp(unop *ssa.UnOp) (llvm.Value, error) {
// var C.add unsafe.Pointer
// Instead of a load from the global, create a bitcast of the
// function pointer itself.
globalName := b.getGlobalInfo(unop.X.(*ssa.Global)).linkName
name := globalName[:len(globalName)-len("$funcaddr")]
fn := b.getFunction(b.fn.Pkg.Members["C."+name].(*ssa.Function))
name := strings.TrimSuffix(unop.X.(*ssa.Global).Name(), "$funcaddr")
fn := b.getFunction(b.fn.Pkg.Members[name].(*ssa.Function))
if fn.IsNil() {
return llvm.Value{}, b.makeError(unop.Pos(), "cgo function not found: "+name)
}
+29 -8
View File
@@ -41,6 +41,13 @@ func TestCompiler(t *testing.T) {
t.Skip("compiler tests require LLVM 11 or above, got LLVM ", 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.
tests := []testCase{
{"basic.go", "", ""},
{"pointer.go", "", ""},
@@ -48,22 +55,20 @@ func TestCompiler(t *testing.T) {
{"string.go", "", ""},
{"float.go", "", ""},
{"interface.go", "", ""},
{"func.go", "", "coroutines"},
{"func.go", "", ""},
{"pragma.go", "", ""},
{"goroutine.go", "wasm", "asyncify"},
{"goroutine.go", "wasm", "coroutines"},
{"goroutine.go", "cortex-m-qemu", "tasks"},
{"channel.go", "", ""},
{"intrinsics.go", "cortex-m-qemu", ""},
{"intrinsics.go", "wasm", ""},
{"gc.go", "", ""},
}
_, minor, err := goenv.GetGorootVersion(goenv.Get("GOROOT"))
if err != nil {
t.Fatal("could not read Go version:", err)
if llvmMajor >= 12 {
tests = append(tests, testCase{"intrinsics.go", "cortex-m-qemu", ""})
tests = append(tests, testCase{"intrinsics.go", "wasm", ""})
}
if minor >= 17 {
if goMinor >= 17 {
tests = append(tests, testCase{"go1.17.go", "", ""})
}
@@ -100,9 +105,9 @@ func TestCompiler(t *testing.T) {
CodeModel: config.CodeModel(),
RelocationModel: config.RelocationModel(),
Scheduler: config.Scheduler(),
FuncImplementation: config.FuncImplementation(),
AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.Target.DefaultStackSize,
NeedsStackObjects: config.NeedsStackObjects(),
}
machine, err := NewTargetMachine(compilerConfig)
if err != nil {
@@ -201,6 +206,12 @@ func fuzzyEqualIR(s1, s2 string) bool {
// stripped out.
func filterIrrelevantIRLines(lines []string) []string {
var out []string
llvmVersion, err := strconv.Atoi(strings.Split(llvm.Version, ".")[0])
if err != nil {
// Note: this should never happen and if it does, it will always happen
// for a particular build because llvm.Version is a constant.
panic(err)
}
for _, line := range lines {
line = strings.Split(line, ";")[0] // strip out comments/info
line = strings.TrimRight(line, "\r ") // drop '\r' on Windows and remove trailing spaces from comments
@@ -210,6 +221,16 @@ func filterIrrelevantIRLines(lines []string) []string {
if strings.HasPrefix(line, "source_filename = ") {
continue
}
if llvmVersion < 12 && strings.HasPrefix(line, "attributes ") {
// Ignore attribute groups. These may change between LLVM versions.
// Right now test outputs are for LLVM 12 and higher.
continue
}
if llvmVersion < 14 && strings.HasPrefix(line, "target datalayout = ") {
// The datalayout string may vary betewen LLVM versions.
// Right now test outputs are for LLVM 14 and higher.
continue
}
out = append(out, line)
}
return out
-9
View File
@@ -343,9 +343,6 @@ func (b *builder) createRunDefers() {
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
}
// Parent coroutine handle.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
b.createCall(fnPtr, forwardParams, "")
case *ssa.Function:
@@ -374,9 +371,6 @@ func (b *builder) createRunDefers() {
// Add the context parameter. We know it is ignored by the receiving
// function, but we have to pass one anyway.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
// Parent coroutine handle.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
}
// Call real function.
@@ -403,9 +397,6 @@ func (b *builder) createRunDefers() {
forwardParams = append(forwardParams, forwardParam)
}
// Parent coroutine handle.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
// Call deferred function.
b.createCall(b.getFunction(fn), forwardParams, "")
case *ssa.Builtin:
+9 -55
View File
@@ -19,29 +19,8 @@ func (b *builder) createFuncValue(funcPtr, context llvm.Value, sig *types.Signat
// createFuncValue creates a function value from a raw function pointer with no
// context.
func (c *compilerContext) createFuncValue(builder llvm.Builder, funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
var funcValueScalar llvm.Value
switch c.FuncImplementation {
case "doubleword":
// Closure is: {context, function pointer}
funcValueScalar = llvm.ConstBitCast(funcPtr, c.rawVoidFuncType)
case "switch":
funcValueWithSignatureGlobalName := funcPtr.Name() + "$withSignature"
funcValueWithSignatureGlobal := c.mod.NamedGlobal(funcValueWithSignatureGlobalName)
if funcValueWithSignatureGlobal.IsNil() {
funcValueWithSignatureType := c.getLLVMRuntimeType("funcValueWithSignature")
funcValueWithSignature := llvm.ConstNamedStruct(funcValueWithSignatureType, []llvm.Value{
llvm.ConstPtrToInt(funcPtr, c.uintptrType),
c.getFuncSignatureID(sig),
})
funcValueWithSignatureGlobal = llvm.AddGlobal(c.mod, funcValueWithSignatureType, funcValueWithSignatureGlobalName)
funcValueWithSignatureGlobal.SetInitializer(funcValueWithSignature)
funcValueWithSignatureGlobal.SetGlobalConstant(true)
funcValueWithSignatureGlobal.SetLinkage(llvm.LinkOnceODRLinkage)
}
funcValueScalar = llvm.ConstPtrToInt(funcValueWithSignatureGlobal, c.uintptrType)
default:
panic("unimplemented func value variant")
}
// Closure is: {context, function pointer}
funcValueScalar := llvm.ConstBitCast(funcPtr, c.rawVoidFuncType)
funcValueType := c.getFuncType(sig)
funcValue := llvm.Undef(funcValueType)
funcValue = builder.CreateInsertValue(funcValue, context, 0, "")
@@ -78,43 +57,19 @@ func (b *builder) extractFuncContext(funcValue llvm.Value) llvm.Value {
// value. This may be an expensive operation.
func (b *builder) decodeFuncValue(funcValue llvm.Value, sig *types.Signature) (funcPtr, context llvm.Value) {
context = b.CreateExtractValue(funcValue, 0, "")
switch b.FuncImplementation {
case "doubleword":
bitcast := b.CreateExtractValue(funcValue, 1, "")
if !bitcast.IsAConstantExpr().IsNil() && bitcast.Opcode() == llvm.BitCast {
funcPtr = bitcast.Operand(0)
return
}
llvmSig := b.getRawFuncType(sig)
funcPtr = b.CreateBitCast(bitcast, llvmSig, "")
case "switch":
if !funcValue.IsAConstant().IsNil() {
// If this is a constant func value, the underlying function is
// known and can be returned directly.
funcValueWithSignatureGlobal := llvm.ConstExtractValue(funcValue, []uint32{1}).Operand(0)
funcPtr = llvm.ConstExtractValue(funcValueWithSignatureGlobal.Initializer(), []uint32{0}).Operand(0)
return
}
llvmSig := b.getRawFuncType(sig)
sigGlobal := b.getFuncSignatureID(sig)
funcPtr = b.createRuntimeCall("getFuncPtr", []llvm.Value{funcValue, sigGlobal}, "")
funcPtr = b.CreateIntToPtr(funcPtr, llvmSig, "")
default:
panic("unimplemented func value variant")
bitcast := b.CreateExtractValue(funcValue, 1, "")
if !bitcast.IsAConstantExpr().IsNil() && bitcast.Opcode() == llvm.BitCast {
funcPtr = bitcast.Operand(0)
return
}
llvmSig := b.getRawFuncType(sig)
funcPtr = b.CreateBitCast(bitcast, llvmSig, "")
return
}
// getFuncType returns the type of a func value given a signature.
func (c *compilerContext) getFuncType(typ *types.Signature) llvm.Type {
switch c.FuncImplementation {
case "doubleword":
return c.ctx.StructType([]llvm.Type{c.i8ptrType, c.rawVoidFuncType}, false)
case "switch":
return c.getLLVMRuntimeType("funcValue")
default:
panic("unimplemented func value variant")
}
return c.ctx.StructType([]llvm.Type{c.i8ptrType, c.rawVoidFuncType}, false)
}
// getRawFuncType returns a LLVM function pointer type for a given signature.
@@ -160,7 +115,6 @@ func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
}
// All functions take these parameters at the end.
paramTypes = append(paramTypes, c.i8ptrType) // context
paramTypes = append(paramTypes, c.i8ptrType) // parent coroutine
// Make a func type out of the signature.
return llvm.PointerType(llvm.FunctionType(returnType, paramTypes, false), c.funcPtrAddrSpace)
+21 -53
View File
@@ -30,11 +30,6 @@ func (b *builder) createGo(instr *ssa.Go) {
switch value := instr.Call.Value.(type) {
case *ssa.Function:
// Goroutine call is regular function call. No context is necessary.
if b.Scheduler == "coroutines" {
// The context parameter is assumed to be always present in the
// coroutines scheduler.
context = llvm.Undef(b.i8ptrType)
}
case *ssa.MakeClosure:
// A goroutine call on a func value, but the callee is trivial to find. For
// example: immediately applied functions.
@@ -95,50 +90,31 @@ func (b *builder) createGo(instr *ssa.Go) {
// * The function pointer (for tasks).
var context llvm.Value
funcPtr, context = b.decodeFuncValue(b.getValue(instr.Call.Value), instr.Call.Value.Type().Underlying().(*types.Signature))
params = append(params, context) // context parameter
params = append(params, context, funcPtr)
hasContext = true
switch b.Scheduler {
case "none", "coroutines":
// There are no additional parameters needed for the goroutine start operation.
case "tasks", "asyncify":
// Add the function pointer as a parameter to start the goroutine.
params = append(params, funcPtr)
default:
panic("unknown scheduler type")
}
prefix = b.fn.RelString(nil)
}
paramBundle := b.emitPointerPack(params)
var callee, stackSize llvm.Value
switch b.Scheduler {
case "none", "tasks", "asyncify":
callee = b.createGoroutineStartWrapper(funcPtr, prefix, hasContext, instr.Pos())
if b.AutomaticStackSize {
// The stack size is not known until after linking. Call a dummy
// function that will be replaced with a load from a special ELF
// section that contains the stack size (and is modified after
// linking).
stackSizeFn := b.getFunction(b.program.ImportedPackage("internal/task").Members["getGoroutineStackSize"].(*ssa.Function))
stackSize = b.createCall(stackSizeFn, []llvm.Value{callee, llvm.Undef(b.i8ptrType), llvm.Undef(b.i8ptrType)}, "stacksize")
} else {
// The stack size is fixed at compile time. By emitting it here as a
// constant, it can be optimized.
if (b.Scheduler == "tasks" || b.Scheduler == "asyncify") && b.DefaultStackSize == 0 {
b.addError(instr.Pos(), "default stack size for goroutines is not set")
}
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
var stackSize llvm.Value
callee := b.createGoroutineStartWrapper(funcPtr, prefix, hasContext, instr.Pos())
if b.AutomaticStackSize {
// The stack size is not known until after linking. Call a dummy
// function that will be replaced with a load from a special ELF
// section that contains the stack size (and is modified after
// linking).
stackSizeFn := b.getFunction(b.program.ImportedPackage("internal/task").Members["getGoroutineStackSize"].(*ssa.Function))
stackSize = b.createCall(stackSizeFn, []llvm.Value{callee, llvm.Undef(b.i8ptrType)}, "stacksize")
} else {
// The stack size is fixed at compile time. By emitting it here as a
// constant, it can be optimized.
if (b.Scheduler == "tasks" || b.Scheduler == "asyncify") && b.DefaultStackSize == 0 {
b.addError(instr.Pos(), "default stack size for goroutines is not set")
}
case "coroutines":
callee = b.CreatePtrToInt(funcPtr, b.uintptrType, "")
// There is no goroutine stack size: coroutines are used instead of
// stacks.
stackSize = llvm.Undef(b.uintptrType)
default:
panic("unreachable")
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
}
start := b.getFunction(b.program.ImportedPackage("internal/task").Members["start"].(*ssa.Function))
b.createCall(start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.i8ptrType), llvm.ConstPointerNull(b.i8ptrType)}, "")
b.createCall(start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.i8ptrType)}, "")
}
// createGoroutineStartWrapper creates a wrapper for the task-based
@@ -217,7 +193,6 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
// Create the list of params for the call.
paramTypes := fn.Type().ElementType().ParamTypes()
paramTypes = paramTypes[:len(paramTypes)-1] // strip parentHandle parameter
if !hasContext {
paramTypes = paramTypes[:len(paramTypes)-1] // strip context parameter
}
@@ -225,14 +200,13 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
if !hasContext {
params = append(params, llvm.Undef(c.i8ptrType)) // add dummy context parameter
}
params = append(params, llvm.Undef(c.i8ptrType)) // add dummy parentHandle parameter
// Create the call.
builder.CreateCall(fn, params, "")
if c.Scheduler == "asyncify" {
builder.CreateCall(deadlock, []llvm.Value{
llvm.Undef(c.i8ptrType), llvm.Undef(c.i8ptrType),
llvm.Undef(c.i8ptrType),
}, "")
}
@@ -288,25 +262,19 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
// Get the list of parameters, with the extra parameters at the end.
paramTypes := fn.Type().ElementType().ParamTypes()
paramTypes[len(paramTypes)-1] = fn.Type() // the last element is the function pointer
paramTypes = append(paramTypes, fn.Type()) // the last element is the function pointer
params := llvmutil.EmitPointerUnpack(builder, c.mod, wrapper.Param(0), paramTypes)
// Get the function pointer.
fnPtr := params[len(params)-1]
// The last parameter in the packed object has somewhat of a dual role.
// Inside the parameter bundle it's the function pointer, stored right
// after the context pointer. But in the IR call instruction, it's the
// parentHandle function that's always undef outside of the coroutines
// scheduler. Thus, make the parameter undef here.
params[len(params)-1] = llvm.Undef(c.i8ptrType)
params = params[:len(params)-1]
// Create the call.
builder.CreateCall(fnPtr, params, "")
if c.Scheduler == "asyncify" {
builder.CreateCall(deadlock, []llvm.Value{
llvm.Undef(c.i8ptrType), llvm.Undef(c.i8ptrType),
llvm.Undef(c.i8ptrType),
}, "")
}
}
+12 -9
View File
@@ -24,7 +24,7 @@ func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
// Magic function: insert inline assembly instead of calling it.
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{}, false)
asm := constant.StringVal(args[0].(*ssa.Const).Value)
target := llvm.InlineAsm(fnType, asm, "", true, false, 0)
target := llvm.InlineAsm(fnType, asm, "", true, false, 0, false)
return b.CreateCall(target, nil, ""), nil
}
@@ -98,7 +98,10 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
case llvm.IntegerTypeKind:
constraints = append(constraints, "r")
case llvm.PointerTypeKind:
constraints = append(constraints, "*m")
// Memory references require a type in LLVM 14, probably as a
// preparation for opaque pointers.
err = b.makeError(instr.Pos(), "support for pointer operands was dropped in TinyGo 0.23")
return s
default:
err = b.makeError(instr.Pos(), "unknown type in inline assembly for value: "+name)
return s
@@ -116,7 +119,7 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
outputType = b.ctx.VoidType()
}
fnType := llvm.FunctionType(outputType, argTypes, false)
target := llvm.InlineAsm(fnType, asmString, strings.Join(constraints, ","), true, false, 0)
target := llvm.InlineAsm(fnType, asmString, strings.Join(constraints, ","), true, false, 0, false)
result := b.CreateCall(target, args, "")
if hasOutput {
return result, nil
@@ -159,7 +162,7 @@ func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
// marked as clobbered.
constraints += ",~{r1},~{r2},~{r3}"
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0)
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0, false)
return b.CreateCall(target, llvmArgs, ""), nil
}
@@ -197,7 +200,7 @@ func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
// marked as clobbered.
constraints += ",~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7}"
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0)
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0, false)
return b.CreateCall(target, llvmArgs, ""), nil
}
@@ -222,24 +225,24 @@ func (b *builder) emitCSROperation(call *ssa.CallCommon) (llvm.Value, error) {
// marked as such.
fnType := llvm.FunctionType(b.uintptrType, nil, false)
asm := fmt.Sprintf("csrr $0, %d", csr)
target := llvm.InlineAsm(fnType, asm, "=r", true, false, 0)
target := llvm.InlineAsm(fnType, asm, "=r", true, false, 0, false)
return b.CreateCall(target, nil, ""), nil
case "Set":
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.uintptrType}, false)
asm := fmt.Sprintf("csrw %d, $0", csr)
target := llvm.InlineAsm(fnType, asm, "r", true, false, 0)
target := llvm.InlineAsm(fnType, asm, "r", true, false, 0, false)
return b.CreateCall(target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
case "SetBits":
// Note: it may be possible to optimize this to csrrsi in many cases.
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType}, false)
asm := fmt.Sprintf("csrrs $0, %d, $1", csr)
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0)
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0, false)
return b.CreateCall(target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
case "ClearBits":
// Note: it may be possible to optimize this to csrrci in many cases.
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType}, false)
asm := fmt.Sprintf("csrrc $0, %d, $1", csr)
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0)
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0, false)
return b.CreateCall(target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
default:
return llvm.Value{}, b.makeError(call.Pos(), "unknown CSR operation: "+name)
+89 -48
View File
@@ -31,6 +31,15 @@ func (b *builder) createMakeInterface(val llvm.Value, typ types.Type, pos token.
return itf
}
// extractValueFromInterface extract the value from an interface value
// (runtime._interface) under the assumption that it is of the type given in
// llvmType. The behavior is undefied if the interface is nil or llvmType
// doesn't match the underlying type of the interface.
func (b *builder) extractValueFromInterface(itf llvm.Value, llvmType llvm.Type) llvm.Value {
valuePtr := b.CreateExtractValue(itf, 1, "typeassert.value.ptr")
return b.emitPointerUnpack(valuePtr, []llvm.Type{llvmType})[0]
}
// getTypeCode returns a reference to a type code.
// It returns a pointer to an external global which should be replaced with the
// real type in the interface lowering pass.
@@ -143,6 +152,27 @@ func (c *compilerContext) makeStructTypeFields(typ *types.Struct) llvm.Value {
return structGlobal
}
var basicTypes = [...]string{
types.Bool: "bool",
types.Int: "int",
types.Int8: "int8",
types.Int16: "int16",
types.Int32: "int32",
types.Int64: "int64",
types.Uint: "uint",
types.Uint8: "uint8",
types.Uint16: "uint16",
types.Uint32: "uint32",
types.Uint64: "uint64",
types.Uintptr: "uintptr",
types.Float32: "float32",
types.Float64: "float64",
types.Complex64: "complex64",
types.Complex128: "complex128",
types.String: "string",
types.UnsafePointer: "unsafe.Pointer",
}
// getTypeCodeName returns a name for this type that can be used in the
// interface lowering pass to assign type codes as expected by the reflect
// package. See getTypeCodeNum.
@@ -153,48 +183,7 @@ func getTypeCodeName(t types.Type) string {
case *types.Array:
return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + getTypeCodeName(t.Elem())
case *types.Basic:
var kind string
switch t.Kind() {
case types.Bool:
kind = "bool"
case types.Int:
kind = "int"
case types.Int8:
kind = "int8"
case types.Int16:
kind = "int16"
case types.Int32:
kind = "int32"
case types.Int64:
kind = "int64"
case types.Uint:
kind = "uint"
case types.Uint8:
kind = "uint8"
case types.Uint16:
kind = "uint16"
case types.Uint32:
kind = "uint32"
case types.Uint64:
kind = "uint64"
case types.Uintptr:
kind = "uintptr"
case types.Float32:
kind = "float32"
case types.Float64:
kind = "float64"
case types.Complex64:
kind = "complex64"
case types.Complex128:
kind = "complex128"
case types.String:
kind = "string"
case types.UnsafePointer:
kind = "unsafeptr"
default:
panic("unknown basic type: " + t.Name())
}
return "basic:" + kind
return "basic:" + basicTypes[t.Kind()]
case *types.Chan:
return "chan:" + getTypeCodeName(t.Elem())
case *types.Interface:
@@ -416,8 +405,7 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
} else {
// Type assert on concrete type. Extract the underlying type from
// the interface (but only after checking it matches).
valuePtr := b.CreateExtractValue(itf, 1, "typeassert.value.ptr")
valueOk = b.emitPointerUnpack(valuePtr, []llvm.Type{assertedType})[0]
valueOk = b.extractValueFromInterface(itf, assertedType)
}
b.CreateBr(nextBlock)
@@ -522,7 +510,6 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFn llv
wrapFnType := llvm.FunctionType(fnType.ReturnType(), paramTypes, false)
wrapper = llvm.AddFunction(c.mod, wrapperName, wrapFnType)
c.addStandardAttributes(wrapper)
wrapper.LastParam().SetName("parentHandle")
wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
wrapper.SetUnnamedAddr(true)
@@ -584,23 +571,77 @@ func signature(sig *types.Signature) string {
if i > 0 {
s += ", "
}
s += sig.Params().At(i).Type().String()
s += typestring(sig.Params().At(i).Type())
}
s += ")"
}
if sig.Results().Len() == 0 {
// keep as-is
} else if sig.Results().Len() == 1 {
s += " " + sig.Results().At(0).Type().String()
s += " " + typestring(sig.Results().At(0).Type())
} else {
s += " ("
for i := 0; i < sig.Results().Len(); i++ {
if i > 0 {
s += ", "
}
s += sig.Results().At(i).Type().String()
s += typestring(sig.Results().At(i).Type())
}
s += ")"
}
return s
}
// typestring returns a stable (human-readable) type string for the given type
// that can be used for interface equality checks. It is almost (but not
// exactly) the same as calling t.String(). The main difference is some
// normalization around `byte` vs `uint8` for example.
func typestring(t types.Type) string {
// See: https://github.com/golang/go/blob/master/src/go/types/typestring.go
switch t := t.(type) {
case *types.Array:
return "[" + strconv.FormatInt(t.Len(), 10) + "]" + typestring(t.Elem())
case *types.Basic:
return basicTypes[t.Kind()]
case *types.Chan:
switch t.Dir() {
case types.SendRecv:
return "chan (" + typestring(t.Elem()) + ")"
case types.SendOnly:
return "chan<- (" + typestring(t.Elem()) + ")"
case types.RecvOnly:
return "<-chan (" + typestring(t.Elem()) + ")"
default:
panic("unknown channel direction")
}
case *types.Interface:
methods := make([]string, t.NumMethods())
for i := range methods {
method := t.Method(i)
methods[i] = method.Name() + signature(method.Type().(*types.Signature))
}
return "interface{" + strings.Join(methods, ";") + "}"
case *types.Map:
return "map[" + typestring(t.Key()) + "]" + typestring(t.Elem())
case *types.Named:
return t.String()
case *types.Pointer:
return "*" + typestring(t.Elem())
case *types.Signature:
return "func" + signature(t)
case *types.Slice:
return "[]" + typestring(t.Elem())
case *types.Struct:
fields := make([]string, t.NumFields())
for i := range fields {
field := t.Field(i)
fields[i] = field.Name() + " " + typestring(field.Type())
if tag := t.Tag(i); tag != "" {
fields[i] += " " + strconv.Quote(tag)
}
}
return "struct{" + strings.Join(fields, ";") + "}"
default:
panic("unknown type: " + t.String())
}
}
+1 -1
View File
@@ -31,7 +31,7 @@ func (c *checker) checkType(t llvm.Type, checked map[llvm.Type]struct{}, special
return fmt.Errorf("type %q uses global context", t.String())
default:
// we used some other context by accident
return fmt.Errorf("type %q uses context %v instead of the main context %v", t.Context(), c.ctx)
return fmt.Errorf("type %q uses context %v instead of the main context %v", t.String(), t.Context(), c.ctx)
}
// if this is a composite type, check the components of the type
+1 -1
View File
@@ -147,7 +147,7 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
// Create the global initializer.
bitmapBytes := make([]byte, int(objectSizeWords+7)/8)
copy(bitmapBytes, bitmap.Bytes())
bitmap.FillBytes(bitmapBytes)
var bitmapByteValues []llvm.Value
for _, b := range bitmapBytes {
bitmapByteValues = append(bitmapByteValues, llvm.ConstInt(c.ctx.Int8Type(), uint64(b), false))
+2 -4
View File
@@ -97,15 +97,13 @@ func EmitPointerPack(builder llvm.Builder, mod llvm.Module, prefix string, needs
packedHeapAlloc := builder.CreateCall(alloc, []llvm.Value{
sizeValue,
llvm.ConstNull(i8ptrType),
llvm.Undef(i8ptrType), // unused context parameter
llvm.ConstPointerNull(i8ptrType), // coroutine handle
llvm.Undef(i8ptrType), // unused context parameter
}, "")
if needsStackObjects {
trackPointer := mod.NamedFunction("runtime.trackPointer")
builder.CreateCall(trackPointer, []llvm.Value{
packedHeapAlloc,
llvm.Undef(i8ptrType), // unused context parameter
llvm.ConstPointerNull(i8ptrType), // coroutine handle
llvm.Undef(i8ptrType), // unused context parameter
}, "")
}
packedAlloc := builder.CreateBitCast(packedHeapAlloc, llvm.PointerType(packedType, 0), "")
+73 -1
View File
@@ -10,6 +10,13 @@ import (
"tinygo.org/x/go-llvm"
)
// constants for hashmap algorithms; must match src/runtime/hashmap.go
const (
hashmapAlgorithmBinary = iota
hashmapAlgorithmString
hashmapAlgorithmInterface
)
// createMakeMap creates a new map object (runtime.hashmap) by allocating and
// initializing an appropriately sized object.
func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
@@ -17,22 +24,27 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
keyType := mapType.Key().Underlying()
llvmValueType := b.getLLVMType(mapType.Elem().Underlying())
var llvmKeyType llvm.Type
var alg uint64 // must match values in src/runtime/hashmap.go
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
// String keys.
llvmKeyType = b.getLLVMType(keyType)
alg = hashmapAlgorithmString
} else if hashmapIsBinaryKey(keyType) {
// Trivially comparable keys.
llvmKeyType = b.getLLVMType(keyType)
alg = hashmapAlgorithmBinary
} else {
// All other keys. Implemented as map[interface{}]valueType for ease of
// implementation.
llvmKeyType = b.getLLVMRuntimeType("_interface")
alg = hashmapAlgorithmInterface
}
keySize := b.targetData.TypeAllocSize(llvmKeyType)
valueSize := b.targetData.TypeAllocSize(llvmValueType)
llvmKeySize := llvm.ConstInt(b.ctx.Int8Type(), keySize, false)
llvmValueSize := llvm.ConstInt(b.ctx.Int8Type(), valueSize, false)
sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
algEnum := llvm.ConstInt(b.ctx.Int8Type(), alg, false)
if expr.Reserve != nil {
sizeHint = b.getValue(expr.Reserve)
var err error
@@ -41,7 +53,7 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
return llvm.Value{}, err
}
}
hashmap := b.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint}, "")
hashmap := b.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint, algEnum}, "")
return hashmap, nil
}
@@ -167,6 +179,66 @@ func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos tok
}
}
// createMapIteratorNext lowers the *ssa.Next instruction for iterating over a
// map. It returns a tuple of {bool, key, value} with the result of the
// iteration.
func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llvm.Value) llvm.Value {
// Determine the type of the values to return from the *ssa.Next
// instruction. It is returned as {bool, keyType, valueType}.
keyType := rangeVal.Type().Underlying().(*types.Map).Key()
valueType := rangeVal.Type().Underlying().(*types.Map).Elem()
llvmKeyType := b.getLLVMType(keyType)
llvmValueType := b.getLLVMType(valueType)
// There is a special case in which keys are stored as an interface value
// instead of the value they normally are. This happens for non-trivially
// comparable types such as float32 or some structs.
isKeyStoredAsInterface := false
if t, ok := keyType.Underlying().(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string
} else if hashmapIsBinaryKey(keyType) {
// key can be compared with runtime.memequal
} else {
// The key is stored as an interface value, and may or may not be an
// interface type (for example, float32 keys are stored as an interface
// value).
if _, ok := keyType.Underlying().(*types.Interface); !ok {
isKeyStoredAsInterface = true
}
}
// Determine the type of the key as stored in the map.
llvmStoredKeyType := llvmKeyType
if isKeyStoredAsInterface {
llvmStoredKeyType = b.getLLVMRuntimeType("_interface")
}
// Extract the key and value from the map.
mapKeyAlloca, mapKeyPtr, mapKeySize := b.createTemporaryAlloca(llvmStoredKeyType, "range.key")
mapValueAlloca, mapValuePtr, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyPtr, mapValuePtr}, "range.next")
mapKey := b.CreateLoad(mapKeyAlloca, "")
mapValue := b.CreateLoad(mapValueAlloca, "")
if isKeyStoredAsInterface {
// The key is stored as an interface but it isn't of interface type.
// Extract the underlying value.
mapKey = b.extractValueFromInterface(mapKey, llvmKeyType)
}
// End the lifetimes of the allocas, because we're done with them.
b.emitLifetimeEnd(mapKeyPtr, mapKeySize)
b.emitLifetimeEnd(mapValuePtr, mapValueSize)
// Construct the *ssa.Next return value: {ok, mapKey, mapValue}
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
tuple = b.CreateInsertValue(tuple, ok, 0, "")
tuple = b.CreateInsertValue(tuple, mapKey, 1, "")
tuple = b.CreateInsertValue(tuple, mapValue, 2, "")
return tuple
}
// Returns true if this key type does not contain strings, interfaces etc., so
// can be compared with runtime.memequal.
func hashmapIsBinaryKey(keyType types.Type) bool {
+9 -21
View File
@@ -84,7 +84,6 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
// closures and bound methods, but should be optimized away when not used.
if !info.exported {
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "context", flags: 0})
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "parentHandle", flags: 0})
}
var paramTypes []llvm.Type
@@ -208,14 +207,9 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
// present in *ssa.Function, such as the link name and whether it should be
// exported.
func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
info := functionInfo{}
if strings.HasPrefix(f.Name(), "C.") {
// Created by CGo: such a name cannot be created by regular C code.
info.linkName = f.Name()[2:]
info.exported = true
} else {
info := functionInfo{
// Pick the default linkName.
info.linkName = f.RelString(nil)
linkName: f.RelString(nil),
}
// Check for //go: pragmas, which may change the link name (among others).
info.parsePragmas(f)
@@ -460,20 +454,14 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
// getGlobalInfo returns some information about a specific global.
func (c *compilerContext) getGlobalInfo(g *ssa.Global) globalInfo {
info := globalInfo{}
if strings.HasPrefix(g.Name(), "C.") {
// Created by CGo: such a name cannot be created by regular C code.
info.linkName = g.Name()[2:]
info.extern = true
} else {
info := globalInfo{
// Pick the default linkName.
info.linkName = g.RelString(nil)
// Check for //go: pragmas, which may change the link name (among
// others).
doc := c.astComments[info.linkName]
if doc != nil {
info.parsePragmas(doc)
}
linkName: g.RelString(nil),
}
// Check for //go: pragmas, which may change the link name (among others).
doc := c.astComments[info.linkName]
if doc != nil {
info.parsePragmas(doc)
}
return info
}
+5 -5
View File
@@ -56,7 +56,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
}
constraints += ",~{rcx},~{r11}"
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel)
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel, false)
return b.CreateCall(target, args, ""), nil
case b.GOARCH == "386" && b.GOOS == "linux":
// Sources:
@@ -82,7 +82,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
argTypes = append(argTypes, llvmValue.Type())
}
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel)
target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel, false)
return b.CreateCall(target, args, ""), nil
case b.GOARCH == "arm" && b.GOOS == "linux":
// Implement the EABI system call convention for Linux.
@@ -114,7 +114,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
constraints += ",~{r" + strconv.Itoa(i) + "}"
}
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0, false)
return b.CreateCall(target, args, ""), nil
case b.GOARCH == "arm64" && b.GOOS == "linux":
// Source: syscall(2) man page.
@@ -146,7 +146,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
}
constraints += ",~{x16},~{x17}" // scratch registers
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0, false)
return b.CreateCall(target, args, ""), nil
default:
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
@@ -157,7 +157,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
// functions, depending on the target OS/arch.
func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
switch b.GOOS {
case "linux", "freebsd":
case "linux":
syscallResult, err := b.createRawSyscall(call)
if err != nil {
return syscallResult, err
+30 -28
View File
@@ -1,41 +1,43 @@
; ModuleID = 'basic.go'
source_filename = "basic.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
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"
%main.kv = type { float }
%main.kv.0 = type { i8 }
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.addInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.addInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
entry:
%0 = add i32 %x, %y
ret i32 %0
}
; Function Attrs: nounwind
define hidden i1 @main.equalInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.equalInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
entry:
%0 = icmp eq i32 %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i32 @main.divInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.divInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0
call void @runtime.divideByZeroPanic(i8* undef) #0
unreachable
divbyzero.next: ; preds = %entry
@@ -47,16 +49,16 @@ divbyzero.next: ; preds = %entry
ret i32 %5
}
declare void @runtime.divideByZeroPanic(i8*, i8*)
declare void @runtime.divideByZeroPanic(i8*)
; Function Attrs: nounwind
define hidden i32 @main.divUint(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.divUint(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0
call void @runtime.divideByZeroPanic(i8* undef) #0
unreachable
divbyzero.next: ; preds = %entry
@@ -65,13 +67,13 @@ divbyzero.next: ; preds = %entry
}
; Function Attrs: nounwind
define hidden i32 @main.remInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.remInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0
call void @runtime.divideByZeroPanic(i8* undef) #0
unreachable
divbyzero.next: ; preds = %entry
@@ -84,13 +86,13 @@ divbyzero.next: ; preds = %entry
}
; Function Attrs: nounwind
define hidden i32 @main.remUint(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.remUint(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0
call void @runtime.divideByZeroPanic(i8* undef) #0
unreachable
divbyzero.next: ; preds = %entry
@@ -99,61 +101,61 @@ divbyzero.next: ; preds = %entry
}
; Function Attrs: nounwind
define hidden i1 @main.floatEQ(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.floatEQ(float %x, float %y, i8* %context) unnamed_addr #0 {
entry:
%0 = fcmp oeq float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatNE(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.floatNE(float %x, float %y, i8* %context) unnamed_addr #0 {
entry:
%0 = fcmp une float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatLower(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.floatLower(float %x, float %y, i8* %context) unnamed_addr #0 {
entry:
%0 = fcmp olt float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatLowerEqual(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.floatLowerEqual(float %x, float %y, i8* %context) unnamed_addr #0 {
entry:
%0 = fcmp ole float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatGreater(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.floatGreater(float %x, float %y, i8* %context) unnamed_addr #0 {
entry:
%0 = fcmp ogt float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatGreaterEqual(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.floatGreaterEqual(float %x, float %y, i8* %context) unnamed_addr #0 {
entry:
%0 = fcmp oge float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden float @main.complexReal(float %x.r, float %x.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden float @main.complexReal(float %x.r, float %x.i, i8* %context) unnamed_addr #0 {
entry:
ret float %x.r
}
; Function Attrs: nounwind
define hidden float @main.complexImag(float %x.r, float %x.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden float @main.complexImag(float %x.r, float %x.i, i8* %context) unnamed_addr #0 {
entry:
ret float %x.i
}
; Function Attrs: nounwind
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #0 {
entry:
%0 = fadd float %x.r, %y.r
%1 = fadd float %x.i, %y.i
@@ -163,7 +165,7 @@ entry:
}
; Function Attrs: nounwind
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #0 {
entry:
%0 = fsub float %x.r, %y.r
%1 = fsub float %x.i, %y.i
@@ -173,7 +175,7 @@ entry:
}
; Function Attrs: nounwind
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #0 {
entry:
%0 = fmul float %x.r, %y.r
%1 = fmul float %x.i, %y.i
@@ -187,14 +189,14 @@ entry:
}
; Function Attrs: nounwind
define hidden void @main.foo(%main.kv* dereferenceable_or_null(4) %a, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.foo(%main.kv* dereferenceable_or_null(4) %a, i8* %context) unnamed_addr #0 {
entry:
call void @"main.foo$1"(%main.kv.0* null, i8* undef, i8* undef)
call void @"main.foo$1"(%main.kv.0* null, i8* undef)
ret void
}
; Function Attrs: nounwind
define hidden void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #0 {
entry:
ret void
}
+26 -20
View File
@@ -1,25 +1,28 @@
; ModuleID = 'channel.go'
source_filename = "channel.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
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"
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
%"internal/task.gcData" = type { i8* }
%"internal/task.state" = type { i32, i8*, %"internal/task.stackState", i1 }
%"internal/task.stackState" = type { i32, i32 }
%runtime.chanSelectState = type { %runtime.channel*, i8* }
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.chanIntSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.chanIntSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
entry:
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
%chan.value = alloca i32, align 4
@@ -28,22 +31,22 @@ entry:
store i32 3, i32* %chan.value, align 4
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
call void @runtime.chanSend(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef, i8* null) #0
call void @runtime.chanSend(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
ret void
}
; Function Attrs: argmemonly nounwind willreturn
; Function Attrs: argmemonly nofree nosync nounwind willreturn
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
declare void @runtime.chanSend(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*, i8*)
declare void @runtime.chanSend(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*)
; Function Attrs: argmemonly nounwind willreturn
; Function Attrs: argmemonly nofree nosync nounwind willreturn
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
; Function Attrs: nounwind
define hidden void @main.chanIntRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.chanIntRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
entry:
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
%chan.value = alloca i32, align 4
@@ -51,38 +54,41 @@ entry:
call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef, i8* null) #0
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
ret void
}
declare i1 @runtime.chanRecv(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*, i8*)
declare i1 @runtime.chanRecv(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*)
; Function Attrs: nounwind
define hidden void @main.chanZeroSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.chanZeroSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
entry:
%complit = alloca {}, align 8
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
%0 = bitcast {}* %complit to i8*
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
call void @runtime.chanSend(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef, i8* null) #0
call void @runtime.chanSend(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
ret void
}
; Function Attrs: nounwind
define hidden void @main.chanZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.chanZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
entry:
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef, i8* null) #0
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
ret void
}
; Function Attrs: nounwind
define hidden void @main.selectZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch1, %runtime.channel* dereferenceable_or_null(32) %ch2, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.selectZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch1, %runtime.channel* dereferenceable_or_null(32) %ch2, i8* %context) unnamed_addr #0 {
entry:
%select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8
%select.send.value = alloca i32, align 4
@@ -99,7 +105,7 @@ entry:
%.repack4 = getelementptr inbounds [2 x %runtime.chanSelectState], [2 x %runtime.chanSelectState]* %select.states.alloca, i32 0, i32 1, i32 1
store i8* null, i8** %.repack4, align 4
%select.states = getelementptr inbounds [2 x %runtime.chanSelectState], [2 x %runtime.chanSelectState]* %select.states.alloca, i32 0, i32 0
%select.result = call { i32, i1 } @runtime.tryChanSelect(i8* undef, %runtime.chanSelectState* nonnull %select.states, i32 2, i32 2, i8* undef, i8* null) #0
%select.result = call { i32, i1 } @runtime.tryChanSelect(i8* undef, %runtime.chanSelectState* nonnull %select.states, i32 2, i32 2, i8* undef) #0
call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %select.states.alloca.bitcast)
%1 = extractvalue { i32, i1 } %select.result, 0
%2 = icmp eq i32 %1, 0
@@ -116,7 +122,7 @@ select.body: ; preds = %select.next
br label %select.done
}
declare { i32, i1 } @runtime.tryChanSelect(i8*, %runtime.chanSelectState*, i32, i32, i8*, i8*)
declare { i32, i1 } @runtime.tryChanSelect(i8*, %runtime.chanSelectState*, i32, i32, i8*)
attributes #0 = { nounwind }
attributes #1 = { argmemonly nounwind willreturn }
attributes #1 = { argmemonly nofree nosync nounwind willreturn }
+13 -11
View File
@@ -1,18 +1,20 @@
; ModuleID = 'float.go'
source_filename = "float.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
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*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.f32tou32(float %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.f32tou32(float %v, i8* %context) unnamed_addr #0 {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
@@ -24,25 +26,25 @@ entry:
}
; Function Attrs: nounwind
define hidden float @main.maxu32f(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden float @main.maxu32f(i8* %context) unnamed_addr #0 {
entry:
ret float 0x41F0000000000000
}
; Function Attrs: nounwind
define hidden i32 @main.maxu32tof32(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.maxu32tof32(i8* %context) unnamed_addr #0 {
entry:
ret i32 -1
}
; Function Attrs: nounwind
define hidden { i32, i32, i32, i32 } @main.inftoi32(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { i32, i32, i32, i32 } @main.inftoi32(i8* %context) unnamed_addr #0 {
entry:
ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 }
}
; Function Attrs: nounwind
define hidden i32 @main.u32tof32tou32(i32 %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.u32tof32tou32(i32 %v, i8* %context) unnamed_addr #0 {
entry:
%0 = uitofp i32 %v to float
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
@@ -52,7 +54,7 @@ entry:
}
; Function Attrs: nounwind
define hidden float @main.f32tou32tof32(float %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden float @main.f32tou32tof32(float %v, i8* %context) unnamed_addr #0 {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
@@ -65,7 +67,7 @@ entry:
}
; Function Attrs: nounwind
define hidden i8 @main.f32tou8(float %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i8 @main.f32tou8(float %v, i8* %context) unnamed_addr #0 {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 2.550000e+02
@@ -77,7 +79,7 @@ entry:
}
; Function Attrs: nounwind
define hidden i8 @main.f32toi8(float %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i8 @main.f32toi8(float %v, i8* %context) unnamed_addr #0 {
entry:
%abovemin = fcmp oge float %v, -1.280000e+02
%belowmax = fcmp ole float %v, 1.270000e+02
-53
View File
@@ -1,53 +0,0 @@
; ModuleID = 'func.go'
source_filename = "func.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
%runtime.funcValueWithSignature = type { i32, i8* }
@"reflect/types.funcid:func:{basic:int}{}" = external constant i8
@"main.someFunc$withSignature" = linkonce_odr constant %runtime.funcValueWithSignature { i32 ptrtoint (void (i32, i8*, i8*)* @main.someFunc to i32), i8* @"reflect/types.funcid:func:{basic:int}{}" }
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.foo(i8* %callback.context, i32 %callback.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i32 @runtime.getFuncPtr(i8* %callback.context, i32 %callback.funcptr, i8* nonnull @"reflect/types.funcid:func:{basic:int}{}", i8* undef, i8* null) #0
%1 = icmp eq i32 %0, 0
br i1 %1, label %fpcall.throw, label %fpcall.next
fpcall.throw: ; preds = %entry
call void @runtime.nilPanic(i8* undef, i8* null) #0
unreachable
fpcall.next: ; preds = %entry
%2 = inttoptr i32 %0 to void (i32, i8*, i8*)*
call void %2(i32 3, i8* %callback.context, i8* undef) #0
ret void
}
declare i32 @runtime.getFuncPtr(i8*, i32, i8* dereferenceable_or_null(1), i8*, i8*)
declare void @runtime.nilPanic(i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.bar(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @main.foo(i8* undef, i32 ptrtoint (%runtime.funcValueWithSignature* @"main.someFunc$withSignature" to i32), i8* undef, i8* undef)
ret void
}
; Function Attrs: nounwind
define hidden void @main.someFunc(i32 %arg0, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
attributes #0 = { nounwind }
+47
View File
@@ -0,0 +1,47 @@
; ModuleID = 'func.go'
source_filename = "func.go"
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.foo(i8* %callback.context, void ()* %callback.funcptr, i8* %context) unnamed_addr #0 {
entry:
%0 = icmp eq void ()* %callback.funcptr, null
br i1 %0, label %fpcall.throw, label %fpcall.next
fpcall.throw: ; preds = %entry
call void @runtime.nilPanic(i8* undef) #0
unreachable
fpcall.next: ; preds = %entry
%1 = bitcast void ()* %callback.funcptr to void (i32, i8*)*
call void %1(i32 3, i8* %callback.context) #0
ret void
}
declare void @runtime.nilPanic(i8*)
; Function Attrs: nounwind
define hidden void @main.bar(i8* %context) unnamed_addr #0 {
entry:
call void @main.foo(i8* undef, void ()* bitcast (void (i32, i8*)* @main.someFunc to void ()*), i8* undef)
ret void
}
; Function Attrs: nounwind
define hidden void @main.someFunc(i32 %arg0, i8* %context) unnamed_addr #0 {
entry:
ret void
}
attributes #0 = { nounwind }
+8 -5
View File
@@ -20,6 +20,10 @@ var (
y [60]uintptr
z *byte
}
struct4 *struct {
x *byte
y [61]uintptr
}
slice1 []byte
slice2 []*int
@@ -50,14 +54,13 @@ func newStruct() {
y [60]uintptr
z *byte
})
struct4 = new(struct {
x *byte
y [61]uintptr
})
}
func newFuncValue() *func() {
// On some platforms that use runtime.funcValue ("switch" style) function
// values, a func value is allocated as having two pointer words while the
// struct looks like {unsafe.Pointer; uintptr}. This is so that the interp
// package won't get confused, see getPointerBitmap in compiler/llvm.go for
// details.
return new(func())
}
+47 -24
View File
@@ -1,6 +1,6 @@
; ModuleID = 'gc.go'
source_filename = "gc.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
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"
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID*, i32 }
@@ -17,79 +17,100 @@ target triple = "wasm32-unknown-wasi"
@main.struct1 = hidden global {}* null, align 4
@main.struct2 = hidden global { i32, i32 }* null, align 4
@main.struct3 = hidden global { i8*, [60 x i32], i8* }* null, align 4
@main.struct4 = hidden global { i8*, [61 x i32] }* null, align 4
@main.slice1 = hidden global { i8*, i32, i32 } zeroinitializer, align 8
@main.slice2 = hidden global { i32**, i32, i32 } zeroinitializer, align 8
@main.slice3 = hidden global { { i8*, i32, i32 }*, i32, i32 } zeroinitializer, align 8
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c" \00\00\00\00\00\00\01" }
@"runtime/gc.layout:62-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\00\00\00\00\00\00\00\01" }
@"reflect/types.type:basic:complex128" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* null, i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:basic:complex128", i32 0 }
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:complex128", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null, i32 0 }
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.newScalar(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.newScalar(i8* %context) unnamed_addr #0 {
entry:
%new = call i8* @runtime.alloc(i32 1, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%new = call i8* @runtime.alloc(i32 1, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
store i8* %new, i8** @main.scalar1, align 4
%new1 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%new1 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #0
store i8* %new1, i8** bitcast (i32** @main.scalar2 to i8**), align 4
%new2 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%new2 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #0
store i8* %new2, i8** bitcast (i64** @main.scalar3 to i8**), align 4
%new3 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%new3 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new3, i8* undef) #0
store i8* %new3, i8** bitcast (float** @main.scalar4 to i8**), align 4
ret void
}
; Function Attrs: nounwind
define hidden void @main.newArray(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.newArray(i8* %context) unnamed_addr #0 {
entry:
%new = call i8* @runtime.alloc(i32 3, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%new = call i8* @runtime.alloc(i32 3, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
store i8* %new, i8** bitcast ([3 x i8]** @main.array1 to i8**), align 4
%new1 = call i8* @runtime.alloc(i32 71, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%new1 = call i8* @runtime.alloc(i32 71, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #0
store i8* %new1, i8** bitcast ([71 x i8]** @main.array2 to i8**), align 4
%new2 = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 67 to i8*), i8* undef, i8* null) #0
%new2 = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 67 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #0
store i8* %new2, i8** bitcast ([3 x i8*]** @main.array3 to i8**), align 4
ret void
}
; Function Attrs: nounwind
define hidden void @main.newStruct(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.newStruct(i8* %context) unnamed_addr #0 {
entry:
%new = call i8* @runtime.alloc(i32 0, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%new = call i8* @runtime.alloc(i32 0, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
store i8* %new, i8** bitcast ({}** @main.struct1 to i8**), align 4
%new1 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%new1 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #0
store i8* %new1, i8** bitcast ({ i32, i32 }** @main.struct2 to i8**), align 4
%new2 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-2000000000000001" to i8*), i8* undef, i8* null) #0
%new2 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-2000000000000001" to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #0
store i8* %new2, i8** bitcast ({ i8*, [60 x i32], i8* }** @main.struct3 to i8**), align 4
%new3 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-0001" to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new3, i8* undef) #0
store i8* %new3, i8** bitcast ({ i8*, [61 x i32] }** @main.struct4 to i8**), align 4
ret void
}
; Function Attrs: nounwind
define hidden { i8*, void ()* }* @main.newFuncValue(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { i8*, void ()* }* @main.newFuncValue(i8* %context) unnamed_addr #0 {
entry:
%new = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 197 to i8*), i8* undef, i8* null) #0
%new = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 197 to i8*), i8* undef) #0
%0 = bitcast i8* %new to { i8*, void ()* }*
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
ret { i8*, void ()* }* %0
}
; Function Attrs: nounwind
define hidden void @main.makeSlice(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.makeSlice(i8* %context) unnamed_addr #0 {
entry:
%makeslice = call i8* @runtime.alloc(i32 5, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%makeslice = call i8* @runtime.alloc(i32 5, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #0
store i8* %makeslice, i8** getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 0), align 8
store i32 5, i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 1), align 4
store i32 5, i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 2), align 8
%makeslice1 = call i8* @runtime.alloc(i32 20, i8* nonnull inttoptr (i32 67 to i8*), i8* undef, i8* null) #0
%makeslice1 = call i8* @runtime.alloc(i32 20, i8* nonnull inttoptr (i32 67 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %makeslice1, i8* undef) #0
store i8* %makeslice1, i8** bitcast ({ i32**, i32, i32 }* @main.slice2 to i8**), align 8
store i32 5, i32* getelementptr inbounds ({ i32**, i32, i32 }, { i32**, i32, i32 }* @main.slice2, i32 0, i32 1), align 4
store i32 5, i32* getelementptr inbounds ({ i32**, i32, i32 }, { i32**, i32, i32 }* @main.slice2, i32 0, i32 2), align 8
%makeslice3 = call i8* @runtime.alloc(i32 60, i8* nonnull inttoptr (i32 71 to i8*), i8* undef, i8* null) #0
%makeslice3 = call i8* @runtime.alloc(i32 60, i8* nonnull inttoptr (i32 71 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %makeslice3, i8* undef) #0
store i8* %makeslice3, i8** bitcast ({ { i8*, i32, i32 }*, i32, i32 }* @main.slice3 to i8**), align 8
store i32 5, i32* getelementptr inbounds ({ { i8*, i32, i32 }*, i32, i32 }, { { i8*, i32, i32 }*, i32, i32 }* @main.slice3, i32 0, i32 1), align 4
store i32 5, i32* getelementptr inbounds ({ { i8*, i32, i32 }*, i32, i32 }, { { i8*, i32, i32 }*, i32, i32 }* @main.slice3, i32 0, i32 2), align 8
@@ -97,15 +118,17 @@ entry:
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, i8* %context) unnamed_addr #0 {
entry:
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef, i8* null) #0
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
%.repack = bitcast i8* %0 to double*
store double %v.r, double* %.repack, align 8
%.repack1 = getelementptr inbounds i8, i8* %0, i32 8
%1 = bitcast i8* %.repack1 to double*
store double %v.i, double* %1, align 8
%2 = insertvalue %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:basic:complex128" to i32), i8* undef }, i8* %0, 1
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
ret %runtime._interface %2
}
+31 -19
View File
@@ -1,39 +1,43 @@
; ModuleID = 'go1.17.go'
source_filename = "go1.17.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
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*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i8* @main.Add32(i8* %p, i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i8* @main.Add32(i8* %p, i32 %len, i8* %context) unnamed_addr #0 {
entry:
%0 = getelementptr i8, i8* %p, i32 %len
call void @runtime.trackPointer(i8* %0, i8* undef) #0
ret i8* %0
}
; Function Attrs: nounwind
define hidden i8* @main.Add64(i8* %p, i64 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i8* @main.Add64(i8* %p, i64 %len, i8* %context) unnamed_addr #0 {
entry:
%0 = trunc i64 %len to i32
%1 = getelementptr i8, i8* %p, i32 %0
call void @runtime.trackPointer(i8* %1, i8* undef) #0
ret i8* %1
}
; Function Attrs: nounwind
define hidden [4 x i32]* @main.SliceToArray(i32* %s.data, i32 %s.len, i32 %s.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden [4 x i32]* @main.SliceToArray(i32* %s.data, i32 %s.len, i32 %s.cap, i8* %context) unnamed_addr #0 {
entry:
%0 = icmp ult i32 %s.len, 4
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
slicetoarray.throw: ; preds = %entry
call void @runtime.sliceToArrayPointerPanic(i8* undef, i8* null) #0
call void @runtime.sliceToArrayPointerPanic(i8* undef) #0
unreachable
slicetoarray.next: ; preds = %entry
@@ -41,12 +45,13 @@ slicetoarray.next: ; preds = %entry
ret [4 x i32]* %1
}
declare void @runtime.sliceToArrayPointerPanic(i8*, i8*)
declare void @runtime.sliceToArrayPointerPanic(i8*)
; Function Attrs: nounwind
define hidden [4 x i32]* @main.SliceToArrayConst(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden [4 x i32]* @main.SliceToArrayConst(i8* %context) unnamed_addr #0 {
entry:
%makeslice = call i8* @runtime.alloc(i32 24, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%makeslice = call i8* @runtime.alloc(i32 24, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #0
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
slicetoarray.throw: ; preds = %entry
@@ -58,7 +63,7 @@ slicetoarray.next: ; preds = %entry
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.SliceInt(i32* dereferenceable_or_null(4) %ptr, i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { i32*, i32, i32 } @main.SliceInt(i32* dereferenceable_or_null(4) %ptr, i32 %len, i8* %context) unnamed_addr #0 {
entry:
%0 = icmp ugt i32 %len, 1073741823
%1 = icmp eq i32* %ptr, null
@@ -68,20 +73,22 @@ entry:
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0
call void @runtime.unsafeSlicePanic(i8* undef) #0
unreachable
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) #0
ret { i32*, i32, i32 } %7
}
declare void @runtime.unsafeSlicePanic(i8*, i8*)
declare void @runtime.unsafeSlicePanic(i8*)
; Function Attrs: nounwind
define hidden { i8*, i32, i32 } @main.SliceUint16(i8* dereferenceable_or_null(1) %ptr, i16 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { i8*, i32, i32 } @main.SliceUint16(i8* dereferenceable_or_null(1) %ptr, i16 %len, i8* %context) unnamed_addr #0 {
entry:
%0 = icmp eq i8* %ptr, null
%1 = icmp ne i16 %len, 0
@@ -89,7 +96,7 @@ entry:
br i1 %2, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0
call void @runtime.unsafeSlicePanic(i8* undef) #0
unreachable
unsafe.Slice.next: ; preds = %entry
@@ -97,11 +104,12 @@ unsafe.Slice.next: ; preds = %entry
%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) #0
ret { i8*, i32, i32 } %6
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.SliceUint64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { i32*, i32, i32 } @main.SliceUint64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #0 {
entry:
%0 = icmp ugt i64 %len, 1073741823
%1 = icmp eq i32* %ptr, null
@@ -111,7 +119,7 @@ entry:
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0
call void @runtime.unsafeSlicePanic(i8* undef) #0
unreachable
unsafe.Slice.next: ; preds = %entry
@@ -119,11 +127,13 @@ unsafe.Slice.next: ; preds = %entry
%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) #0
ret { i32*, i32, i32 } %8
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.SliceInt64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { i32*, i32, i32 } @main.SliceInt64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #0 {
entry:
%0 = icmp ugt i64 %len, 1073741823
%1 = icmp eq i32* %ptr, null
@@ -133,7 +143,7 @@ entry:
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0
call void @runtime.unsafeSlicePanic(i8* undef) #0
unreachable
unsafe.Slice.next: ; preds = %entry
@@ -141,6 +151,8 @@ unsafe.Slice.next: ; preds = %entry
%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) #0
ret { i32*, i32, i32 } %8
}
+45 -44
View File
@@ -5,52 +5,53 @@ target triple = "thumbv7m-unknown-unknown-eabi"
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
%"internal/task.gcData" = type {}
%"internal/task.state" = type { i32, i32* }
%runtime.chanSelectState = type { %runtime.channel*, i8* }
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.regularFunctionGoroutine(i8* %context) unnamed_addr #0 {
entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* undef, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef, i8* null) #0
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef) #0
ret void
}
declare void @main.regularFunction(i32, i8*, i8*)
declare void @main.regularFunction(i32, i8*)
; Function Attrs: nounwind
define linkonce_odr void @"main.regularFunction$gowrapper"(i8* %0) unnamed_addr #1 {
entry:
%unpack.int = ptrtoint i8* %0 to i32
call void @main.regularFunction(i32 %unpack.int, i8* undef, i8* undef) #0
call void @main.regularFunction(i32 %unpack.int, i8* undef) #0
ret void
}
declare i32 @"internal/task.getGoroutineStackSize"(i32, i8*, i8*)
declare i32 @"internal/task.getGoroutineStackSize"(i32, i8*)
declare void @"internal/task.start"(i32, i8*, i32, i8*, i8*)
declare void @"internal/task.start"(i32, i8*, i32, i8*)
; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.inlineFunctionGoroutine(i8* %context) unnamed_addr #0 {
entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* undef, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef, i8* null) #0
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef) #0
ret void
}
; Function Attrs: nounwind
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
entry:
ret void
}
@@ -59,31 +60,31 @@ entry:
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #2 {
entry:
%unpack.int = ptrtoint i8* %0 to i32
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef, i8* undef)
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef)
ret void
}
; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.closureFunctionGoroutine(i8* %context) unnamed_addr #0 {
entry:
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
%0 = bitcast i8* %n to i32*
store i32 3, i32* %0, align 4
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef, i8* null) #0
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef) #0
%2 = bitcast i8* %1 to i32*
store i32 5, i32* %2, align 4
%3 = getelementptr inbounds i8, i8* %1, i32 4
%4 = bitcast i8* %3 to i8**
store i8* %n, i8** %4, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* undef, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 %stacksize, i8* undef, i8* null) #0
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 %stacksize, i8* undef) #0
%5 = load i32, i32* %0, align 4
call void @runtime.printint32(i32 %5, i8* undef, i8* null) #0
call void @runtime.printint32(i32 %5, i8* undef) #0
ret void
}
; Function Attrs: nounwind
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
entry:
%unpack.ptr = bitcast i8* %context to i32*
store i32 7, i32* %unpack.ptr, align 4
@@ -98,16 +99,16 @@ entry:
%3 = getelementptr inbounds i8, i8* %0, i32 4
%4 = bitcast i8* %3 to i8**
%5 = load i8*, i8** %4, align 4
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5, i8* undef)
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5)
ret void
}
declare void @runtime.printint32(i32, i8*, i8*)
declare void @runtime.printint32(i32, i8*)
; Function Attrs: nounwind
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context) unnamed_addr #0 {
entry:
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef, i8* null) #0
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef) #0
%1 = bitcast i8* %0 to i32*
store i32 5, i32* %1, align 4
%2 = getelementptr inbounds i8, i8* %0, i32 4
@@ -116,8 +117,8 @@ entry:
%4 = getelementptr inbounds i8, i8* %0, i32 8
%5 = bitcast i8* %4 to void ()**
store void ()* %fn.funcptr, void ()** %5, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* undef, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 %stacksize, i8* undef, i8* null) #0
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 %stacksize, i8* undef) #0
ret void
}
@@ -130,40 +131,40 @@ entry:
%4 = bitcast i8* %3 to i8**
%5 = load i8*, i8** %4, align 4
%6 = getelementptr inbounds i8, i8* %0, i32 8
%7 = bitcast i8* %6 to void (i32, i8*, i8*)**
%8 = load void (i32, i8*, i8*)*, void (i32, i8*, i8*)** %7, align 4
call void %8(i32 %2, i8* %5, i8* undef) #0
%7 = bitcast i8* %6 to void (i32, i8*)**
%8 = load void (i32, i8*)*, void (i32, i8*)** %7, align 4
call void %8(i32 %2, i8* %5) #0
ret void
}
; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.recoverBuiltinGoroutine(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #0 {
entry:
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef, i8* null) #0
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef) #0
ret void
}
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*)
; Function Attrs: nounwind
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
entry:
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef, i8* null) #0
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef) #0
ret void
}
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*, i8*)
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*)
; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
entry:
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef, i8* null) #0
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #0
%1 = bitcast i8* %0 to i8**
store i8* %itf.value, i8** %1, align 4
%2 = getelementptr inbounds i8, i8* %0, i32 4
@@ -175,12 +176,12 @@ entry:
%4 = getelementptr inbounds i8, i8* %0, i32 12
%5 = bitcast i8* %4 to i32*
store i32 %itf.typecode, i32* %5, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* undef, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 %stacksize, i8* undef, i8* null) #0
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 %stacksize, i8* undef) #0
ret void
}
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*, i8*) #5
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*) #5
; Function Attrs: nounwind
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(i8* %0) unnamed_addr #6 {
@@ -196,7 +197,7 @@ entry:
%9 = getelementptr inbounds i8, i8* %0, i32 12
%10 = bitcast i8* %9 to i32*
%11 = load i32, i32* %10, align 4
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef, i8* undef) #0
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef) #0
ret void
}
+54 -45
View File
@@ -1,56 +1,59 @@
; ModuleID = 'goroutine.go'
source_filename = "goroutine.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
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"
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
%"internal/task.gcData" = type { i8* }
%"internal/task.state" = type { i32, i8*, %"internal/task.stackState", i1 }
%"internal/task.stackState" = type { i32, i32 }
%runtime.chanSelectState = type { %runtime.channel*, i8* }
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.regularFunctionGoroutine(i8* %context) unnamed_addr #0 {
entry:
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 8192, i8* undef, i8* null) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 16384, i8* undef) #0
ret void
}
declare void @main.regularFunction(i32, i8*, i8*)
declare void @main.regularFunction(i32, i8*)
declare void @runtime.deadlock(i8*, i8*)
declare void @runtime.deadlock(i8*)
; Function Attrs: nounwind
define linkonce_odr void @"main.regularFunction$gowrapper"(i8* %0) unnamed_addr #1 {
entry:
%unpack.int = ptrtoint i8* %0 to i32
call void @main.regularFunction(i32 %unpack.int, i8* undef, i8* undef) #0
call void @runtime.deadlock(i8* undef, i8* undef) #0
call void @main.regularFunction(i32 %unpack.int, i8* undef) #0
call void @runtime.deadlock(i8* undef) #0
unreachable
}
declare void @"internal/task.start"(i32, i8*, i32, i8*, i8*)
declare void @"internal/task.start"(i32, i8*, i32, i8*)
; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.inlineFunctionGoroutine(i8* %context) unnamed_addr #0 {
entry:
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 8192, i8* undef, i8* null) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 16384, i8* undef) #0
ret void
}
; Function Attrs: nounwind
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
entry:
ret void
}
@@ -59,31 +62,35 @@ entry:
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #2 {
entry:
%unpack.int = ptrtoint i8* %0 to i32
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef, i8* undef)
call void @runtime.deadlock(i8* undef, i8* undef) #0
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef)
call void @runtime.deadlock(i8* undef) #0
unreachable
}
; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.closureFunctionGoroutine(i8* %context) unnamed_addr #0 {
entry:
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
%0 = bitcast i8* %n to i32*
call void @runtime.trackPointer(i8* nonnull %n, i8* undef) #0
store i32 3, i32* %0, align 4
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef, i8* null) #0
call void @runtime.trackPointer(i8* nonnull %n, i8* undef) #0
call void @runtime.trackPointer(i8* bitcast (void (i32, i8*)* @"main.closureFunctionGoroutine$1" to i8*), i8* undef) #0
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #0
%2 = bitcast i8* %1 to i32*
store i32 5, i32* %2, align 4
%3 = getelementptr inbounds i8, i8* %1, i32 4
%4 = bitcast i8* %3 to i8**
store i8* %n, i8** %4, align 4
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 8192, i8* undef, i8* null) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 16384, i8* undef) #0
%5 = load i32, i32* %0, align 4
call void @runtime.printint32(i32 %5, i8* undef, i8* null) #0
call void @runtime.printint32(i32 %5, i8* undef) #0
ret void
}
; Function Attrs: nounwind
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
entry:
%unpack.ptr = bitcast i8* %context to i32*
store i32 7, i32* %unpack.ptr, align 4
@@ -98,17 +105,18 @@ entry:
%3 = getelementptr inbounds i8, i8* %0, i32 4
%4 = bitcast i8* %3 to i8**
%5 = load i8*, i8** %4, align 4
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5, i8* undef)
call void @runtime.deadlock(i8* undef, i8* undef) #0
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5)
call void @runtime.deadlock(i8* undef) #0
unreachable
}
declare void @runtime.printint32(i32, i8*, i8*)
declare void @runtime.printint32(i32, i8*)
; Function Attrs: nounwind
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context) unnamed_addr #0 {
entry:
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef, i8* null) #0
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
%1 = bitcast i8* %0 to i32*
store i32 5, i32* %1, align 4
%2 = getelementptr inbounds i8, i8* %0, i32 4
@@ -117,7 +125,7 @@ entry:
%4 = getelementptr inbounds i8, i8* %0, i32 8
%5 = bitcast i8* %4 to void ()**
store void ()* %fn.funcptr, void ()** %5, align 4
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 8192, i8* undef, i8* null) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 16384, i8* undef) #0
ret void
}
@@ -130,41 +138,42 @@ entry:
%4 = bitcast i8* %3 to i8**
%5 = load i8*, i8** %4, align 4
%6 = getelementptr inbounds i8, i8* %0, i32 8
%7 = bitcast i8* %6 to void (i32, i8*, i8*)**
%8 = load void (i32, i8*, i8*)*, void (i32, i8*, i8*)** %7, align 4
call void %8(i32 %2, i8* %5, i8* undef) #0
call void @runtime.deadlock(i8* undef, i8* undef) #0
%7 = bitcast i8* %6 to void (i32, i8*)**
%8 = load void (i32, i8*)*, void (i32, i8*)** %7, align 4
call void %8(i32 %2, i8* %5) #0
call void @runtime.deadlock(i8* undef) #0
unreachable
}
; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.recoverBuiltinGoroutine(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #0 {
entry:
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef, i8* null) #0
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef) #0
ret void
}
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*)
; Function Attrs: nounwind
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
entry:
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef, i8* null) #0
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef) #0
ret void
}
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*, i8*)
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*)
; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
entry:
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef, i8* null) #0
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
%1 = bitcast i8* %0 to i8**
store i8* %itf.value, i8** %1, align 4
%2 = getelementptr inbounds i8, i8* %0, i32 4
@@ -176,11 +185,11 @@ entry:
%4 = getelementptr inbounds i8, i8* %0, i32 12
%5 = bitcast i8* %4 to i32*
store i32 %itf.typecode, i32* %5, align 4
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 8192, i8* undef, i8* null) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 16384, i8* undef) #0
ret void
}
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*, i8*) #5
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*) #5
; Function Attrs: nounwind
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(i8* %0) unnamed_addr #6 {
@@ -196,8 +205,8 @@ entry:
%9 = getelementptr inbounds i8, i8* %0, i32 12
%10 = bitcast i8* %9 to i32*
%11 = load i32, i32* %10, align 4
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef, i8* undef) #0
call void @runtime.deadlock(i8* undef, i8* undef) #0
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef) #0
call void @runtime.deadlock(i8* undef) #0
unreachable
}
-141
View File
@@ -1,141 +0,0 @@
; ModuleID = 'goroutine.go'
source_filename = "goroutine.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
%runtime.funcValueWithSignature = type { i32, i8* }
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
%"internal/task.state" = type { i8* }
%runtime.chanSelectState = type { %runtime.channel*, i8* }
@"main$pack" = internal unnamed_addr constant { i32, i8* } { i32 5, i8* undef }
@"main$pack.1" = internal unnamed_addr constant { i32, i8* } { i32 5, i8* undef }
@"reflect/types.funcid:func:{basic:int}{}" = external constant i8
@"main.closureFunctionGoroutine$1$withSignature" = linkonce_odr constant %runtime.funcValueWithSignature { i32 ptrtoint (void (i32, i8*, i8*)* @"main.closureFunctionGoroutine$1" to i32), i8* @"reflect/types.funcid:func:{basic:int}{}" }
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @main.regularFunction to i32), i8* bitcast ({ i32, i8* }* @"main$pack" to i8*), i32 undef, i8* undef, i8* null) #0
ret void
}
declare void @main.regularFunction(i32, i8*, i8*)
declare void @"internal/task.start"(i32, i8*, i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @"main.inlineFunctionGoroutine$1" to i32), i8* bitcast ({ i32, i8* }* @"main$pack.1" to i8*), i32 undef, i8* undef, i8* null) #0
ret void
}
; Function Attrs: nounwind
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%0 = bitcast i8* %n to i32*
store i32 3, i32* %0, align 4
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef, i8* null) #0
%2 = bitcast i8* %1 to i32*
store i32 5, i32* %2, align 4
%3 = getelementptr inbounds i8, i8* %1, i32 4
%4 = bitcast i8* %3 to i8**
store i8* %n, i8** %4, align 4
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @"main.closureFunctionGoroutine$1" to i32), i8* nonnull %1, i32 undef, i8* undef, i8* null) #0
%5 = load i32, i32* %0, align 4
call void @runtime.printint32(i32 %5, i8* undef, i8* null) #0
ret void
}
; Function Attrs: nounwind
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%unpack.ptr = bitcast i8* %context to i32*
store i32 7, i32* %unpack.ptr, align 4
ret void
}
declare void @runtime.printint32(i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.funcGoroutine(i8* %fn.context, i32 %fn.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i32 @runtime.getFuncPtr(i8* %fn.context, i32 %fn.funcptr, i8* nonnull @"reflect/types.funcid:func:{basic:int}{}", i8* undef, i8* null) #0
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef, i8* null) #0
%2 = bitcast i8* %1 to i32*
store i32 5, i32* %2, align 4
%3 = getelementptr inbounds i8, i8* %1, i32 4
%4 = bitcast i8* %3 to i8**
store i8* %fn.context, i8** %4, align 4
call void @"internal/task.start"(i32 %0, i8* nonnull %1, i32 undef, i8* undef, i8* null) #0
ret void
}
declare i32 @runtime.getFuncPtr(i8*, i32, i8* dereferenceable_or_null(1), i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef, i8* null) #0
ret void
}
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef, i8* null) #0
ret void
}
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef, i8* null) #0
%1 = bitcast i8* %0 to i8**
store i8* %itf.value, i8** %1, align 4
%2 = getelementptr inbounds i8, i8* %0, i32 4
%.repack = bitcast i8* %2 to i8**
store i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"main$string", i32 0, i32 0), i8** %.repack, align 4
%.repack1 = getelementptr inbounds i8, i8* %0, i32 8
%3 = bitcast i8* %.repack1 to i32*
store i32 4, i32* %3, align 4
%4 = getelementptr inbounds i8, i8* %0, i32 12
%5 = bitcast i8* %4 to i32*
store i32 %itf.typecode, i32* %5, align 4
call void @"internal/task.start"(i32 ptrtoint (void (i8*, i8*, i32, i32, i8*, i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke" to i32), i8* nonnull %0, i32 undef, i8* undef, i8* null) #0
ret void
}
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*, i8*) #1
attributes #0 = { nounwind }
attributes #1 = { "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
+27 -19
View File
@@ -1,6 +1,6 @@
; ModuleID = 'interface.go'
source_filename = "interface.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
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"
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID*, i32 }
@@ -22,46 +22,52 @@ target triple = "wasm32-unknown-wasi"
@"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"reflect/methods.String() string"]
@"reflect/types.typeid:basic:int" = external constant i8
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.simpleType(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden %runtime._interface @main.simpleType(i8* %context) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* null, i8* undef) #0
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:basic:int" to i32), i8* null }
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.pointerType(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden %runtime._interface @main.pointerType(i8* %context) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* null, i8* undef) #0
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:basic:int" to i32), i8* null }
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.interfaceType(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden %runtime._interface @main.interfaceType(i8* %context) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* null, i8* undef) #0
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:named:error" to i32), i8* null }
}
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i32) #1
; Function Attrs: nounwind
define hidden %runtime._interface @main.anonymousInterfaceType(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden %runtime._interface @main.anonymousInterfaceType(i8* %context) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* null, i8* undef) #0
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" to i32), i8* null }
}
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32) #2
; Function Attrs: nounwind
define hidden i1 @main.isInt(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.isInt(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
entry:
%typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef, i8* null) #0
%typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef) #0
br i1 %typecode, label %typeassert.ok, label %typeassert.next
typeassert.ok: ; preds = %entry
@@ -71,10 +77,10 @@ typeassert.next: ; preds = %typeassert.ok, %ent
ret i1 %typecode
}
declare i1 @runtime.typeAssert(i32, i8* dereferenceable_or_null(1), i8*, i8*)
declare i1 @runtime.typeAssert(i32, i8* dereferenceable_or_null(1), i8*)
; Function Attrs: nounwind
define hidden i1 @main.isError(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.isError(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
entry:
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0
br i1 %0, label %typeassert.ok, label %typeassert.next
@@ -87,7 +93,7 @@ typeassert.next: ; preds = %typeassert.ok, %ent
}
; Function Attrs: nounwind
define hidden i1 @main.isStringer(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.isStringer(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
entry:
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0
br i1 %0, label %typeassert.ok, label %typeassert.next
@@ -100,25 +106,27 @@ typeassert.next: ; preds = %typeassert.ok, %ent
}
; Function Attrs: nounwind
define hidden i8 @main.callFooMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i8 @main.callFooMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
entry:
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8* %itf.value, i32 3, i32 %itf.typecode, i8* undef, i8* undef) #0
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8* %itf.value, i32 3, i32 %itf.typecode, i8* undef) #0
ret i8 %0
}
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8*, i32, i32, i8*, i8*) #3
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8*, i32, i32, i8*) #3
; Function Attrs: nounwind
define hidden %runtime._string @main.callErrorMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden %runtime._string @main.callErrorMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
entry:
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8* %itf.value, i32 %itf.typecode, i8* undef, i8* undef) #0
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8* %itf.value, i32 %itf.typecode, i8* undef) #0
%1 = extractvalue %runtime._string %0, 0
call void @runtime.trackPointer(i8* %1, i8* undef) #0
ret %runtime._string %0
}
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8*, i32, i8*, i8*) #4
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8*, i32, i8*) #4
attributes #0 = { nounwind }
attributes #1 = { "tinygo-methods"="reflect/methods.Error() string" }
attributes #2 = { "tinygo-methods"="reflect/methods.String() string" }
attributes #3 = { "tinygo-invoke"="main.$methods.foo(int) byte" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) byte" }
attributes #3 = { "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
attributes #4 = { "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
+8 -8
View File
@@ -3,30 +3,30 @@ 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*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden double @main.mySqrt(double %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden double @main.mySqrt(double %x, i8* %context) unnamed_addr #0 {
entry:
%0 = call double @math.Sqrt(double %x, i8* undef, i8* undef) #0
%0 = call double @math.Sqrt(double %x, i8* undef) #0
ret double %0
}
declare double @math.Sqrt(double, i8*, i8*)
declare double @math.Sqrt(double, i8*)
; Function Attrs: nounwind
define hidden double @main.myTrunc(double %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden double @main.myTrunc(double %x, i8* %context) unnamed_addr #0 {
entry:
%0 = call double @math.Trunc(double %x, i8* undef, i8* undef) #0
%0 = call double @math.Trunc(double %x, i8* undef) #0
ret double %0
}
declare double @math.Trunc(double, i8*, i8*)
declare double @math.Trunc(double, i8*)
attributes #0 = { nounwind }
+10 -8
View File
@@ -1,35 +1,37 @@
; ModuleID = 'intrinsics.go'
source_filename = "intrinsics.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
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*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden double @main.mySqrt(double %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden double @main.mySqrt(double %x, i8* %context) unnamed_addr #0 {
entry:
%0 = call double @llvm.sqrt.f64(double %x)
ret double %0
}
; Function Attrs: nounwind readnone speculatable willreturn
; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare double @llvm.sqrt.f64(double) #1
; Function Attrs: nounwind
define hidden double @main.myTrunc(double %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden double @main.myTrunc(double %x, i8* %context) unnamed_addr #0 {
entry:
%0 = call double @llvm.trunc.f64(double %x)
ret double %0
}
; Function Attrs: nounwind readnone speculatable willreturn
; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare double @llvm.trunc.f64(double) #1
attributes #0 = { nounwind }
attributes #1 = { nounwind readnone speculatable willreturn }
attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
+29 -12
View File
@@ -1,61 +1,78 @@
; ModuleID = 'pointer.go'
source_filename = "pointer.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
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*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden [0 x i32] @main.pointerDerefZero([0 x i32]* %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden [0 x i32] @main.pointerDerefZero([0 x i32]* %x, i8* %context) unnamed_addr #0 {
entry:
ret [0 x i32] zeroinitializer
}
; Function Attrs: nounwind
define hidden i32* @main.pointerCastFromUnsafe(i8* %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32* @main.pointerCastFromUnsafe(i8* %x, i8* %context) unnamed_addr #0 {
entry:
%0 = bitcast i8* %x to i32*
call void @runtime.trackPointer(i8* %x, i8* undef) #0
ret i32* %0
}
; Function Attrs: nounwind
define hidden i8* @main.pointerCastToUnsafe(i32* dereferenceable_or_null(4) %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i8* @main.pointerCastToUnsafe(i32* dereferenceable_or_null(4) %x, i8* %context) unnamed_addr #0 {
entry:
%0 = bitcast i32* %x to i8*
call void @runtime.trackPointer(i8* %0, i8* undef) #0
ret i8* %0
}
; Function Attrs: nounwind
define hidden i8* @main.pointerCastToUnsafeNoop(i8* dereferenceable_or_null(1) %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i8* @main.pointerCastToUnsafeNoop(i8* dereferenceable_or_null(1) %x, i8* %context) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* %x, i8* undef) #0
ret i8* %x
}
; Function Attrs: nounwind
define hidden i8* @main.pointerUnsafeGEPFixedOffset(i8* dereferenceable_or_null(1) %ptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i8* @main.pointerUnsafeGEPFixedOffset(i8* dereferenceable_or_null(1) %ptr, i8* %context) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* %ptr, i8* undef) #0
%0 = getelementptr inbounds i8, i8* %ptr, i32 10
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
ret i8* %0
}
; Function Attrs: nounwind
define hidden i8* @main.pointerUnsafeGEPByteOffset(i8* dereferenceable_or_null(1) %ptr, i32 %offset, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i8* @main.pointerUnsafeGEPByteOffset(i8* dereferenceable_or_null(1) %ptr, i32 %offset, i8* %context) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* %ptr, i8* undef) #0
%0 = getelementptr inbounds i8, i8* %ptr, i32 %offset
call void @runtime.trackPointer(i8* %0, i8* undef) #0
call void @runtime.trackPointer(i8* %0, i8* undef) #0
ret i8* %0
}
; Function Attrs: nounwind
define hidden i32* @main.pointerUnsafeGEPIntOffset(i32* dereferenceable_or_null(4) %ptr, i32 %offset, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32* @main.pointerUnsafeGEPIntOffset(i32* dereferenceable_or_null(4) %ptr, i32 %offset, i8* %context) unnamed_addr #0 {
entry:
%0 = getelementptr i32, i32* %ptr, i32 %offset
ret i32* %0
%0 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %0, i8* undef) #0
%1 = getelementptr i32, i32* %ptr, i32 %offset
%2 = bitcast i32* %1 to i8*
call void @runtime.trackPointer(i8* %2, i8* undef) #0
%3 = bitcast i32* %1 to i8*
call void @runtime.trackPointer(i8* %3, i8* undef) #0
ret i32* %1
}
attributes #0 = { nounwind }
+11 -9
View File
@@ -1,6 +1,6 @@
; ModuleID = 'pragma.go'
source_filename = "pragma.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
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"
@extern_global = external global [0 x i8], align 1
@@ -10,10 +10,12 @@ target triple = "wasm32-unknown-wasi"
@undefinedGlobalNotInSection = external global i32, align 4
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
@@ -25,27 +27,27 @@ entry:
}
; Function Attrs: nounwind
define hidden void @somepkg.someFunction1(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @somepkg.someFunction1(i8* %context) unnamed_addr #0 {
entry:
ret void
}
declare void @somepkg.someFunction2(i8*, i8*)
declare void @somepkg.someFunction2(i8*)
; Function Attrs: inlinehint nounwind
define hidden void @main.inlineFunc(i8* %context, i8* %parentHandle) unnamed_addr #2 {
define hidden void @main.inlineFunc(i8* %context) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: noinline nounwind
define hidden void @main.noinlineFunc(i8* %context, i8* %parentHandle) unnamed_addr #3 {
define hidden void @main.noinlineFunc(i8* %context) unnamed_addr #3 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.functionInSection(i8* %context, i8* %parentHandle) unnamed_addr #0 section ".special_function_section" {
define hidden void @main.functionInSection(i8* %context) unnamed_addr #0 section ".special_function_section" {
entry:
ret void
}
@@ -56,7 +58,7 @@ entry:
ret void
}
declare void @main.undefinedFunctionNotInSection(i8*, i8*)
declare void @main.undefinedFunctionNotInSection(i8*)
attributes #0 = { nounwind }
attributes #1 = { nounwind "wasm-export-name"="extern_func" }
+39 -30
View File
@@ -1,36 +1,38 @@
; ModuleID = 'slice.go'
source_filename = "slice.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
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*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.sliceLen(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.sliceLen(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #0 {
entry:
ret i32 %ints.len
}
; Function Attrs: nounwind
define hidden i32 @main.sliceCap(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.sliceCap(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #0 {
entry:
ret i32 %ints.cap
}
; Function Attrs: nounwind
define hidden i32 @main.sliceElement(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.sliceElement(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, i8* %context) unnamed_addr #0 {
entry:
%.not = icmp ult i32 %index, %ints.len
br i1 %.not, label %lookup.next, label %lookup.throw
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(i8* undef, i8* null) #0
call void @runtime.lookupPanic(i8* undef) #0
unreachable
lookup.next: ; preds = %entry
@@ -39,12 +41,13 @@ lookup.next: ; preds = %entry
ret i32 %1
}
declare void @runtime.lookupPanic(i8*, i8*)
declare void @runtime.lookupPanic(i8*)
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.sliceAppendValues(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { i32*, i32, i32 } @main.sliceAppendValues(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #0 {
entry:
%varargs = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%varargs = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %varargs, i8* undef) #0
%0 = bitcast i8* %varargs to i32*
store i32 1, i32* %0, align 4
%1 = getelementptr inbounds i8, i8* %varargs, i32 4
@@ -54,7 +57,7 @@ entry:
%4 = bitcast i8* %3 to i32*
store i32 3, i32* %4, align 4
%append.srcPtr = bitcast i32* %ints.data to i8*
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, i8* undef, i8* null) #0
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, i8* undef) #0
%append.newPtr = extractvalue { i8*, i32, i32 } %append.new, 0
%append.newBuf = bitcast i8* %append.newPtr to i32*
%append.newLen = extractvalue { i8*, i32, i32 } %append.new, 1
@@ -62,17 +65,18 @@ entry:
%5 = insertvalue { i32*, i32, i32 } undef, i32* %append.newBuf, 0
%6 = insertvalue { i32*, i32, i32 } %5, i32 %append.newLen, 1
%7 = insertvalue { i32*, i32, i32 } %6, i32 %append.newCap, 2
call void @runtime.trackPointer(i8* %append.newPtr, i8* undef) #0
ret { i32*, i32, i32 } %7
}
declare { i8*, i32, i32 } @runtime.sliceAppend(i8*, i8* nocapture readonly, i32, i32, i32, i32, i8*, i8*)
declare { i8*, i32, i32 } @runtime.sliceAppend(i8*, i8* nocapture readonly, i32, i32, i32, i32, i8*)
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.sliceAppendSlice(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32* %added.data, i32 %added.len, i32 %added.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { i32*, i32, i32 } @main.sliceAppendSlice(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32* %added.data, i32 %added.len, i32 %added.cap, i8* %context) unnamed_addr #0 {
entry:
%append.srcPtr = bitcast i32* %ints.data to i8*
%append.srcPtr1 = bitcast i32* %added.data to i8*
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* %append.srcPtr1, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, i8* undef, i8* null) #0
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* %append.srcPtr1, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, i8* undef) #0
%append.newPtr = extractvalue { i8*, i32, i32 } %append.new, 0
%append.newBuf = bitcast i8* %append.newPtr to i32*
%append.newLen = extractvalue { i8*, i32, i32 } %append.new, 1
@@ -80,97 +84,102 @@ entry:
%0 = insertvalue { i32*, i32, i32 } undef, i32* %append.newBuf, 0
%1 = insertvalue { i32*, i32, i32 } %0, i32 %append.newLen, 1
%2 = insertvalue { i32*, i32, i32 } %1, i32 %append.newCap, 2
call void @runtime.trackPointer(i8* %append.newPtr, i8* undef) #0
ret { i32*, i32, i32 } %2
}
; Function Attrs: nounwind
define hidden i32 @main.sliceCopy(i32* %dst.data, i32 %dst.len, i32 %dst.cap, i32* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.sliceCopy(i32* %dst.data, i32 %dst.len, i32 %dst.cap, i32* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #0 {
entry:
%copy.dstPtr = bitcast i32* %dst.data to i8*
%copy.srcPtr = bitcast i32* %src.data to i8*
%copy.n = call i32 @runtime.sliceCopy(i8* %copy.dstPtr, i8* %copy.srcPtr, i32 %dst.len, i32 %src.len, i32 4, i8* undef, i8* null) #0
%copy.n = call i32 @runtime.sliceCopy(i8* %copy.dstPtr, i8* %copy.srcPtr, i32 %dst.len, i32 %src.len, i32 4, i8* undef) #0
ret i32 %copy.n
}
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*)
; Function Attrs: nounwind
define hidden { i8*, i32, i32 } @main.makeByteSlice(i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { i8*, i32, i32 } @main.makeByteSlice(i32 %len, i8* %context) unnamed_addr #0 {
entry:
%slice.maxcap = icmp slt i32 %len, 0
br i1 %slice.maxcap, label %slice.throw, label %slice.next
slice.throw: ; preds = %entry
call void @runtime.slicePanic(i8* undef, i8* null) #0
call void @runtime.slicePanic(i8* undef) #0
unreachable
slice.next: ; preds = %entry
%makeslice.buf = call i8* @runtime.alloc(i32 %len, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%makeslice.buf = call i8* @runtime.alloc(i32 %len, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
%0 = insertvalue { i8*, i32, i32 } undef, i8* %makeslice.buf, 0
%1 = insertvalue { i8*, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { i8*, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
ret { i8*, i32, i32 } %2
}
declare void @runtime.slicePanic(i8*, i8*)
declare void @runtime.slicePanic(i8*)
; Function Attrs: nounwind
define hidden { i16*, i32, i32 } @main.makeInt16Slice(i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { i16*, i32, i32 } @main.makeInt16Slice(i32 %len, i8* %context) unnamed_addr #0 {
entry:
%slice.maxcap = icmp slt i32 %len, 0
br i1 %slice.maxcap, label %slice.throw, label %slice.next
slice.throw: ; preds = %entry
call void @runtime.slicePanic(i8* undef, i8* null) #0
call void @runtime.slicePanic(i8* undef) #0
unreachable
slice.next: ; preds = %entry
%makeslice.cap = shl i32 %len, 1
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
%makeslice.array = bitcast i8* %makeslice.buf to i16*
%0 = insertvalue { i16*, i32, i32 } undef, i16* %makeslice.array, 0
%1 = insertvalue { i16*, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { i16*, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
ret { i16*, i32, i32 } %2
}
; Function Attrs: nounwind
define hidden { [3 x i8]*, i32, i32 } @main.makeArraySlice(i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { [3 x i8]*, i32, i32 } @main.makeArraySlice(i32 %len, i8* %context) unnamed_addr #0 {
entry:
%slice.maxcap = icmp ugt i32 %len, 1431655765
br i1 %slice.maxcap, label %slice.throw, label %slice.next
slice.throw: ; preds = %entry
call void @runtime.slicePanic(i8* undef, i8* null) #0
call void @runtime.slicePanic(i8* undef) #0
unreachable
slice.next: ; preds = %entry
%makeslice.cap = mul i32 %len, 3
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
%makeslice.array = bitcast i8* %makeslice.buf to [3 x i8]*
%0 = insertvalue { [3 x i8]*, i32, i32 } undef, [3 x i8]* %makeslice.array, 0
%1 = insertvalue { [3 x i8]*, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { [3 x i8]*, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
ret { [3 x i8]*, i32, i32 } %2
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.makeInt32Slice(i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden { i32*, i32, i32 } @main.makeInt32Slice(i32 %len, i8* %context) unnamed_addr #0 {
entry:
%slice.maxcap = icmp ugt i32 %len, 1073741823
br i1 %slice.maxcap, label %slice.throw, label %slice.next
slice.throw: ; preds = %entry
call void @runtime.slicePanic(i8* undef, i8* null) #0
call void @runtime.slicePanic(i8* undef) #0
unreachable
slice.next: ; preds = %entry
%makeslice.cap = shl i32 %len, 2
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
%makeslice.array = bitcast i8* %makeslice.buf to i32*
%0 = insertvalue { i32*, i32, i32 } undef, i32* %makeslice.array, 0
%1 = insertvalue { i32*, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { i32*, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
ret { i32*, i32, i32 } %2
}
+22 -21
View File
@@ -1,46 +1,48 @@
; ModuleID = 'string.go'
source_filename = "string.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
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"
%runtime._string = type { i8*, i32 }
@"main$string" = internal unnamed_addr constant [3 x i8] c"foo", align 1
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden %runtime._string @main.someString(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden %runtime._string @main.someString(i8* %context) unnamed_addr #0 {
entry:
ret %runtime._string { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"main$string", i32 0, i32 0), i32 3 }
}
; Function Attrs: nounwind
define hidden %runtime._string @main.zeroLengthString(i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden %runtime._string @main.zeroLengthString(i8* %context) unnamed_addr #0 {
entry:
ret %runtime._string zeroinitializer
}
; Function Attrs: nounwind
define hidden i32 @main.stringLen(i8* %s.data, i32 %s.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i32 @main.stringLen(i8* %s.data, i32 %s.len, i8* %context) unnamed_addr #0 {
entry:
ret i32 %s.len
}
; Function Attrs: nounwind
define hidden i8 @main.stringIndex(i8* %s.data, i32 %s.len, i32 %index, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i8 @main.stringIndex(i8* %s.data, i32 %s.len, i32 %index, i8* %context) unnamed_addr #0 {
entry:
%.not = icmp ult i32 %index, %s.len
br i1 %.not, label %lookup.next, label %lookup.throw
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(i8* undef, i8* null) #0
call void @runtime.lookupPanic(i8* undef) #0
unreachable
lookup.next: ; preds = %entry
@@ -49,44 +51,43 @@ lookup.next: ; preds = %entry
ret i8 %1
}
declare void @runtime.lookupPanic(i8*, i8*)
declare void @runtime.lookupPanic(i8*)
; Function Attrs: nounwind
define hidden i1 @main.stringCompareEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.stringCompareEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #0 {
entry:
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef, i8* null) #0
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef) #0
ret i1 %0
}
declare i1 @runtime.stringEqual(i8*, i32, i8*, i32, i8*, i8*)
declare i1 @runtime.stringEqual(i8*, i32, i8*, i32, i8*)
; Function Attrs: nounwind
define hidden i1 @main.stringCompareUnequal(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.stringCompareUnequal(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #0 {
entry:
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef, i8* null) #0
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef) #0
%1 = xor i1 %0, true
ret i1 %1
}
; Function Attrs: nounwind
define hidden i1 @main.stringCompareLarger(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i1 @main.stringCompareLarger(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #0 {
entry:
%0 = call i1 @runtime.stringLess(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef, i8* null) #0
%1 = xor i1 %0, true
ret i1 %1
%0 = call i1 @runtime.stringLess(i8* %s2.data, i32 %s2.len, i8* %s1.data, i32 %s1.len, i8* undef) #0
ret i1 %0
}
declare i1 @runtime.stringLess(i8*, i32, i8*, i32, i8*, i8*)
declare i1 @runtime.stringLess(i8*, i32, i8*, i32, i8*)
; Function Attrs: nounwind
define hidden i8 @main.stringLookup(i8* %s.data, i32 %s.len, i8 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
define hidden i8 @main.stringLookup(i8* %s.data, i32 %s.len, i8 %x, i8* %context) unnamed_addr #0 {
entry:
%0 = zext i8 %x to i32
%.not = icmp ult i32 %0, %s.len
br i1 %.not, label %lookup.next, label %lookup.throw
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(i8* undef, i8* null) #0
call void @runtime.lookupPanic(i8* undef) #0
unreachable
lookup.next: ; preds = %entry
+177
View File
@@ -0,0 +1,177 @@
package main
import (
"flag"
"os"
"os/exec"
"strings"
"sync"
"testing"
yaml "gopkg.in/yaml.v2"
)
/*
This contains code from https://github.com/dgryski/tinygo-test-corpus
The MIT License (MIT)
Copyright (c) 2020 Damian Gryski <damian@gryski.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
var corpus = flag.String("corpus", "", "path to test corpus")
func TestCorpus(t *testing.T) {
t.Parallel()
if *corpus == "" {
t.Skip()
}
var target string
if *testTarget != "" {
target = *testTarget
}
repos, err := loadRepos(*corpus)
if err != nil {
t.Fatalf("loading corpus: %v", err)
}
for _, repo := range repos {
repo := repo
name := repo.Repo
if repo.Tags != "" {
name += "(" + strings.ReplaceAll(repo.Tags, " ", "-") + ")"
}
if repo.Version != "" {
name += "@" + repo.Version
}
t.Run(name, func(t *testing.T) {
t.Parallel()
if target == "wasi" && repo.SkipWASI {
t.Skip("skip wasi")
}
if repo.Slow && testing.Short() {
t.Skip("slow test")
}
var wg sync.WaitGroup
defer wg.Wait()
out := ioLogger(t, &wg)
defer out.Close()
dir := t.TempDir()
cmd := exec.Command("go", "mod", "init", "github.com/tinygo/tinygo-corpus-test")
cmd.Dir = dir
cmd.Stdout, cmd.Stderr = out, out
err := cmd.Run()
if err != nil {
t.Errorf("failed to init: %s", err.Error())
return
}
var ver string
if repo.Version != "" {
ver = "@" + repo.Version
}
cmd = exec.Command("go", "get", "-t", "-d", repo.Repo+"/..."+ver)
cmd.Dir = dir
cmd.Stdout, cmd.Stderr = out, out
err = cmd.Run()
if err != nil {
t.Errorf("failed to get: %s", err.Error())
return
}
doTest := func(t *testing.T, path string) {
var wg sync.WaitGroup
defer wg.Wait()
out := ioLogger(t, &wg)
defer out.Close()
opts := optionsFromTarget(target, sema)
opts.Directory = dir
opts.Tags = repo.Tags
passed, err := Test(path, out, out, &opts, false, testing.Verbose(), false, "", "", "", "")
if err != nil {
t.Errorf("test error: %v", err)
}
if !passed {
t.Error("test failed")
}
}
if len(repo.Subdirs) == 0 {
doTest(t, repo.Repo)
return
}
for _, dir := range repo.Subdirs {
dir := dir
t.Run(dir.Pkg, func(t *testing.T) {
t.Parallel()
if target == "wasi" && dir.SkipWASI {
t.Skip("skip wasi")
}
if dir.Slow && testing.Short() {
t.Skip("slow test")
}
doTest(t, repo.Repo+"/"+dir.Pkg)
})
}
})
}
}
type T struct {
Repo string
Tags string
Subdirs []Subdir
SkipWASI bool
Slow bool
Version string
}
type Subdir struct {
Pkg string
SkipWASI bool
Slow bool
}
func loadRepos(f string) ([]T, error) {
yf, err := os.ReadFile(f)
if err != nil {
return nil, err
}
var repos []T
err = yaml.Unmarshal(yf, &repos)
if err != nil {
return nil, err
}
return repos, nil
}
+7 -5
View File
@@ -3,15 +3,17 @@ module github.com/tinygo-org/tinygo
go 1.15
require (
github.com/aykevl/go-wasm v0.0.2-0.20211030161413-11881cb9032d // indirect
github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
github.com/chromedp/cdproto v0.0.0-20210113043257-dabd2f2e7693
github.com/chromedp/chromedp v0.6.4
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
github.com/chromedp/chromedp v0.7.6
github.com/gofrs/flock v0.8.1
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
github.com/mattn/go-colorable v0.1.8
go.bug.st/serial v1.1.3
golang.org/x/sys v0.0.0-20210510120138-977fb7262007
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9
tinygo.org/x/go-llvm v0.0.0-20210325115028-e7b85195e81c
gopkg.in/yaml.v2 v2.4.0
tinygo.org/x/go-llvm v0.0.0-20220420140351-512c94c1e71f
)
+29 -19
View File
@@ -1,45 +1,51 @@
github.com/aykevl/go-wasm v0.0.2-0.20211030161413-11881cb9032d h1:JeuI5/546naK5hpOIX+Lq5xE8rvt7uwiTp6iL+pLQgk=
github.com/aykevl/go-wasm v0.0.2-0.20211030161413-11881cb9032d/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a h1:QPU7APo6y/6VkCDq6HU3WWIUzER8iywSac23+1UQv60=
github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/chromedp/cdproto v0.0.0-20210113043257-dabd2f2e7693 h1:11eq/RkpaotwdF6b1TRMcdgQUPNmyFEJOB7zLvh0O/Y=
github.com/chromedp/cdproto v0.0.0-20210113043257-dabd2f2e7693/go.mod h1:55pim6Ht4LJKdVLlyFJV/g++HsEA1hQxPbB5JyNdZC0=
github.com/chromedp/chromedp v0.6.4 h1:Gx7ZkRyrSVmbbDDja/ieNgNGJIvElroPOyeqYQGVDSY=
github.com/chromedp/chromedp v0.6.4/go.mod h1:vodUdJf5dF/b8n0UBJv6NeM/QK28RjP3j+eM7fq4+84=
github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee h1:+SFdIVfQpG0s0DHYzou0kgfE0n0ZjKPwbiRJsXrZegU=
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
github.com/chromedp/chromedp v0.7.6 h1:2juGaktzjwULlsn+DnvIZXFUckEp5xs+GOBroaea+jA=
github.com/chromedp/chromedp v0.7.6/go.mod h1:ayT4YU/MGAALNfOg9gNrpGSAdnU51PMx+FCeuT1iXzo=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
github.com/davecgh/go-spew v1.1.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/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs=
github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
github.com/yuin/goldmark v1.3.5/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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -52,10 +58,12 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
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-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/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-20220114195835-da31bd327af9/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=
@@ -65,10 +73,12 @@ golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9 h1:nvvuMxmx1q0gfRki3T0hj
golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
tinygo.org/x/go-llvm v0.0.0-20210308112806-9ef958b6bed4 h1:CMUHxVTb+UuUePuMf8vkWjZ3gTp9BBK91KrgOCwoNHs=
tinygo.org/x/go-llvm v0.0.0-20210308112806-9ef958b6bed4/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
tinygo.org/x/go-llvm v0.0.0-20210325115028-e7b85195e81c h1:vn9IPshzYmzZis10UEVrsIBRv9FpykADw6M3/tHHROg=
tinygo.org/x/go-llvm v0.0.0-20210325115028-e7b85195e81c/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
tinygo.org/x/go-llvm v0.0.0-20220420140351-512c94c1e71f h1:9/J+NpFTpAhYcbh1mC4dr9W/aAPnwrUh8dmq21xWdSM=
tinygo.org/x/go-llvm v0.0.0-20220420140351-512c94c1e71f/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
+9 -3
View File
@@ -12,7 +12,13 @@ import (
// Version of TinyGo.
// Update this value before release of new version of software.
const Version = "0.21.0-dev"
const Version = "0.23.0"
var (
// This variable is set at build time using -ldflags parameters.
// See: https://stackoverflow.com/a/11355611
GitSha1 string
)
// GetGorootVersion returns the major and minor version for a given GOROOT path.
// If the goroot cannot be determined, (0, 0) is returned.
@@ -52,9 +58,9 @@ func GorootVersionString(goroot string) (string, error) {
return string(data), nil
} else if data, err := ioutil.ReadFile(filepath.Join(
goroot, "src", "runtime", "internal", "sys", "zversion.go")); err == nil {
goroot, "src", "internal", "buildcfg", "zbootstrap.go")); err == nil {
r := regexp.MustCompile("const TheVersion = `(.*)`")
r := regexp.MustCompile("const version = `(.*)`")
matches := r.FindSubmatch(data)
if len(matches) != 2 {
return "", errors.New("Invalid go version output:\n" + string(data))
+3 -7
View File
@@ -11,12 +11,6 @@ import (
"tinygo.org/x/go-llvm"
)
// Version of the interp package. It must be incremented whenever the interp
// package is changed in a way that affects the output so that cached package
// builds will be invalidated.
// This version is independent of the TinyGo version number.
const Version = 2 // last change: fix GEP on untyped pointers
// Enable extra checks, which should be disabled by default.
// This may help track down bugs by adding a few more sanity checks.
const checks = true
@@ -28,6 +22,7 @@ type runner struct {
builder llvm.Builder
pointerSize uint32 // cached pointer size from the TargetData
i8ptrType llvm.Type // often used type so created in advance
uintptrType llvm.Type // equivalent to uintptr in Go
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
debug bool // log debug messages
pkgName string // package name of the currently executing package
@@ -50,6 +45,7 @@ func newRunner(mod llvm.Module, debug bool) *runner {
}
r.pointerSize = uint32(r.targetData.PointerSize())
r.i8ptrType = llvm.PointerType(mod.Context().Int8Type(), 0)
r.uintptrType = mod.Context().IntType(r.targetData.PointerSize() * 8)
r.maxAlign = r.targetData.PrefTypeAlignment(r.i8ptrType) // assume pointers are maximally aligned (this is not always the case)
return &r
}
@@ -122,7 +118,7 @@ func Run(mod llvm.Module, debug bool) error {
// Create a call to the package initializer (which was
// previously deleted).
i8undef := llvm.Undef(r.i8ptrType)
r.builder.CreateCall(fn, []llvm.Value{i8undef, i8undef}, "")
r.builder.CreateCall(fn, []llvm.Value{i8undef}, "")
// Make sure that any globals touched by the package
// initializer, won't be accessed by later package initializers.
r.markExternalLoad(fn)
+1
View File
@@ -71,6 +71,7 @@ func runTest(t *testing.T, pathPrefix string) {
defer pm.Dispose()
pm.AddGlobalOptimizerPass()
pm.AddDeadStoreEliminationPass()
pm.AddAggressiveDCEPass()
pm.Run(mod)
// Read the expected output IR.
+27 -10
View File
@@ -17,10 +17,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
locals := make([]value, len(fn.locals))
r.callsExecuted++
if time.Since(r.start) > time.Minute {
// Running for more than a minute. This should never happen.
return nil, mem, r.errorAt(fn.blocks[0].instructions[0], fmt.Errorf("interp: running for more than a minute, timing out (executed calls: %d)", r.callsExecuted))
}
t0 := time.Since(r.start)
// Parameters are considered a kind of local values.
for i, param := range params {
@@ -106,6 +103,13 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
}
switch inst.opcode {
case llvm.Ret:
const maxInterpSeconds = 180
if t0 > maxInterpSeconds*time.Second {
// Running for more than maxInterpSeconds seconds. This should never happen, but does.
// 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))
}
if len(operands) != 0 {
if r.debug {
fmt.Fprintln(os.Stderr, indent+"ret", operands[0])
@@ -197,7 +201,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// which case this call won't even get to this point but will
// already be emitted in initAll.
continue
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet" || callFn.name == "os.runtime_args":
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet" ||
callFn.name == "os.runtime_args" || callFn.name == "internal/task.start" || callFn.name == "internal/task.Current":
// These functions should be run at runtime. Specifically:
// * Print and panic functions are best emitted directly without
// interpreting them, otherwise we get a ton of putchar (etc.)
@@ -208,6 +213,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// * os.runtime_args reads globals that are initialized outside
// the view of the interp package so it always needs to be run
// at runtime.
// * internal/task.start, internal/task.Current: start and read shcheduler state,
// which is modified elsewhere.
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
if err != nil {
return nil, mem, err
@@ -376,6 +383,10 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
if !actualTypePtrToInt.IsAConstantInt().IsNil() && actualTypePtrToInt.ZExtValue() == 0 {
locals[inst.localIndex] = literalValue{uint8(0)}
break
}
actualType := actualTypePtrToInt.Operand(0)
if strings.TrimPrefix(actualType.Name(), "reflect/types.type:") == strings.TrimPrefix(assertedType.Name(), "reflect/types.typeid:") {
locals[inst.localIndex] = literalValue{uint8(1)}
@@ -433,7 +444,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
}
// Load the type code of the interface value.
typecodeIDBitCast, err := operands[len(operands)-3].toLLVMValue(inst.llvmInst.Operand(len(operands)-4).Type(), &mem)
typecodeIDBitCast, err := operands[len(operands)-2].toLLVMValue(inst.llvmInst.Operand(len(operands)-3).Type(), &mem)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
@@ -482,8 +493,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// possibly trying to recover from it if it failed to execute.
if r.debug {
argStrings := make([]string, len(operands)-1)
for i := range argStrings {
argStrings[i] = operands[i+1].String()
for i, v := range operands[1:] {
argStrings[i] = v.String()
}
fmt.Fprintln(os.Stderr, indent+"call:", callFn.name+"("+strings.Join(argStrings, ", ")+")")
}
@@ -521,7 +532,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
return nil, mem, r.errorAt(inst, err)
}
size := operands[1].(literalValue).value.(uint64)
if mem.hasExternalStore(ptr) {
if inst.llvmInst.IsVolatile() || inst.llvmInst.Ordering() != llvm.AtomicOrderingNotAtomic || mem.hasExternalStore(ptr) {
// If there could be an external store (for example, because a
// pointer to the object was passed to a function that could not
// be interpreted at compile time) then the load must be done at
@@ -551,7 +562,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
if mem.hasExternalLoadOrStore(ptr) {
if inst.llvmInst.IsVolatile() || inst.llvmInst.Ordering() != llvm.AtomicOrderingNotAtomic || mem.hasExternalLoadOrStore(ptr) {
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
if err != nil {
return nil, mem, err
@@ -925,12 +936,18 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me
if inst.llvmInst.IsVolatile() {
result.SetVolatile(true)
}
if ordering := inst.llvmInst.Ordering(); ordering != llvm.AtomicOrderingNotAtomic {
result.SetOrdering(ordering)
}
case llvm.Store:
mem.markExternalStore(operands[1])
result = r.builder.CreateStore(operands[0], operands[1])
if inst.llvmInst.IsVolatile() {
result.SetVolatile(true)
}
if ordering := inst.llvmInst.Ordering(); ordering != llvm.AtomicOrderingNotAtomic {
result.SetOrdering(ordering)
}
case llvm.BitCast:
result = r.builder.CreateBitCast(operands[0], inst.llvmInst.Type(), inst.name)
case llvm.ExtractValue:
+8 -1
View File
@@ -903,7 +903,14 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value,
return llvm.Value{}, err
}
if llvmValue.Type() != llvmType {
llvmValue = llvm.ConstBitCast(llvmValue, llvmType)
if llvmValue.Type().PointerAddressSpace() != llvmType.PointerAddressSpace() {
// Special case for AVR function pointers.
// Because go-llvm doesn't have addrspacecast at the moment,
// do it indirectly with a ptrtoint/inttoptr pair.
llvmValue = llvm.ConstIntToPtr(llvm.ConstPtrToInt(llvmValue, mem.r.uintptrType), llvmType)
} else {
llvmValue = llvm.ConstBitCast(llvmValue, llvmType)
}
}
return llvmValue, nil
}

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