Compare commits

..

1 Commits

Author SHA1 Message Date
Ayke van Laethem 907d90105a runtime: use the main (startup) stack for the main goroutine
Instead of always starting a new goroutine for the main goroutine, run
the main goroutine on the system stack.
The system stack is not occupied with scheduling, instead each goroutine
that wants to pause itself calls into the scheduler which will switch to
the next task (goroutine) to run, or sleeps.

There are various advantages of this over the previous system:

  * When the program doesn't start a goroutine, the code size and RAM
    consumption is close to what you'd get with `-scheduler=none`.
  * When the program does start a goroutine, there is still a reduction
    in RAM consumption because only one extra stack is needed.
  * Because tasks directly switch to the next task to run, only a single
    task switch is needed instead of two (goroutine -> scheduler ->
    goroutine). This should improve task switching performance.

I kept the current behavior for WebAssembly/Asyncify. I looked into how
the same benefits can be realized for WebAssembly but couldn't easily
find how to do that. Maybe this can be done separately, or maybe we'll
just wait for the stack switching proposal to finish.

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

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