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.
This environment variable can be set to 5, 6, or 7 and controls which
ARM version (ARMv5, ARMv6, ARMv7) is used when compiling for GOARCH=arm.
I have picked the default value ARMv6, which I believe is supported on
most common single board computers including all Raspberry Pis. The
difference in code size is pretty big.
We could even go further and support ARMv4 if anybody is interested. It
should be pretty simple to add this if needed.
This change implements a new "scheduler" for WebAssembly using binaryen's asyncify transform.
This is more reliable than the current "coroutines" transform, and works with non-Go code in the call stack.
runtime (js/wasm): handle scheduler nesting
If WASM calls into JS which calls back into WASM, it is possible for the scheduler to nest.
The event from the callback must be handled immediately, so the task cannot simply be deferred to the outer scheduler.
This creates a minimal scheduler loop which is used to handle such nesting.
This makes sure that the LLVM target features match the one generated by
Clang:
- This fixes a bug introduced when setting the target CPU for all
targets: Cortex-M4 would now start using floating point operations
while they were disabled in C.
- This will make it possible in the future to inline C functions in Go
and vice versa. This will need some more work though.
There is a code size impact. Cortex-M4 targets are increased slightly in
binary size while Cortex-M0 targets tend to be reduced a little bit.
Other than that, there is little impact.
With this fix, `cflags` in the target JSON files is correctly ordered.
Previously, the cflags of a parent JSON file would come after the ones
in the child JSON file, which makes it hard to override properties in
the child JSON file.
Specifically, this fixes the case where targets/riscv32.json sets
`-march=rv32imac` and targets/esp32c3.json wants to override this using
`-march=rv32imc` but can't do this because its `-march` comes before the
riscv32.json one.
The target triples have to match mostly to be able to link LLVM modules.
Linking LLVM modules is already possible (the triples already match),
but testing becomes much easier when they match exactly.
For macOS, I picked "macosx10.12.0". That's an old and unsupported
version, but I had to pick _something_. Clang by default uses
"macos10.4.0", which is much older.
This commit adds support for musl-libc and uses it by default on Linux.
The main benefit of it is that binaries are always statically linked
instead of depending on the host libc, even when using CGo.
Advantages:
- The resulting binaries are always statically linked.
- No need for any tools on the host OS, like a compiler, linker, or
libc in a release build of TinyGo.
- This also simplifies cross compilation as no cross compiler is
needed (it's all built into the TinyGo release build).
Disadvantages:
- Binary size increases by 5-6 kilobytes if -no-debug is used. Binary
size increases by a much larger margin when debugging symbols are
included (the default behavior) because musl is built with debugging
symbols enabled.
- Musl does things a bit differently than glibc, and some CGo code
might rely on the glibc behavior.
- The first build takes a bit longer because musl needs to be built.
As an additional bonus, time is now obtained from the system in a way
that fixes the Y2038 problem because musl has been a bit more agressive
in switching to 64-bit time_t.
This is really just a preparatory commit for musl support. The idea is
to store not just the archive file (.a) but also an include directory.
This is optional for picolibc but required for musl, so the main purpose
of this commit is the refactor needed for this change.
This brings a bit more consistency to libc configuration. It seems
better to me to set the header flags all in the same place, instead of
some in Go code and some in JSON target files (depending on the target).
This is for consistency with Clang, which always adds a CPU flag even if
it's not specified in CFLAGS.
This commit also adds some tests to make sure the Clang target-cpu
matches the CPU property in the JSON files.
This does have an effect on the generated binaries. The effect is very
small though: on average just 0.2% increase in binary size, apparently
because Cortex-M3 and Cortex-M4 are compiled a bit differently. However,
when rebased on top of https://github.com/tinygo-org/tinygo/pull/2218
(minsize), the difference drops to -0.1% (a slight decrease on average).
This adds support for stdio in picolibc and fixes wasm_exec.js so that
it can also support C puts. With this, C stdout works on all supported
platforms.
It is better to use environment variables (GOOS and GOARCH) for
consistency instead of providing two slightly incompatible ways. This
-target flag should only be used to specify a .json file (either
directly or in the TinyGo targets directory). Previously it was possible
to specify the LLVM target as well but that was never really fully
supported.
So:
- To specify a different OS/arch like you would in regular Go, use
GOOS and GOARCH.
- To specify a microcontroller chip or board, use the -target flag.
Also remove the old `os.Setenv` which might have had a purpose long ago
but doesn't have a purpose now.
... instead of setting a special -target= value. This is more robust and
makes sure that the test actually tests different arcitectures as they
would be compiled by TinyGo. As an example, the bug of the bugfix in the
previous commit ("arm: use armv7 instead of thumbv7") would have been
caught if this change was applied earlier.
I've decided to put GOOS/GOARCH in compileopts.Options, as it makes
sense to me to treat them the same way as command line parameters.
At the moment, thumbv7 is crashing. I'm not exactly sure why, but it
appears that there is an unknown instruction in __aeabi_uldivmod
(probably from libgcc).
I've fixed this by switching to armv7, which is also somewhat modern.
Maybe we can switch back to Thumb2 (aka thumbv7) once we start using
musl and compiler-rt. In the meantime, this does fix a miscompilation
(illegal instruction).
This commit changes a target triple like "armv6m-none-eabi" to
"armv6m-unknown-unknow-eabi". The reason is that while the former is
correctly parsed in Clang (due to normalization), it wasn't parsed
correctly in LLVM meaning that the environment wasn't set to EABI.
This change normalizes all target triples and uses the EABI environment
(-eabi in the triple) for Cortex-M targets.
This change also drops the `--target=` flag in the target JSON files,
the flag is now added implicitly in `(*compileopts.Config).CFlags()`.
This removes some duplication in target JSON files.
Unfortunately, this change also increases code size for Cortex-M
targets. It looks like LLVM now emits calls like __aeabi_memmove instead
of memmove, which pull in slightly more code (they basically just call
the regular C functions) and the calls themself don't seem to be as
efficient as they could be. Perhaps this is a LLVM bug that will be
fixed in the future, as this is a very common occurrence.
This brings some consistency to the CFlags and fixes the issue that on
some platforms (Linux, MacOS), no optimization level was set and
therefore C files in packages were not optimized at all.
This reduces binary size substantially, for two reasons:
- It switches to a much more architecture ARMv4 vs ARMv7.
- It switches to Thumb2, which is a lot denser than regular ARM.
Practically all modern and not-so-modern ARM chips support Thumb2, so
this seems like a safe change to me.
The size in numbers:
- Code size for testdata/stdlib.go is reduced by about 35%.
- Binary size for testdata/stdlib.go (when compiling with -no-debug to
strip debug information) is reduced by about 16%.
Previously we used the i386 target, probably with all optional features
disabled. However, the Pentium 4 has been released a _long_ time ago and
it seems reasonable to me to take that as a minimum requirement.
Upstream Go now also seems to move in this direction:
https://github.com/golang/go/issues/40255
The main motivation for this is that there were floating point issues
when running the tests for the math package:
GOARCH=386 tinygo test math
I haven't investigated what's the issue, but I strongly suspect it's
caused by the weird x87 80-bit floating point format. This could perhaps
be fixed in a different way (by setting the FPU precision to 64 bits)
but I figured that just setting the minimum requirement to the Pentium 4
would probably be fine. If needed, we can respect the GO386 environment
variable to support these very old CPUs.
To support this newer CPU, I had to make sure that the stack is aligned
to 16 bytes everywhere. This was not yet always the case.
Stripping debug information at link time also allows relocation
compression (aka linker relaxations). Keeping debug information at
compile time and optionally stripping it at link time has some
advantages:
* Automatic stack sizes on Cortex-M rely on the presence of debug
information.
* Some parts of the compiler now rely on the presence of debug
information for proper diagnostics.
* It works better with the cache: there is no distinction between
debug and no-debug builds.
* It makes it easier (or possible at all) to enable debug information
in the wasi-libc library without big downsides.
This can be very useful for some purposes:
* It makes it possible to disable the UART in cases where it is not
needed or needs to be disabled to conserve power.
* It makes it possible to disable the serial output to reduce code
size, which may be important for some chips. Sometimes, a few kB can
be saved this way.
* It makes it possible to override the default, for example you might
want to use an actual UART to debug the USB-CDC implementation.
It also lowers the dependency on having machine.Serial defined, which is
often not defined when targeting a chip. Eventually, we might want to
make it possible to write `-target=nrf52` or `-target=atmega328p` for
example to target the chip itself with no board specific assumptions.
The defaults don't change. I checked this by running `make smoketest`
before and after and comparing the results.
The wasm build tag together with GOARCH=arm was causing problems in the
internal/cpu package. In general, I think having two architecture build
tag will only cause problems (in this case, wasm and arm) so I've
removed the wasm build tag and replaced it with tinygo.wasm.
This is similar to the tinygo.riscv build tag, which is used for older
Go versions that don't yet have RISC-V support in the standard library
(and therefore pretend to be GOARCH=arm instead).
This makes it possible to flash a board even when there are multiple
different kinds of boards attached, e.g. an Arduino Uno and a Circuit
Playground Express. You can find the VID/PID pair in several ways:
1. By running `lsusb` before and after attaching the board and looking
at the new USB device.
2. By grepping for `usb_PID` and `usb_VID` in the TinyGo source code.
3. By checking the Arduino IDE boards.txt from the vendor.
Note that one board may have multiple VID/PID pairs:
* The bootloader and main program may have a different PID, so far
I've seen that the main program generally has the bootloader PID
with 0x8000 added.
* The software running on the board may have an erroneous PID, for
example from a different board. I've seen this happen a few times.
* A single board may have had some revisions which changed the PID.
This is particularly true for the Arduino Uno.
As a fallback, if the given VID/PID pair isn't found, the whole set of
serial ports will be used.
There are many boards which I haven't included yet simply because I
couldn't test them.
This results in smaller and likely more efficient code. It does require
some architecture specific code for each architecture, but I've kept the
amount of code as small as possible.
With this is possible to enable e.g., SIMD in WASM using -llvm-features
+simd128. Multiple features can be specified separated by comma,
e.g., -llvm-features +simd128,+tail-call
With help from @deadprogram and @aykevl.
This commit does two things:
1. It makes it possible to grow the heap on Linux and MacOS by
allocating 1GB of virtual memory on startup and then slowly using it
as necessary, when running out of available heap space.
2. It switches the default GC to be the conservative GC (previously
extalloc). This is good for consistency with other platforms that
all use this same GC.
This makes the extalloc GC unused by default.
The CircleCI macOS builds are failing, probably due to the old macOS
version that's used. This version (10.13 High Sierra) isn't supported
anymore on Homebrew so it seems best to me to simply bump the version.
I picked Xcode 11.1.0 because 10.3.0 is somehow triggering an error
while trying to install QEMU (the Python install fails).
Because of this newer Xcode version, I had to add an extra flag
(-isysroot) to the default command line for MacOS. The reason is that
this newer Xcode version no longer stores header files in /usr/local, an
SDK must be specified manually. With this change, the default SDK is
used.
This flag, if set, is a regexp for function names. If there are heap
allocations in the matching function names, these heap allocations will
be printed with an explanation why the heap allocation exists (and why
the object can't be stack allocated).
At the moment, all targets use the Clang compiler to compile C and
assembly files. There is no good reason to make this configurable
anymore and in fact it will make future changes more complicated (and
thus more likely to have bugs). Therefore, I've removed support for
setting the compiler.
Note that the same is not true for the linker. While it makes sense to
standardize on the Clang compiler (because if Clang doesn't support a
target, TinyGo is unlikely to support it either), linkers will remain
configurable for the foreseeable future. One example is Xtensa, which is
supported by the Xtensa LLVM fork but doesn't have support in ld.lld
yet.
I've also fixed a bug in compileAndCacheCFile: it wasn't using the right
CFlags for caching purposes. This could lead to using stale caches. This
commit fixes that too.
This commit implements replacing some global variables with a different
value, if the global variable has no initializer. For example, if you
have:
package main
var version string
you can replace the value with -ldflags="-X main.version=0.2".
Right now it only works for uninitialized globals. The Go tooling also
supports initialized globals (var version = "<undefined>") but that is a
bit hard to combine with how initialized globals are currently
implemented.
The current implementation still allows caching package IR files while
making sure the values don't end up in the build cache. This means
compiling a program multiple times with different values will use the
cached package each time, inserting the string value only late in the
build process.
Fixes#1045
This simplifies future changes. While the move itself is very simple, it
required some other changes to a few transforms that create new
functions to add the optsize attribute manually. It also required
abstracting away the optimization level flags (based on the -opt flag)
so that it can easily be retrieved from the config object.
This commit does not impact binary size on baremetal and WebAssembly.
I've seen a few tests on linux/amd64 grow slightly in size, but I'm not
too worried about those.
Moving settings to a separate config struct has two benefits:
- It decouples the compiler a bit from other packages, most
importantly the compileopts package. Decoupling is generally a good
thing.
- Perhaps more importantly, it precisely specifies which settings are
used while compiling and affect the resulting LLVM module. This will
be necessary for caching the LLVM module.
While it would have been possible to cache without this refactor, it
would have been very easy to miss a setting and thus let the
compiler work with invalid/stale data.
On WebAssembly it is possible to grow the heap with the memory.grow
instruction. This commit implements this feature and with that also
removes the -heap-size flag that was reportedly broken (I haven't
verified that). This should make it easier to use TinyGo for
WebAssembly, where there was no good reason to use a fixed heap size.
This commit has no effect on baremetal targets with optimizations
enabled.