Compare commits

..

2 Commits

Author SHA1 Message Date
sago35 46e84a09f8 go mod tidy 2021-12-07 08:44:22 +09:00
sago35 954acdbdf5 smoketest: run with go script 2021-12-07 08:43:28 +09:00
589 changed files with 6735 additions and 14648 deletions
+110 -4
View File
@@ -22,12 +22,12 @@ commands:
steps:
- restore_cache:
keys:
- llvm-source-13-v1
- llvm-source-12-v1
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-13-v1
key: llvm-source-12-v1
paths:
- llvm-project/clang/lib/Headers
- llvm-project/clang/include
@@ -85,10 +85,10 @@ commands:
- run: go install -tags=llvm<<parameters.llvm>> .
- restore_cache:
keys:
- wasi-libc-sysroot-systemclang-v4
- wasi-libc-sysroot-systemclang-v3
- run: make wasi-libc
- save_cache:
key: wasi-libc-sysroot-systemclang-v4
key: wasi-libc-sysroot-systemclang-v3
paths:
- lib/wasi-libc/sysroot
- run: make gen-device -j4
@@ -99,6 +99,104 @@ commands:
- ~/.cache/go-build
- /go/pkg/mod
- run: make fmt-check
build-macos:
steps:
- checkout
- submodules
- run:
name: "Install dependencies"
command: |
curl https://dl.google.com/go/go1.17.darwin-amd64.tar.gz -o go1.17.darwin-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.17.darwin-amd64.tar.gz
ln -s /usr/local/go/bin/go /usr/local/bin/go
HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake ninja
- install-xtensa-toolchain:
variant: "macos"
- restore_cache:
keys:
- go-cache-macos-v3-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-macos-v3-{{ checksum "go.mod" }}
- restore_cache:
keys:
- llvm-source-12-macos-v1
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-12-macos-v1
paths:
- llvm-project/clang/lib/Headers
- llvm-project/clang/include
- llvm-project/lld/include
- llvm-project/llvm/include
- restore_cache:
keys:
- llvm-build-12-macos-v1
- run:
name: "Build LLVM"
command: |
if [ ! -f llvm-build/lib/liblldELF.a ]
then
# fetch LLVM source (may only have headers right now)
rm -rf llvm-project
make llvm-source
# build!
make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
fi
- save_cache:
key: llvm-build-12-macos-v1
paths:
llvm-build
- restore_cache:
keys:
- binaryen-macos-v1
- run:
name: "Build Binaryen"
command: |
if [ ! -f build/wasm-opt ]
then
make binaryen
fi
- save_cache:
key: binaryen-macos-v1
paths:
- build/wasm-opt
- restore_cache:
keys:
- wasi-libc-sysroot-macos-v4
- run:
name: "Build wasi-libc"
command: make wasi-libc
- save_cache:
key: wasi-libc-sysroot-macos-v4
paths:
- lib/wasi-libc/sysroot
- run:
name: "Test TinyGo"
command: make test GOTESTFLAGS="-v -short"
no_output_timeout: 20m
- run:
name: "Build TinyGo release"
command: |
make release -j3
cp -p build/release.tar.gz /tmp/tinygo.darwin-amd64.tar.gz
- store_artifacts:
path: /tmp/tinygo.darwin-amd64.tar.gz
- run:
name: "Extract release tarball"
command: |
mkdir -p ~/lib
tar -C /usr/local/opt -xf /tmp/tinygo.darwin-amd64.tar.gz
ln -s /usr/local/opt/tinygo/bin/tinygo /usr/local/bin/tinygo
tinygo version
- run: make tinygo-test
- run: make smoketest AVR=0
- save_cache:
key: go-cache-macos-v3-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths:
- ~/.cache/go-build
- /go/pkg/mod
jobs:
test-llvm11-go115:
@@ -113,9 +211,17 @@ jobs:
steps:
- test-linux:
llvm: "12"
build-macos:
macos:
xcode: "11.1.0" # macOS 10.14
steps:
- build-macos
workflows:
test-all:
jobs:
- test-llvm11-go115
- test-llvm12-go116
- build-macos
-97
View File
@@ -1,97 +0,0 @@
name: macOS
on:
pull_request:
push:
branches:
- dev
- release
jobs:
build-macos:
name: build-macos
runs-on: macos-10.15
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: '1.17'
- name: Install Dependencies
shell: bash
run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
- name: Install Xtensa toolchain
shell: bash
run: |
curl -L https://github.com/espressif/crosstool-NG/releases/download/esp-2020r2/xtensa-esp32-elf-gcc8_2_0-esp-2020r2-macos.tar.gz -o xtensa-esp32-elf-gcc8_2_0-esp-2020r2-macos.tar.gz
sudo tar -C /usr/local -xf xtensa-esp32-elf-gcc8_2_0-esp-2020r2-macos.tar.gz
sudo ln -s /usr/local/xtensa-esp32-elf/bin/xtensa-esp32-elf-ld /usr/local/bin/xtensa-esp32-elf-ld
rm xtensa-esp32-elf-gcc8_2_0-esp-2020r2-macos.tar.gz
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Cache LLVM source
uses: actions/cache@v2
id: cache-llvm-source
with:
key: llvm-source-13-macos-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
llvm-project/lld/include
llvm-project/llvm/include
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Cache LLVM build
uses: actions/cache@v2
id: cache-llvm-build
with:
key: llvm-build-13-macos-v3
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
shell: bash
run: |
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# install dependencies
HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake ninja
# build!
make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
- name: Cache wasi-libc sysroot
uses: actions/cache@v2
id: cache-wasi-libc
with:
key: wasi-libc-sysroot-v2
path: lib/wasi-libc/sysroot
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
- name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-v -short"
- name: Build TinyGo release tarball
run: make release -j3
- name: Test stdlib packages
run: make tinygo-test
- name: Make release artifact
shell: bash
run: cp -p build/release.tar.gz build/tinygo.darwin-amd64.tar.gz
- name: Publish release artifact
# Note: this release artifact is double-zipped, see:
# https://github.com/actions/upload-artifact/issues/39
# We can essentially pick one of these:
# - have a double-zipped artifact when downloaded from the UI
# - have a very slow artifact upload
# We're doing the former here, to keep artifact uploads fast.
uses: actions/upload-artifact@v2
with:
name: release-double-zipped
path: build/tinygo.darwin-amd64.tar.gz
- name: Smoke tests
shell: bash
run: make smoketest TINYGO=$(PWD)/build/tinygo AVR=0
@@ -0,0 +1,45 @@
name: CI for tinygo-dev docker container
on:
push:
branches: [ dev, fix-docker-llvm-build ]
jobs:
push_to_registry:
name: Push Docker image to GHCR/Docker Hub
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Check out the repo
uses: actions/checkout@v2
with:
submodules: recursive
- name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: |
tinygo/tinygo-dev
ghcr.io/${{ github.repository }}/tinygo-dev
tags: |
type=sha,format=long
type=raw,value=latest
- name: Log in to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
-83
View File
@@ -1,83 +0,0 @@
# This is the Github action to build and push the tinygo/tinygo-dev Docker image.
# If you are looking for the tinygo/tinygo "release" Docker image please see
# https://github.com/tinygo-org/docker
#
name: Docker
on:
push:
branches: [ dev, fix-docker-llvm-build ]
jobs:
push_to_registry:
name: build-push-dev
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Check out the repo
uses: actions/checkout@v2
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: |
tinygo/tinygo-dev
ghcr.io/${{ github.repository }}/tinygo-dev
tags: |
type=sha,format=long
type=raw,value=latest
- name: Log in to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Trigger Drivers repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/drivers/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
- name: Trigger Bluetooth repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/bluetooth/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
- name: Trigger TinyFS repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinyfs/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
- name: Trigger TinyFont repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinyfont/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
- name: Trigger TinyDraw repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinydraw/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
+7 -17
View File
@@ -38,7 +38,7 @@ jobs:
uses: actions/cache@v2
id: cache-llvm-source
with:
key: llvm-source-13-linux-v1
key: llvm-source-12-linux-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -51,7 +51,7 @@ jobs:
uses: actions/cache@v2
id: cache-llvm-build
with:
key: llvm-build-13-linux-v2
key: llvm-build-12-linux-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -76,7 +76,7 @@ jobs:
uses: actions/cache@v2
id: cache-wasi-libc
with:
key: wasi-libc-sysroot-linux-asserts-v3
key: wasi-libc-sysroot-linux-asserts-v2
path: lib/wasi-libc/sysroot
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
@@ -108,10 +108,6 @@ jobs:
uses: actions/setup-go@v2
with:
go-version: '1.17'
- name: Install wasmtime
run: |
curl https://wasmtime.dev/install.sh -sSf | bash
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
- name: Download release artifact
uses: actions/download-artifact@v2
with:
@@ -132,7 +128,6 @@ jobs:
sudo tar -C /usr/local -xf xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
sudo ln -s /usr/local/xtensa-esp32-elf/bin/xtensa-esp32-elf-ld /usr/local/bin/xtensa-esp32-elf-ld
rm xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
- run: make tinygo-test-wasi-fast
- run: make smoketest
assert-test-linux:
# Run all tests that can run on Linux, with LLVM assertions enabled to catch
@@ -145,16 +140,12 @@ jobs:
submodules: true
- name: Install apt dependencies
run: |
echo "Show cpuinfo; sometimes useful when troubleshooting"
cat /proc/cpuinfo
sudo apt-get update
sudo apt-get install --no-install-recommends \
qemu-system-arm \
qemu-system-riscv32 \
qemu-user \
gcc-avr \
avr-libc \
simavr \
ninja-build
- name: Install Go
uses: actions/setup-go@v2
@@ -179,7 +170,7 @@ jobs:
uses: actions/cache@v2
id: cache-llvm-source
with:
key: llvm-source-13-linux-asserts-v1
key: llvm-source-12-linux-asserts-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -192,7 +183,7 @@ jobs:
uses: actions/cache@v2
id: cache-llvm-build
with:
key: llvm-build-13-linux-asserts-v2
key: llvm-build-12-linux-asserts-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -217,12 +208,11 @@ jobs:
uses: actions/cache@v2
id: cache-wasi-libc
with:
key: wasi-libc-sysroot-linux-asserts-v3
key: wasi-libc-sysroot-linux-asserts-v2
path: lib/wasi-libc/sysroot
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
- run: make gen-device -j4
- name: Test TinyGo
run: make ASSERT=1 test
- name: Build TinyGo
@@ -237,6 +227,6 @@ jobs:
sudo tar -C /usr/local -xf xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
sudo ln -s /usr/local/xtensa-esp32-elf/bin/xtensa-esp32-elf-ld /usr/local/bin/xtensa-esp32-elf-ld
rm xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
- run: make gen-device -j4
- run: make smoketest
- run: make wasmtest
- run: make tinygo-baremetal
+15 -7
View File
@@ -15,11 +15,10 @@ jobs:
uses: actions/setup-go@v2
with:
go-version: '1.17'
- uses: brechtm/setup-scoop@v2
- name: Install Dependencies
- name: Install Ninja
shell: bash
run: |
scoop install ninja binaryen
choco install ninja
- name: Checkout
uses: actions/checkout@v2
with:
@@ -35,7 +34,7 @@ jobs:
uses: actions/cache@v2
id: cache-llvm-source
with:
key: llvm-source-13-windows-v1
key: llvm-source-12-windows-v1
path: |
llvm-project/clang/lib/Headers
llvm-project/clang/include
@@ -48,7 +47,7 @@ jobs:
uses: actions/cache@v2
id: cache-llvm-build
with:
key: llvm-build-13-windows-v2
key: llvm-build-12-windows-v1
path: llvm-build
- name: Build LLVM
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
@@ -65,11 +64,20 @@ jobs:
uses: actions/cache@v2
id: cache-wasi-libc
with:
key: wasi-libc-sysroot-v2
key: wasi-libc-sysroot-v1
path: lib/wasi-libc/sysroot
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
- name: Cache Binaryen
uses: actions/cache@v2
id: cache-binaryen
with:
key: binaryen-windows-v2
path: build/wasm-opt.exe
- name: Build Binaryen
if: steps.cache-binaryen.outputs.cache-hit != 'true'
run: make binaryen
- name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-v -short"
@@ -92,6 +100,6 @@ jobs:
path: build/release/release.zip
- name: Smoke tests
shell: bash
run: make smoketest TINYGO=$(PWD)/build/tinygo AVR=0 XTENSA=0
run: make smoketest TINYGO=build/tinygo AVR=0 XTENSA=0
- name: Test stdlib packages
run: make tinygo-test
-3
View File
@@ -32,6 +32,3 @@
[submodule "lib/mingw-w64"]
path = lib/mingw-w64
url = https://github.com/mingw-w64/mingw-w64.git
[submodule "lib/macos-minimal-sdk"]
path = lib/macos-minimal-sdk
url = https://github.com/aykevl/macos-minimal-sdk.git
+6 -1
View File
@@ -11,7 +11,12 @@ lld so that the binary can be easily moved between systems. It also shows how to
build a release tarball that includes this binary and all necessary extra files.
**Note**: this documentation describes how to build a statically linked release
tarball. If you want to help with development of TinyGo itself, you should follow the guide located at https://tinygo.org/docs/guides/build/
tarball. If you want to develop TinyGo, you will probably want to follow a
different guide:
* [Linux](https://tinygo.org/getting-started/linux/#source-install)
* [macOS](https://tinygo.org/getting-started/macos/#source-install)
* [Windows](https://tinygo.org/getting-started/windows/#source-install)
## Dependencies
-105
View File
@@ -1,108 +1,3 @@
0.22.0
---
* **command line**
- add asyncify to scheduler flag help
- support -run for tests
- remove FreeBSD target support
- add LLVM 12 and LLVM 13 support, use LLVM 13 by default
- add support for ARM64 MacOS
- improve help
- check /run/media as well as /media on Linux for non-debian-based distros
- `test`: set cmd.Dir even when running emulators
- `info`: add JSON output using the `-json` flag
* **compiler**
- `builder`: fix off-by-one in size calculation
- `builder`: handle concurrent library header rename
- `builder`: use flock to avoid double-compiles
- `builder`: use build ID as cache key
- `builder`: add -fno-stack-protector to musl build
- `builder`: update clang header search path to look in /usr/lib
- `builder`: explicitly disable unwind tables for ARM
- `cgo`: add support for `C.CString` and related functions
- `compiler`: fix ranging over maps with particular map types
- `compiler`: add correct debug location to init instructions
- `compiler`: fix emission of large object layouts
- `compiler`: work around AVR atomics bugs
- `compiler`: predeclare runtime.trackPointer
- `interp`: work around AVR function pointers in globals
- `interp`: run goroutine starts and checks at runtime
- `interp`: always run atomic and volatile loads/stores at runtime
- `interp`: bump timeout to 180 seconds
- `interp`: handle type assertions on nil interfaces
- `loader`: elminate goroot cache inconsistency
- `loader`: respect $GOROOT when running `go list`
- `transform`: allocate the correct amount of bytes in an alloca
- `transform`: remove switched func lowering
* **standard library**
- `crypto/rand`: show error if platform has no rng
- `device/*`: add `*_Msk` field for each bit field and avoid duplicates
- `device/*`: provide Set/Get for each register field described in the SVD files
- `internal/task`: swap stack chain when switching goroutines
- `internal/task`: remove `-scheduler=coroutines`
- `machine`: add `Device` string constant
- `net`: add bare Interface implementation
- `net`: add net.Buffers
- `os`: stub out support for some features
- `os`: obey TMPDIR on unix, TMP on Windows, etc
- `os`: implement `ReadAt`, `Mkdir`, `Remove`, `Stat`, `Lstat`, `CreateTemp`, `MkdirAll`, `Chdir`, `Chmod`, `Clearenv`, `Unsetenv`, `Setenv`, `MkdirTemp`, `Rename`, `Seek`, `ExpandEnv`, `Symlink`, `Readlink`
- `os`: implement `File.Stat`
- `os`: fix `IsNotExist` on nonexistent path
- `os`: fix opening files on WASI in read-only mode
- `os`: work around lack of `syscall.seek` on 386 and arm
- `reflect`: make sure indirect pointers are handled correctly
- `runtime`: allow comparing interfaces
- `runtime`: use LLVM intrinsic to read the stack pointer
- `runtime`: strengthen hashmap hash function for structs and arrays
- `runtime`: fix float/complex hashing
- `runtime`: fix nil map dereference
- `runtime`: add realloc implementation to GCs
- `runtime`: handle negative sleep times
- `runtime`: correct GC scan bounds
- `runtime`: remove extalloc GC
- `rumtime`: implement `__sync` libcalls as critical sections for most microcontrollers
- `runtime`: add stubs for `Func.FileLine` and `Frame.PC`
- `sync`: fix concurrent read-lock on write-locked RWMutex
- `sync`: add a package doc
- `sync`: add tests
- `syscall`: add support for `Mmap` and `Mprotect`
- `syscall`: fix array size for mmap slice creation
- `syscall`: enable `Getwd` in wasi
- `testing`: add a stub for `CoverMode`
- `testing`: support -bench option to run benchmarks matching the given pattern.
- `testing`: support b.SetBytes(); implement sub-benchmarks.
- `testing`: replace spaces with underscores in test/benchmark names, as upstream does
- `testing`: implement testing.Cleanup
- `testing`: allow filtering subbenchmarks with the `-bench` flag
- `testing`: implement `-benchtime` flag
- `testing`: print duration
- `testing`: allow filtering of subtests using `-run`
* **targets**
- `all`: change LLVM features to match vanilla Clang
- `avr`: use interrupt-based timer which is much more accurate
- `nrf`: fix races in I2C
- `samd51`: implement TRNG for randomness
- `stm32`: pull-up on I2C lines
- `stm32`: fix timeout for i2c comms
- `stm32f4`, `stm32f103`: initial implementation for ADC
- `stm32f4`, `stm32f7`, `stm32l0x2`, `stm32l4`, `stm32l5`, `stm32wl`: TRNG implementation in crypto/rand
- `stm32wl`: add I2C support
- `windows`: add support for the `-size=` flag
- `wasm`: add support for `tinygo test`
- `wasi`, `wasm`: raise default stack size to 16 KiB
* **boards**
- add M5Stack
- add lorae5 (stm32wle) support
- add Generic Node Sensor Edition
- add STM32F469 Discovery
- add M5Stamp C3
- add Blues Wireless Swan
- `bluepill`: add definitions for ADC pins
- `stm32f4disco`: add definitions for ADC pins
- `stm32l552ze`: use supported stlink interface
- `microbit-v2`: add some pin definitions
0.21.0
---
+68 -38
View File
@@ -1,50 +1,80 @@
# tinygo-llvm stage obtains the llvm source for TinyGo
FROM golang:1.17 AS tinygo-llvm
# TinyGo base stage installs the most recent Go 1.17.x, LLVM 11 and the TinyGo compiler itself.
FROM golang:1.17 AS tinygo-base
RUN apt-get update && \
apt-get install -y apt-utils make cmake clang-11 binutils-avr gcc-avr avr-libc ninja-build
COPY ./Makefile /tinygo/Makefile
RUN cd /tinygo/ && \
make llvm-source
# tinygo-llvm-build stage build the custom llvm with xtensa support
FROM tinygo-llvm AS tinygo-llvm-build
RUN cd /tinygo/ && \
make llvm-build
# tinygo-xtensa stage installs tools needed for ESP32
FROM tinygo-llvm-build AS tinygo-xtensa
ARG xtensa_version="1.22.0-80-g6c4433a-5.2.0"
RUN cd /tmp/ && \
wget -q https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-${xtensa_version}.tar.gz && \
tar xzf xtensa-esp32-elf-linux64-${xtensa_version}.tar.gz && \
cp ./xtensa-esp32-elf/bin/xtensa-esp32-elf-ld /usr/local/bin/ && \
rm -rf /tmp/xtensa*
# tinygo-compiler stage builds the compiler itself
FROM tinygo-xtensa AS tinygo-compiler
RUN wget -O- https://apt.llvm.org/llvm-snapshot.gpg.key| apt-key add - && \
echo "deb http://apt.llvm.org/bullseye/ llvm-toolchain-bullseye-11 main" >> /etc/apt/sources.list && \
apt-get update && \
apt-get install -y llvm-11-dev libclang-11-dev lld-11 git
COPY . /tinygo
# update submodules
# remove submodules directories and re-init them to fix any hard-coded paths
# after copying the tinygo directory in the previous step.
RUN cd /tinygo/ && \
rm -rf ./lib/*/ && \
rm -rf ./lib/* && \
git submodule sync && \
git submodule update --init --recursive --force
RUN cd /tinygo/ && \
make
# tinygo-tools stage installs the needed dependencies to compile TinyGo programs for all platforms.
FROM tinygo-compiler AS tinygo-tools
COPY ./lib/picolibc-stdio.c /tinygo/lib/picolibc-stdio.c
RUN cd /tinygo/ && \
make wasi-libc binaryen && \
make gen-device -j4 && \
cp build/* $GOPATH/bin/
go install /tinygo/
# tinygo-wasm stage installs the needed dependencies to compile TinyGo programs for WASM.
FROM tinygo-base AS tinygo-wasm
COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
COPY --from=tinygo-base /tinygo/src /tinygo/src
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
RUN cd /tinygo/ && \
apt-get update && \
apt-get install -y make clang-11 libllvm11 lld-11 cmake ninja-build && \
mkdir build && \
make wasi-libc binaryen
# tinygo-avr stage installs the needed dependencies to compile TinyGo programs for AVR microcontrollers.
FROM tinygo-base AS tinygo-avr
COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
COPY --from=tinygo-base /tinygo/src /tinygo/src
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
COPY --from=tinygo-base /tinygo/Makefile /tinygo/
COPY --from=tinygo-base /tinygo/tools /tinygo/tools
COPY --from=tinygo-base /tinygo/lib /tinygo/lib
RUN cd /tinygo/ && \
apt-get update && \
apt-get install -y apt-utils make binutils-avr gcc-avr avr-libc && \
make gen-device-avr && \
apt-get autoremove -y && \
apt-get clean
# tinygo-arm stage installs the needed dependencies to compile TinyGo programs for ARM microcontrollers.
FROM tinygo-base AS tinygo-arm
COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
COPY --from=tinygo-base /tinygo/src /tinygo/src
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
COPY --from=tinygo-base /tinygo/Makefile /tinygo/
COPY --from=tinygo-base /tinygo/tools /tinygo/tools
COPY --from=tinygo-base /tinygo/lib /tinygo/lib
RUN cd /tinygo/ && \
apt-get update && \
apt-get install -y apt-utils make clang-11 && \
make gen-device-nrf && make gen-device-stm32
# tinygo-all stage installs the needed dependencies to compile TinyGo programs for all platforms.
FROM tinygo-wasm AS tinygo-all
COPY --from=tinygo-base /tinygo/Makefile /tinygo/
COPY --from=tinygo-base /tinygo/tools /tinygo/tools
COPY --from=tinygo-base /tinygo/lib /tinygo/lib
RUN cd /tinygo/ && \
apt-get update && \
apt-get install -y apt-utils make clang-11 binutils-avr gcc-avr avr-libc && \
make gen-device
CMD ["tinygo"]
+2 -2
View File
@@ -1,7 +1,7 @@
Copyright (c) 2018-2022 The TinyGo Authors. All rights reserved.
Copyright (c) 2018-2021 TinyGo Authors. All rights reserved.
TinyGo includes portions of the Go standard library.
Copyright (c) 2009-2022 The Go Authors. All rights reserved.
Copyright (c) 2009-2021 The Go Authors. All rights reserved.
TinyGo includes portions of LLVM, which is under the Apache License v2.0 with
LLVM Exceptions. See https://llvm.org/LICENSE.txt for license information.
+29 -136
View File
@@ -9,21 +9,10 @@ CLANG_SRC ?= $(LLVM_PROJECTDIR)/clang
LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
# Try to autodetect LLVM build tools.
# Versions are listed here in descending priority order.
LLVM_VERSIONS = 13 12 11
errifempty = $(if $(1),$(1),$(error $(2)))
detect = $(shell which $(call errifempty,$(firstword $(foreach p,$(2),$(shell command -v $(p) 2> /dev/null && echo $(p)))),failed to locate $(1) at any of: $(2)))
toolSearchPathsVersion = $(1)-$(2)
ifeq ($(shell uname -s),Darwin)
# Also explicitly search Brew's copy, which is not in PATH by default.
BREW_PREFIX := $(shell brew --prefix)
toolSearchPathsVersion += $(BREW_PREFIX)/opt/llvm@$(2)/bin/$(1)-$(2) $(BREW_PREFIX)/opt/llvm@$(2)/bin/$(1)
endif
# First search for a custom built copy, then move on to explicitly version-tagged binaries, then just see if the tool is in path with its normal name.
findLLVMTool = $(call detect,$(1),$(abspath llvm-build/bin/$(1)) $(foreach ver,$(LLVM_VERSIONS),$(call toolSearchPathsVersion,$(1),$(ver))) $(1))
CLANG ?= $(call findLLVMTool,clang)
LLVM_AR ?= $(call findLLVMTool,llvm-ar)
LLVM_NM ?= $(call findLLVMTool,llvm-nm)
detect = $(shell command -v $(1) 2> /dev/null && echo $(1))
CLANG ?= $(word 1,$(abspath $(call detect,llvm-build/bin/clang))$(call detect,clang-11)$(call detect,clang))
LLVM_AR ?= $(word 1,$(abspath $(call detect,llvm-build/bin/llvm-ar))$(call detect,llvm-ar-11)$(call detect,llvm-ar))
LLVM_NM ?= $(word 1,$(abspath $(call detect,llvm-build/bin/llvm-nm))$(call detect,llvm-nm-11)$(call detect,llvm-nm))
# Go binary and GOROOT to select
GO ?= go
@@ -36,7 +25,7 @@ GOTESTFLAGS ?= -v
MD5SUM = md5sum
# tinygo binary for tests
TINYGO ?= $(call detect,tinygo,tinygo $(CURDIR)/build/tinygo)
TINYGO ?= $(word 1,$(call detect,tinygo)$(call detect,build/tinygo))
# Use CCACHE for LLVM if possible
ifneq (, $(shell command -v ccache 2> /dev/null))
@@ -68,15 +57,10 @@ ifeq ($(OS),Windows_NT)
CGO_LDFLAGS += -static -static-libgcc -static-libstdc++
CGO_LDFLAGS_EXTRA += -lversion
USE_SYSTEM_BINARYEN ?= 1
BINARYEN_OPTION += -DCMAKE_EXE_LINKER_FLAGS='-static-libgcc -static-libstdc++'
else ifeq ($(shell uname -s),Darwin)
MD5SUM = md5
CGO_LDFLAGS += -lxar
USE_SYSTEM_BINARYEN ?= 1
else ifeq ($(shell uname -s),FreeBSD)
MD5SUM = md5
START_GROUP = -Wl,--start-group
@@ -91,7 +75,7 @@ CLANG_LIB_NAMES = clangAnalysis clangAST clangASTMatchers clangBasic clangCodeGe
CLANG_LIBS = $(START_GROUP) $(addprefix -l,$(CLANG_LIB_NAMES)) $(END_GROUP) -lstdc++
# Libraries that should be linked in for the statically linked LLD.
LLD_LIB_NAMES = lldCOFF lldCommon lldCore lldDriver lldELF lldMachO2 lldMinGW lldReaderWriter lldWasm lldYAML
LLD_LIB_NAMES = lldCOFF lldCommon lldCore lldDriver lldELF lldMachO lldMinGW lldReaderWriter lldWasm lldYAML
LLD_LIBS = $(START_GROUP) $(addprefix -l,$(LLD_LIB_NAMES)) $(END_GROUP)
# Other libraries that are needed to link TinyGo.
@@ -115,6 +99,7 @@ ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
CGO_LDFLAGS+=-L$(abspath $(LLVM_BUILDDIR)/lib) -lclang $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
endif
clean:
@rm -rf build
@@ -175,7 +160,7 @@ gen-device-rp: build/gen-device-svd
# Get LLVM sources.
$(LLVM_PROJECTDIR)/llvm:
git clone -b xtensa_release_13.0.0 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
git clone -b xtensa_release_12.0.1 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
llvm-source: $(LLVM_PROJECTDIR)/llvm
# Configure LLVM.
@@ -187,7 +172,6 @@ $(LLVM_BUILDDIR)/build.ninja: llvm-source
$(LLVM_BUILDDIR): $(LLVM_BUILDDIR)/build.ninja
cd $(LLVM_BUILDDIR) && ninja $(NINJA_BUILD_TARGETS)
ifneq ($(USE_SYSTEM_BINARYEN),1)
# Build Binaryen
.PHONY: binaryen
binaryen: build/wasm-opt$(EXE)
@@ -195,39 +179,32 @@ build/wasm-opt$(EXE):
mkdir -p build
cd lib/binaryen && cmake -G Ninja . -DBUILD_STATIC_LIB=ON $(BINARYEN_OPTION) && ninja bin/wasm-opt$(EXE)
cp lib/binaryen/bin/wasm-opt$(EXE) build/wasm-opt$(EXE)
endif
# Build wasi-libc sysroot
.PHONY: wasi-libc
wasi-libc: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a
lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
cd lib/wasi-libc && make -j4 WASM_CFLAGS="-O2 -g -DNDEBUG" MALLOC_IMPL=none WASM_CC=$(CLANG) WASM_AR=$(LLVM_AR) WASM_NM=$(LLVM_NM)
cd lib/wasi-libc && make -j4 WASM_CFLAGS="-O2 -g -DNDEBUG" WASM_CC=$(CLANG) WASM_AR=$(LLVM_AR) WASM_NM=$(LLVM_NM)
# Build the Go compiler.
tinygo:
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " make llvm-source"; echo " make $(LLVM_BUILDDIR)"; exit 1; fi
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X main.gitSha1=`git rev-parse --short HEAD`" .
test: wasi-libc
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags byollvm ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
TEST_PACKAGES_SLOW = \
TEST_PACKAGES = \
compress/bzip2 \
compress/flate \
crypto/dsa \
index/suffixarray \
# Standard library packages that pass tests quickly on darwin, linux, wasi, and windows
TEST_PACKAGES_FAST = \
compress/lzw \
compress/zlib \
container/heap \
container/list \
container/ring \
crypto/des \
crypto/dsa \
crypto/elliptic/internal/fiat \
crypto/internal/subtle \
crypto/md5 \
@@ -247,17 +224,16 @@ TEST_PACKAGES_FAST = \
hash/crc64 \
hash/fnv \
html \
index/suffixarray \
internal/itoa \
internal/profile \
math \
math/cmplx \
net \
net/http/internal/ascii \
net/mail \
os \
path \
reflect \
sync \
testing \
testing/iotest \
text/scanner \
@@ -265,84 +241,18 @@ TEST_PACKAGES_FAST = \
unicode/utf16 \
unicode/utf8 \
# archive/zip requires os.ReadAt, which is not yet supported on windows
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows
# io/fs requires os.ReadDir, which is not yet supported on windows or wasi
# testing/fstest requires os.ReadDir, which is not yet supported on windows or wasi
# Additional standard library packages that pass tests on individual platforms
TEST_PACKAGES_LINUX := \
archive/zip \
debug/dwarf \
debug/plan9obj \
io/fs \
testing/fstest
TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
# Report platforms on which each standard library package is known to pass tests
jointmp := $(shell echo /tmp/join.$$$$)
report-stdlib-tests-pass:
@for t in $(TEST_PACKAGES_DARWIN); do echo "$$t darwin"; done | sort > $(jointmp).darwin
@for t in $(TEST_PACKAGES_LINUX); do echo "$$t linux"; done | sort > $(jointmp).linux
@for t in $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW); do echo "$$t darwin linux wasi windows"; done | sort > $(jointmp).portable
@join -a1 -a2 $(jointmp).darwin $(jointmp).linux | \
join -a1 -a2 - $(jointmp).portable
@rm $(jointmp).*
# Standard library packages that pass tests quickly on the current platform
ifeq ($(shell uname),Darwin)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_DARWIN)
endif
ifeq ($(shell uname),Linux)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_LINUX)
endif
ifeq ($(OS),Windows_NT)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST)
endif
# Test known-working standard library packages.
# TODO: parallelize, and only show failing tests (no implied -v flag).
.PHONY: tinygo-test
tinygo-test:
$(TINYGO) test $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
tinygo-test-fast:
$(TINYGO) test $(TEST_PACKAGES_HOST)
tinygo-bench:
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
tinygo-bench-fast:
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST)
$(TINYGO) test $(TEST_PACKAGES)
# Same thing, except for wasi rather than the current platform.
tinygo-test-wasi:
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
tinygo-test-wasi-fast:
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST)
tinygo-bench-wasi:
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
tinygo-bench-wasi-fast:
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST)
# Test external packages in a large corpus.
test-corpus:
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml
test-corpus-fast:
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus -short . -corpus=testdata/corpus.yaml
test-corpus-wasi: wasi-libc
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml -target=wasi
tinygo-baremetal:
# Regression tests that run on a baremetal target and don't fit in either main_test.go or smoketest.
# regression test for #2666: e.g. encoding/hex must pass on baremetal
$(TINYGO) test -target cortex-m-qemu encoding/hex
.PHONY: smoketest
.PHONY: smoketest smoketest-commands
smoketest:
@go run ./src/cmd/run-smoketest make smoketest-commands
smoketest-commands:
$(TINYGO) version
# compile-only platform-independent examples
cd tests/text/template/smoke && $(TINYGO) test -c && rm -f smoke.test
# regression test for #2563
cd tests/os/smoke && $(TINYGO) test -c -target=pybadge && rm smoke.test
# test all examples (except pwm)
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky1
@$(MD5SUM) test.hex
@@ -358,8 +268,6 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/echo2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/i2s
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/mcp3008
@@ -478,8 +386,6 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=qtpy examples/serial
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy41 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy40 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy36 examples/blinky1
@@ -506,8 +412,6 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=macropad-rp2040 examples/blinky1
@$(MD5SUM) test.hex
# test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex
@@ -542,12 +446,8 @@ ifneq ($(STM32), 0)
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco-1 examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f469disco examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=lorae5 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=swan examples/blinky1
@$(MD5SUM) test.hex
endif
ifneq ($(AVR), 0)
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
@@ -581,8 +481,6 @@ ifneq ($(XTENSA), 0)
endif
$(TINYGO) build -size short -o test.bin -target=esp32c3 examples/serial
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/serial
@$(MD5SUM) test.bin
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=hifive1-qemu examples/serial
@@ -606,7 +504,6 @@ endif
@$(MD5SUM) test.hex
GOOS=linux GOARCH=arm $(TINYGO) build -size short -o test.elf ./testdata/cgo
GOOS=windows GOARCH=amd64 $(TINYGO) build -size short -o test.exe ./testdata/cgo
GOOS=darwin GOARCH=amd64 $(TINYGO) build -o test ./testdata/cgo
ifneq ($(OS),Windows_NT)
# TODO: this does not yet work on Windows. Somehow, unused functions are
# not garbage collected.
@@ -617,12 +514,11 @@ endif
wasmtest:
$(GO) test ./tests/wasm
build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binaryen)
build/release: tinygo gen-device wasi-libc binaryen
@mkdir -p build/release/tinygo/bin
@mkdir -p build/release/tinygo/lib/clang/include
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
@mkdir -p build/release/tinygo/lib/compiler-rt/lib
@mkdir -p build/release/tinygo/lib/macos-minimal-sdk
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
@mkdir -p build/release/tinygo/lib/musl/arch
@@ -632,21 +528,18 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libc
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libm
@mkdir -p build/release/tinygo/lib/wasi-libc
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus
@mkdir -p build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4
@mkdir -p build/release/tinygo/pkg/armv6m-unknown-unknown-eabi
@mkdir -p build/release/tinygo/pkg/armv7m-unknown-unknown-eabi
@mkdir -p build/release/tinygo/pkg/armv7em-unknown-unknown-eabi
@echo copying source files
@cp -p build/tinygo$(EXE) build/release/tinygo/bin
ifneq ($(USE_SYSTEM_BINARYEN),1)
@cp -p build/wasm-opt$(EXE) build/release/tinygo/bin
endif
@cp -p $(abspath $(CLANG_SRC))/lib/Headers/*.h build/release/tinygo/lib/clang/include
@cp -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/CMSIS
@cp -rp lib/CMSIS/README.md build/release/tinygo/lib/CMSIS
@cp -rp lib/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt/lib
@cp -rp lib/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt
@cp -rp lib/compiler-rt/README.txt build/release/tinygo/lib/compiler-rt
@cp -rp lib/macos-minimal-sdk/* build/release/tinygo/lib/macos-minimal-sdk
@cp -rp lib/musl/arch/aarch64 build/release/tinygo/lib/musl/arch
@cp -rp lib/musl/arch/arm build/release/tinygo/lib/musl/arch
@cp -rp lib/musl/arch/generic build/release/tinygo/lib/musl/arch
@@ -684,12 +577,12 @@ endif
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
@cp -rp src build/release/tinygo/src
@cp -rp targets build/release/tinygo/targets
./build/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/compiler-rt compiler-rt
./build/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/compiler-rt compiler-rt
./build/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/compiler-rt compiler-rt
./build/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/picolibc picolibc
./build/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/picolibc picolibc
./build/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/picolibc picolibc
./build/tinygo build-library -target=armv6m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv6m-unknown-unknown-eabi/compiler-rt compiler-rt
./build/tinygo build-library -target=armv7m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7m-unknown-unknown-eabi/compiler-rt compiler-rt
./build/tinygo build-library -target=armv7em-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7em-unknown-unknown-eabi/compiler-rt compiler-rt
./build/tinygo build-library -target=armv6m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv6m-unknown-unknown-eabi/picolibc picolibc
./build/tinygo build-library -target=armv7m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7m-unknown-unknown-eabi/picolibc picolibc
./build/tinygo build-library -target=armv7em-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7em-unknown-unknown-eabi/picolibc picolibc
release: build/release
tar -czf build/release.tar.gz -C build/release tinygo
+7 -14
View File
@@ -1,6 +1,6 @@
# TinyGo - Go compiler for small places
[![Linux](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml) [![macOS](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml) [![Windows](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml) [![Docker](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml) [![CircleCI](https://circleci.com/gh/tinygo-org/tinygo/tree/dev.svg?style=svg)](https://circleci.com/gh/tinygo-org/tinygo/tree/dev)
[![CircleCI](https://circleci.com/gh/tinygo-org/tinygo/tree/dev.svg?style=svg)](https://circleci.com/gh/tinygo-org/tinygo/tree/dev) [![Windows](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml)
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (Wasm), and command-line tools.
@@ -43,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
The following 82 microcontroller boards are currently supported:
The following 74 microcontroller boards are currently supported:
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
@@ -59,7 +59,6 @@ The following 82 microcontroller boards are currently supported:
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
* [Adafruit ItsyBitsy M4](https://www.adafruit.com/product/3800)
* [Adafruit ItsyBitsy nRF52840](https://www.adafruit.com/product/4481)
* [Adafruit MacroPad RP2040](https://www.adafruit.com/product/5100)
* [Adafruit Matrix Portal M4](https://www.adafruit.com/product/4745)
* [Adafruit Metro M4 Express Airlift](https://www.adafruit.com/product/4000)
* [Adafruit PyBadge](https://www.adafruit.com/product/4200)
@@ -80,17 +79,13 @@ The following 82 microcontroller boards are currently supported:
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
* [BBC micro:bit](https://microbit.org/)
* [BBC micro:bit v2](https://microbit.org/new-microbit/)
* [blues wireless Swan](https://blues.io/products/swan/)
* [Digispark](http://digistump.com/products/1)
* [Dragino LoRaWAN GPS Tracker LGT-92](http://www.dragino.com/products/lora-lorawan-end-node/item/142-lgt-92.html)
* [ESP32 - Core board](https://www.espressif.com/en/products/socs/esp32)
* [ESP32 - mini32](https://www.espressif.com/en/products/socs/esp32)
* [ESP8266 - d1mini](https://www.espressif.com/en/products/socs/esp8266)
* [ESP8266 - NodeMCU](https://www.espressif.com/en/products/socs/esp8266)
* [ESP32](https://www.espressif.com/en/products/socs/esp32)
* [ESP8266](https://www.espressif.com/en/products/socs/esp8266)
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
* [M5Stack](https://docs.m5stack.com/en/core/basic)
* [M5Stack Core2](https://shop.m5stack.com/products/m5stack-core2-esp32-iot-development-kit)
* [M5Stamp C3](https://docs.m5stack.com/en/core/stamp_c3)
* [Makerdiary nRF52840-MDK](https://wiki.makerdiary.com/nrf52840-mdk/)
* [Makerdiary nRF52840-MDK USB Dongle](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/)
* [Microchip SAM E54 Xplained Pro](https://www.microchip.com/developmenttools/productdetails/atsame54-xpro)
@@ -107,15 +102,14 @@ The following 82 microcontroller boards are currently supported:
* [PineTime DevKit](https://www.pine64.org/pinetime/)
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
* [PJRC Teensy 4.1](https://www.pjrc.com/store/teensy41.html)
* [ProductivityOpen P1AM-100](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html)
* [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/)
* [Raytac MDBT50Q-RX Dongle (with TinyUF2 bootloader)](https://www.adafruit.com/product/5199)
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
* [Seeed 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 Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
* [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1)
* [SiFIve HiFive1](https://www.sifive.com/boards/hifive1)
* [ST Micro "Nucleo" F103RB](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html)
* [ST Micro "Nucleo" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
* [ST Micro "Nucleo" L031K6](https://www.st.com/ja/evaluation-tools/nucleo-l031k6.html)
@@ -124,9 +118,7 @@ The following 82 microcontroller boards are currently supported:
* [ST Micro "Nucleo" WL55JC](https://www.st.com/en/evaluation-tools/nucleo-wl55jc.html)
* [ST Micro STM32F103XX "Bluepill"](https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill)
* [ST Micro STM32F407 "Discovery"](https://www.st.com/en/evaluation-tools/stm32f4discovery.html)
* [ST Micro STM32F469 "Discovery"](https://www.st.com/content/st_com/en/products/evaluation-tools/product-evaluation-tools/mcu-mpu-eval-tools/stm32-mcu-mpu-eval-tools/stm32-discovery-kits/32f469idiscovery.html)
* [X9 Pro smartwatch](https://github.com/curtpw/nRF5x-device-reverse-engineering/tree/master/X9-nrf52832-activity-tracker/)
* [The Things Industries Generic Node Sensor Edition](https://www.genericnode.com/docs/sensor-edition/)
For more information, see [this list of boards](https://tinygo.org/microcontrollers/). Pull requests for additional support are welcome!
@@ -167,6 +159,7 @@ Goals:
Non-goals:
* Using more than one core.
* Be efficient while using zillions of goroutines. However, good goroutine support is certainly a goal.
* Be as fast as `gc`. However, LLVM will probably be better at optimizing certain things so TinyGo might actually turn out to be faster for number crunching.
* Be able to compile every Go program out there.
+39 -131
View File
@@ -23,7 +23,7 @@ import (
"strconv"
"strings"
"github.com/gofrs/flock"
"github.com/tinygo-org/tinygo/cgo"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/compiler"
"github.com/tinygo-org/tinygo/goenv"
@@ -45,11 +45,6 @@ type BuildResult struct {
// binary must be run in the directory of the tested package.
MainDir string
// The root of the Go module tree. This is used for running tests in emulator
// that restrict file system access to allow them to grant access to the entire
// source tree they're likely to need to read testdata from.
ModuleRoot string
// ImportPath is the import path of the main package. This is useful for
// correctly printing test results: the import path isn't always the same as
// the path listed on the command line.
@@ -68,8 +63,9 @@ type BuildResult struct {
// implementation of an imported package changes.
type packageAction struct {
ImportPath string
CompilerBuildID string
TinyGoVersion string
CGoVersion int // cgo.Version
CompilerVersion int // compiler.Version
InterpVersion int // interp.Version
LLVMVersion string
Config *compiler.Config
CFlags []string
@@ -87,32 +83,12 @@ type packageAction struct {
// The error value may be of type *MultiError. Callers will likely want to check
// for this case and print such errors individually.
func Build(pkgName, outpath string, config *compileopts.Config, action func(BuildResult) error) error {
// Read the build ID of the tinygo binary.
// Used as a cache key for package builds.
compilerBuildID, err := ReadBuildID()
if err != nil {
return err
}
// Create a temporary directory for intermediary files.
dir, err := ioutil.TempDir("", "tinygo")
if err != nil {
return err
}
if config.Options.Work {
fmt.Printf("WORK=%s\n", dir)
} else {
defer os.RemoveAll(dir)
}
// Look up the build cache directory, which is used to speed up incremental
// builds.
cacheDir := goenv.Get("GOCACHE")
if cacheDir == "off" {
// Use temporary build directory instead, effectively disabling the
// build cache.
cacheDir = dir
}
defer os.RemoveAll(dir)
// Check for a libc dependency.
// As a side effect, this also creates the headers for the given libc, if
@@ -120,23 +96,18 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
root := goenv.Get("TINYGOROOT")
var libcDependencies []*compileJob
switch config.Target.Libc {
case "darwin-libSystem":
job := makeDarwinLibSystemJob(config, dir)
libcDependencies = append(libcDependencies, job)
case "musl":
job, unlock, err := Musl.load(config, dir)
job, err := Musl.load(config, dir)
if err != nil {
return err
}
defer unlock()
libcDependencies = append(libcDependencies, dummyCompileJob(filepath.Join(filepath.Dir(job.result), "crt1.o")))
libcDependencies = append(libcDependencies, job)
case "picolibc":
libcJob, unlock, err := Picolibc.load(config, dir)
libcJob, err := Picolibc.load(config, dir)
if err != nil {
return err
}
defer unlock()
libcDependencies = append(libcDependencies, libcJob)
case "wasi-libc":
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
@@ -145,11 +116,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
}
libcDependencies = append(libcDependencies, dummyCompileJob(path))
case "mingw-w64":
_, unlock, err := MinGW.load(config, dir)
_, err := MinGW.load(config, dir)
if err != nil {
return err
}
unlock()
libcDependencies = append(libcDependencies, makeMinGWExtraLibs(dir)...)
case "":
// no library specified, so nothing to do
@@ -169,6 +139,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
SizeLevel: sizeLevel,
Scheduler: config.Scheduler(),
FuncImplementation: config.FuncImplementation(),
AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.Target.DefaultStackSize,
NeedsStackObjects: config.NeedsStackObjects(),
@@ -204,21 +175,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
var packageJobs []*compileJob
packageBitcodePaths := make(map[string]string)
packageActionIDs := make(map[string]string)
if config.Options.GlobalValues["runtime"]["buildVersion"] == "" {
version := goenv.Version
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
version += "-" + goenv.GitSha1
}
if config.Options.GlobalValues == nil {
config.Options.GlobalValues = make(map[string]map[string]string)
}
if config.Options.GlobalValues["runtime"] == nil {
config.Options.GlobalValues["runtime"] = make(map[string]string)
}
config.Options.GlobalValues["runtime"]["buildVersion"] = version
}
for _, pkg := range lprogram.Sorted() {
pkg := pkg // necessary to avoid a race condition
@@ -232,8 +188,9 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// the parameters for the build.
actionID := packageAction{
ImportPath: pkg.ImportPath,
CompilerBuildID: string(compilerBuildID),
TinyGoVersion: goenv.Version,
CGoVersion: cgo.Version,
CompilerVersion: compiler.Version,
InterpVersion: interp.Version,
LLVMVersion: llvm.Version,
Config: compilerConfig,
CFlags: pkg.CFlags,
@@ -262,22 +219,26 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Determine the path of the bitcode file (which is a serialized version
// of a LLVM module).
cacheDir := goenv.Get("GOCACHE")
if cacheDir == "off" {
// Use temporary build directory instead, effectively disabling the
// build cache.
cacheDir = dir
}
bitcodePath := filepath.Join(cacheDir, "pkg-"+hex.EncodeToString(hash[:])+".bc")
packageBitcodePaths[pkg.ImportPath] = bitcodePath
// Check whether this package has been compiled before, and if so don't
// compile it again.
if _, err := os.Stat(bitcodePath); err == nil {
// Already cached, don't recreate this package.
continue
}
// The package has not yet been compiled, so create a job to do so.
job := &compileJob{
description: "compile package " + pkg.ImportPath,
run: func(*compileJob) error {
// Acquire a lock (if supported).
unlock := lock(bitcodePath + ".lock")
defer unlock()
if _, err := os.Stat(bitcodePath); err == nil {
// Already cached, don't recreate this package.
return nil
}
// Compile AST to IR. The compiler.CompilePackage function will
// build the SSA as needed.
mod, errs := compiler.CompilePackage(pkg.ImportPath, pkg, program.Package(pkg.Pkg), machine, compilerConfig, config.DumpSSA())
@@ -434,7 +395,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Load and link all the bitcode files. This does not yet optimize
// anything, it only links the bitcode files together.
ctx := llvm.NewContext()
mod = ctx.NewModule("main")
mod = ctx.NewModule("")
for _, pkg := range lprogram.Sorted() {
pkgMod, err := ctx.ParseBitcodeFile(packageBitcodePaths[pkg.ImportPath])
if err != nil {
@@ -453,6 +414,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
llvmInitFn.SetUnnamedAddr(true)
transform.AddStandardAttributes(llvmInitFn, config)
llvmInitFn.Param(0).SetName("context")
llvmInitFn.Param(1).SetName("parentHandle")
block := mod.Context().AddBasicBlock(llvmInitFn, "entry")
irbuilder := mod.Context().NewBuilder()
defer irbuilder.Dispose()
@@ -463,7 +425,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
if pkgInit.IsNil() {
panic("init not found for " + pkg.Pkg.Path())
}
irbuilder.CreateCall(pkgInit, []llvm.Value{llvm.Undef(i8ptrType)}, "")
irbuilder.CreateCall(pkgInit, []llvm.Value{llvm.Undef(i8ptrType), llvm.Undef(i8ptrType)}, "")
}
irbuilder.CreateRetVoid()
@@ -517,7 +479,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
outext := filepath.Ext(outpath)
if outext == ".o" || outext == ".bc" || outext == ".ll" {
// Run jobs to produce the LLVM module.
err := runJobs(programJob, config.Options.Semaphore)
err := runJobs(programJob, config.Options.Parallelism)
if err != nil {
return err
}
@@ -530,14 +492,8 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
}
return ioutil.WriteFile(outpath, llvmBuf.Bytes(), 0666)
case ".bc":
var buf llvm.MemoryBuffer
if config.UseThinLTO() {
buf = llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
} else {
buf = llvm.WriteBitcodeToMemoryBuffer(mod)
}
defer buf.Dispose()
return ioutil.WriteFile(outpath, buf.Bytes(), 0666)
data := llvm.WriteBitcodeToMemoryBuffer(mod).Bytes()
return ioutil.WriteFile(outpath, data, 0666)
case ".ll":
data := []byte(mod.String())
return ioutil.WriteFile(outpath, data, 0666)
@@ -557,17 +513,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
dependencies: []*compileJob{programJob},
result: objfile,
run: func(*compileJob) error {
var llvmBuf llvm.MemoryBuffer
if config.UseThinLTO() {
llvmBuf = llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
} else {
var err error
llvmBuf, err = machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
if err != nil {
return err
}
llvmBuf, err := machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
if err != nil {
return err
}
defer llvmBuf.Dispose()
return ioutil.WriteFile(objfile, llvmBuf.Bytes(), 0666)
},
}
@@ -584,11 +533,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Add compiler-rt dependency if needed. Usually this is a simple load from
// a cache.
if config.Target.RTLib == "compiler-rt" {
job, unlock, err := CompilerRT.load(config, dir)
job, err := CompilerRT.load(config, dir)
if err != nil {
return err
}
defer unlock()
linkerDependencies = append(linkerDependencies, job)
}
@@ -600,7 +548,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
job := &compileJob{
description: "compile extra file " + path,
run: func(job *compileJob) error {
result, err := compileAndCacheCFile(abspath, dir, config.CFlags(), config.UseThinLTO(), config.Options.PrintCommands)
result, err := compileAndCacheCFile(abspath, dir, config.CFlags(), config.Options.PrintCommands)
job.result = result
return err
},
@@ -618,7 +566,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
job := &compileJob{
description: "compile CGo file " + abspath,
run: func(job *compileJob) error {
result, err := compileAndCacheCFile(abspath, dir, pkg.CFlags, config.UseThinLTO(), config.Options.PrintCommands)
result, err := compileAndCacheCFile(abspath, dir, pkg.CFlags, config.Options.PrintCommands)
job.result = result
return err
},
@@ -687,24 +635,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
if config.Options.PrintCommands != nil {
config.Options.PrintCommands(config.Target.Linker, ldflags...)
}
if config.UseThinLTO() {
ldflags = append(ldflags,
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"),
"-plugin-opt=mcpu="+config.CPU(),
"-plugin-opt=O"+strconv.Itoa(optLevel),
"-plugin-opt=thinlto")
if config.CodeModel() != "default" {
ldflags = append(ldflags,
"-mllvm", "-code-model="+config.CodeModel())
}
if sizeLevel >= 2 {
// Workaround with roughly the same effect as
// https://reviews.llvm.org/D119342.
// Can hopefully be removed in LLVM 15.
ldflags = append(ldflags,
"-mllvm", "--rotation-max-header-size=0")
}
}
err = link(config.Target.Linker, ldflags...)
if err != nil {
return &commandError{"failed to link", executable, err}
@@ -810,7 +740,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Run all jobs to compile and link the program.
// Do this now (instead of after elf-to-hex and similar conversions) as it
// is simpler and cannot be parallelized.
err = runJobs(linkJob, config.Options.Semaphore)
err = runJobs(linkJob, config.Options.Parallelism)
if err != nil {
return err
}
@@ -858,18 +788,9 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
default:
return fmt.Errorf("unknown output binary format: %s", outputBinaryFormat)
}
// If there's a module root, use that.
moduleroot := lprogram.MainPkg().Module.Dir
if moduleroot == "" {
// if not, just the regular root
moduleroot = lprogram.MainPkg().Root
}
return action(BuildResult{
Binary: tmppath,
MainDir: lprogram.MainPkg().Dir,
ModuleRoot: moduleroot,
ImportPath: lprogram.MainPkg().ImportPath,
})
}
@@ -895,7 +816,7 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
}
}
if config.GOOS() != "darwin" && !config.UseThinLTO() {
if config.GOOS() != "darwin" {
transform.ApplyFunctionSections(mod) // -ffunction-sections
}
@@ -1260,16 +1181,3 @@ func patchRP2040BootCRC(executable string) error {
// Update the .boot2 section to included the CRC
return replaceElfSection(executable, ".boot2", bytes)
}
// lock may acquire a lock at the specified path.
// It returns a function to release the lock.
// If flock is not supported, it does nothing.
func lock(path string) func() {
flock := flock.New(path)
err := flock.Lock()
if err != nil {
return func() {}
}
return func() { flock.Close() }
}
-103
View File
@@ -1,103 +0,0 @@
package builder
import (
"bytes"
"debug/elf"
"debug/macho"
"encoding/binary"
"fmt"
"io"
"os"
"runtime"
)
// ReadBuildID reads the build ID from the currently running executable.
func ReadBuildID() ([]byte, error) {
executable, err := os.Executable()
if err != nil {
return nil, err
}
f, err := os.Open(executable)
if err != nil {
return nil, err
}
defer f.Close()
switch runtime.GOOS {
case "linux", "freebsd":
// Read the GNU build id section. (Not sure about FreeBSD though...)
file, err := elf.NewFile(f)
if err != nil {
return nil, err
}
var gnuID, goID []byte
for _, section := range file.Sections {
if section.Type != elf.SHT_NOTE ||
(section.Name != ".note.gnu.build-id" && section.Name != ".note.go.buildid") {
continue
}
buf := make([]byte, section.Size)
n, err := section.ReadAt(buf, 0)
if uint64(n) != section.Size || err != nil {
return nil, fmt.Errorf("could not read build id: %w", err)
}
if section.Name == ".note.gnu.build-id" {
gnuID = buf
} else {
goID = buf
}
}
if gnuID != nil {
return gnuID, nil
} else if goID != nil {
return goID, nil
}
case "darwin":
// Read the LC_UUID load command, which contains the equivalent of a
// build ID.
file, err := macho.NewFile(f)
if err != nil {
return nil, err
}
for _, load := range file.Loads {
// Unfortunately, the debug/macho package doesn't support the
// LC_UUID command directly. So we have to read it from
// macho.LoadBytes.
load, ok := load.(macho.LoadBytes)
if !ok {
continue
}
raw := load.Raw()
command := binary.LittleEndian.Uint32(raw)
if command != 0x1b {
// Looking for the LC_UUID load command.
// LC_UUID is defined here as 0x1b:
// https://opensource.apple.com/source/xnu/xnu-4570.71.2/EXTERNAL_HEADERS/mach-o/loader.h.auto.html
continue
}
return raw[4:], nil
}
default:
// On other platforms (such as Windows) there isn't such a convenient
// build ID. Luckily, Go does have an equivalent of the build ID, which
// is stored as a special symbol named go.buildid. You can read it
// using `go tool buildid`, but the code below extracts it directly
// from the binary.
// Unfortunately, because of stripping with the -w flag, no symbol
// table might be available. Therefore, we have to scan the binary
// directly. Luckily the build ID is always at the start of the file.
// For details, see:
// https://github.com/golang/go/blob/master/src/cmd/internal/buildid/buildid.go
fileStart := make([]byte, 4096)
_, err := io.ReadFull(f, fileStart)
index := bytes.Index(fileStart, []byte("\xff Go build ID: \""))
if index < 0 || index > len(fileStart)-103 {
return nil, fmt.Errorf("could not find build id in %s", err)
}
buf := fileStart[index : index+103]
if bytes.HasPrefix(buf, []byte("\xff Go build ID: \"")) && bytes.HasSuffix(buf, []byte("\"\n \xff")) {
return buf[len("\xff Go build ID: \"") : len(buf)-1], nil
}
}
return nil, fmt.Errorf("could not find build ID in %s", executable)
}
+6 -18
View File
@@ -56,22 +56,13 @@ import (
// depfile but without invalidating its name. For this reason, the depfile is
// written on each new compilation (even when it seems unnecessary). However, it
// could in rare cases lead to a stale file fetched from the cache.
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool, printCommands func(string, ...string)) (string, error) {
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands func(string, ...string)) (string, error) {
// Hash input file.
fileHash, err := hashFile(abspath)
if err != nil {
return "", err
}
// Acquire a lock (if supported).
unlock := lock(filepath.Join(goenv.Get("GOCACHE"), fileHash+".c.lock"))
defer unlock()
ext := ".o"
if thinlto {
ext = ".bc"
}
// Create cache key for the dependencies file.
buf, err := json.Marshal(struct {
Path string
@@ -104,7 +95,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
}
// Obtain hashes of all the files listed as a dependency.
outpath, err := makeCFileCachePath(dependencies, depfileNameHash, ext)
outpath, err := makeCFileCachePath(dependencies, depfileNameHash)
if err == nil {
if _, err := os.Stat(outpath); err == nil {
return outpath, nil
@@ -117,7 +108,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
return "", err
}
objTmpFile, err := ioutil.TempFile(goenv.Get("GOCACHE"), "tmp-*"+ext)
objTmpFile, err := ioutil.TempFile(goenv.Get("GOCACHE"), "tmp-*.o")
if err != nil {
return "", err
}
@@ -129,9 +120,6 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
depTmpFile.Close()
flags := append([]string{}, cflags...) // copy cflags
flags = append(flags, "-MD", "-MV", "-MTdeps", "-MF", depTmpFile.Name()) // autogenerate dependencies
if thinlto {
flags = append(flags, "-flto=thin")
}
flags = append(flags, "-c", "-o", objTmpFile.Name(), abspath)
if strings.ToLower(filepath.Ext(abspath)) == ".s" {
// If this is an assembly file (.s or .S, lowercase or uppercase), then
@@ -189,7 +177,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
}
// Move temporary object file to final location.
outpath, err := makeCFileCachePath(dependencySlice, depfileNameHash, ext)
outpath, err := makeCFileCachePath(dependencySlice, depfileNameHash)
if err != nil {
return "", err
}
@@ -204,7 +192,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool,
// Create a cache path (a path in GOCACHE) to store the output of a compiler
// job. This path is based on the dep file name (which is a hash of metadata
// including compiler flags) and the hash of all input files in the paths slice.
func makeCFileCachePath(paths []string, depfileNameHash, ext string) (string, error) {
func makeCFileCachePath(paths []string, depfileNameHash string) (string, error) {
// Hash all input files.
fileHashes := make(map[string]string, len(paths))
for _, path := range paths {
@@ -229,7 +217,7 @@ func makeCFileCachePath(paths []string, depfileNameHash, ext string) (string, er
outFileNameBuf := sha512.Sum512_224(buf)
cacheKey := hex.EncodeToString(outFileNameBuf[:])
outpath := filepath.Join(goenv.Get("GOCACHE"), "obj-"+cacheKey+ext)
outpath := filepath.Join(goenv.Get("GOCACHE"), "obj-"+cacheKey+".o")
return outpath, nil
}
+37 -42
View File
@@ -115,26 +115,29 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Any DebugInfoKind implies GenDwarfForAssembly.
Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections_EQ)) {
Opts.CompressDebugSections =
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
.Case("none", llvm::DebugCompressionType::None)
.Case("zlib", llvm::DebugCompressionType::Z)
.Case("zlib-gnu", llvm::DebugCompressionType::GNU)
.Default(llvm::DebugCompressionType::None);
if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
OPT_compress_debug_sections_EQ)) {
if (A->getOption().getID() == OPT_compress_debug_sections) {
// TODO: be more clever about the compression type auto-detection
Opts.CompressDebugSections = llvm::DebugCompressionType::GNU;
} else {
Opts.CompressDebugSections =
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
.Case("none", llvm::DebugCompressionType::None)
.Case("zlib", llvm::DebugCompressionType::Z)
.Case("zlib-gnu", llvm::DebugCompressionType::GNU)
.Default(llvm::DebugCompressionType::None);
}
}
Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
Opts.DwarfDebugFlags =
std::string(Args.getLastArgValue(OPT_dwarf_debug_flags));
Opts.DwarfDebugProducer =
std::string(Args.getLastArgValue(OPT_dwarf_debug_producer));
if (const Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ,
options::OPT_fdebug_compilation_dir_EQ))
Opts.DebugCompilationDir = A->getValue();
Opts.DebugCompilationDir =
std::string(Args.getLastArgValue(OPT_fdebug_compilation_dir));
Opts.MainFileName = std::string(Args.getLastArgValue(OPT_main_file_name));
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
@@ -216,7 +219,7 @@ getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
std::error_code EC;
auto Out = std::make_unique<raw_fd_ostream>(
Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_TextWithCRLF));
Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_Text));
if (EC) {
Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
return nullptr;
@@ -225,8 +228,7 @@ getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
return Out;
}
static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
DiagnosticsEngine &Diags) {
bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
// Get the target specific parser.
std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error);
@@ -234,7 +236,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
MemoryBuffer::getFileOrSTDIN(Opts.InputFile);
if (std::error_code EC = Buffer.getError()) {
Error = EC.message();
@@ -275,15 +277,11 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
if (!Opts.SplitDwarfOutput.empty())
DwoOS = getOutputStream(Opts.SplitDwarfOutput, Diags, IsBinary);
// Build up the feature string from the target feature list.
std::string FS = llvm::join(Opts.Features, ",");
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
std::unique_ptr<MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
assert(STI && "Unable to create subtarget info!");
MCContext Ctx(Triple(Opts.Triple), MAI.get(), MRI.get(), STI.get(), &SrcMgr,
&MCOptions);
MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr, &MCOptions);
bool PIC = false;
if (Opts.RelocationModel == "static") {
@@ -296,12 +294,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
PIC = false;
}
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
std::unique_ptr<MCObjectFileInfo> MOFI(
TheTarget->createMCObjectFileInfo(Ctx, PIC));
Ctx.setObjectFileInfo(MOFI.get());
MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, Ctx);
if (Opts.SaveTemporaryLabels)
Ctx.setAllowTemporaryLabels(false);
if (Opts.GenDwarfForAssembly)
@@ -323,16 +316,19 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
if (!Opts.MainFileName.empty())
Ctx.setMainFileName(StringRef(Opts.MainFileName));
Ctx.setDwarfFormat(Opts.Dwarf64 ? dwarf::DWARF64 : dwarf::DWARF32);
Ctx.setDwarfVersion(Opts.DwarfVersion);
if (Opts.GenDwarfForAssembly)
Ctx.setGenDwarfRootFile(Opts.InputFile,
SrcMgr.getMemoryBuffer(BufferIndex)->getBuffer());
// Build up the feature string from the target feature list.
std::string FS = llvm::join(Opts.Features, ",");
std::unique_ptr<MCStreamer> Str;
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
assert(MCII && "Unable to create instruction info!");
std::unique_ptr<MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
raw_pwrite_stream *Out = FDOS.get();
std::unique_ptr<buffer_ostream> BOS;
@@ -371,8 +367,6 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
std::unique_ptr<MCAsmBackend> MAB(
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
assert(MAB && "Unable to create asm backend!");
std::unique_ptr<MCObjectWriter> OW =
DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS)
: MAB->createObjectWriter(*Out);
@@ -387,7 +381,8 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
// is emitted in __LLVM,__asm section if the object file is MachO format.
if (Opts.EmbedBitcode && Ctx.getObjectFileType() == MCContext::IsMachO) {
if (Opts.EmbedBitcode && Ctx.getObjectFileInfo()->getObjectFileType() ==
MCObjectFileInfo::IsMachO) {
MCSection *AsmLabel = Ctx.getMachOSection(
"__LLVM", "__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly());
Str.get()->SwitchSection(AsmLabel);
@@ -424,12 +419,12 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
Failed = Parser->Run(Opts.NoInitialTextSection);
}
return Failed;
}
bool ExecuteAssembler(AssemblerInvocation &Opts,
DiagnosticsEngine &Diags) {
bool Failed = ExecuteAssemblerImpl(Opts, Diags);
// Close Streamer first.
// It might have a reference to the output stream.
Str.reset();
// Close the output stream early.
BOS.reset();
FDOS.reset();
// Delete output file if there were errors.
if (Failed) {
@@ -477,7 +472,7 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
return 1;
if (Asm.ShowHelp) {
getDriverOptTable().printHelp(
getDriverOptTable().PrintHelp(
llvm::outs(), "clang -cc1as [options] file...",
"Clang Integrated Assembler",
/*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,
-2
View File
@@ -39,7 +39,6 @@ struct AssemblerInvocation {
unsigned SaveTemporaryLabels : 1;
unsigned GenDwarfForAssembly : 1;
unsigned RelaxELFRelocations : 1;
unsigned Dwarf64 : 1;
unsigned DwarfVersion;
std::string DwarfDebugFlags;
std::string DwarfDebugProducer;
@@ -109,7 +108,6 @@ public:
FatalWarnings = 0;
NoWarn = 0;
IncrementalLinkerCompatible = 0;
Dwarf64 = 0;
DwarfVersion = 0;
EmbedBitcode = 0;
}
+1 -11
View File
@@ -2,7 +2,6 @@ package builder
import (
"errors"
"fmt"
"os"
"os/exec"
"runtime"
@@ -26,16 +25,7 @@ func init() {
// Add the path to a Homebrew-installed LLVM for ease of use (no need to
// manually set $PATH).
if runtime.GOOS == "darwin" {
var prefix string
switch runtime.GOARCH {
case "amd64":
prefix = "/usr/local/opt/llvm@" + llvmMajor + "/bin/"
case "arm64":
prefix = "/opt/homebrew/opt/llvm@" + llvmMajor + "/bin/"
default:
// unknown GOARCH
panic(fmt.Sprintf("unknown GOARCH: %s on darwin", runtime.GOARCH))
}
prefix := "/usr/local/opt/llvm@" + llvmMajor + "/bin/"
commands["clang"] = append(commands["clang"], prefix+"clang-"+llvmMajor)
commands["ld.lld"] = append(commands["ld.lld"], prefix+"ld.lld")
commands["wasm-ld"] = append(commands["wasm-ld"], prefix+"wasm-ld")
-58
View File
@@ -1,58 +0,0 @@
package builder
import (
"path/filepath"
"strings"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
)
// Create a job that builds a Darwin libSystem.dylib stub library. This library
// contains all the symbols needed so that we can link against it, but it
// doesn't contain any real symbol implementations.
func makeDarwinLibSystemJob(config *compileopts.Config, tmpdir string) *compileJob {
return &compileJob{
description: "compile Darwin libSystem.dylib",
run: func(job *compileJob) (err error) {
arch := strings.Split(config.Triple(), "-")[0]
job.result = filepath.Join(tmpdir, "libSystem.dylib")
objpath := filepath.Join(tmpdir, "libSystem.o")
inpath := filepath.Join(goenv.Get("TINYGOROOT"), "lib/macos-minimal-sdk/src", arch, "libSystem.s")
// Compile assembly file to object file.
flags := []string{
"-nostdlib",
"--target=" + config.Triple(),
"-c",
"-o", objpath,
inpath,
}
if config.Options.PrintCommands != nil {
config.Options.PrintCommands("clang", flags...)
}
err = runCCompiler(flags...)
if err != nil {
return err
}
// Link object file to dynamic library.
platformVersion := strings.TrimPrefix(strings.Split(config.Triple(), "-")[2], "macosx")
flags = []string{
"-flavor", "darwinnew",
"-demangle",
"-dynamic",
"-dylib",
"-arch", arch,
"-platform_version", "macos", platformVersion, platformVersion,
"-install_name", "/usr/lib/libSystem.B.dylib",
"-o", job.result,
objpath,
}
if config.Options.PrintCommands != nil {
config.Options.PrintCommands("ld.lld", flags...)
}
return link("ld.lld", flags...)
},
}
}
-14
View File
@@ -84,20 +84,6 @@ func getClangHeaderPath(TINYGOROOT string) string {
}
}
// On Arch Linux, the clang executable is stored in /usr/bin rather than being symlinked from there.
// Search directly in /usr/lib for clang.
if matches, err := filepath.Glob("/usr/lib/clang/" + llvmMajor + ".*.*"); err == nil {
// Check for the highest version first.
sort.Strings(matches)
for i := len(matches) - 1; i >= 0; i-- {
path := filepath.Join(matches[i], "include")
_, err := os.Stat(filepath.Join(path, "stdint.h"))
if err == nil {
return path
}
}
}
// Could not find it.
return ""
}
+87 -117
View File
@@ -4,12 +4,8 @@ package builder
// parallel while taking care of dependencies.
import (
"container/heap"
"errors"
"fmt"
"runtime"
"sort"
"strings"
"time"
)
@@ -33,6 +29,7 @@ type compileJob struct {
dependencies []*compileJob
result string // result (path)
run func(*compileJob) (err error)
state jobState
err error // error if finished
duration time.Duration // how long it took to run this job (only set after finishing)
}
@@ -47,20 +44,41 @@ func dummyCompileJob(result string) *compileJob {
}
}
// readyToRun returns whether this job is ready to run: it is itself not yet
// started and all dependencies are finished.
func (job *compileJob) readyToRun() bool {
if job.state != jobStateQueued {
// Already running or finished, so shouldn't be run again.
return false
}
// Check dependencies.
for _, dep := range job.dependencies {
if dep.state != jobStateFinished {
// A dependency is not finished, so this job has to wait until it
// is.
return false
}
}
// All conditions are satisfied.
return true
}
// runJobs runs the indicated job and all its dependencies. For every job, all
// the dependencies are run first. It returns the error of the first job that
// fails.
// It runs all jobs in the order of the dependencies slice, depth-first.
// Therefore, if some jobs are preferred to run before others, they should be
// ordered as such in the job dependencies.
func runJobs(job *compileJob, sema chan struct{}) error {
if sema == nil {
// Have a default, if the semaphore isn't set. This is useful for
func runJobs(job *compileJob, parallelism int) error {
if parallelism == 0 {
// Have a default, if the parallelism isn't set. This is useful for
// tests.
sema = make(chan struct{}, runtime.NumCPU())
parallelism = runtime.NumCPU()
}
if cap(sema) == 0 {
return errors.New("cannot 0 jobs at a time")
if parallelism < 1 {
return fmt.Errorf("-p flag must be at least 1, provided -p=%d", parallelism)
}
// Create a slice of jobs to run, where all dependencies are run in order.
@@ -79,91 +97,64 @@ func runJobs(job *compileJob, sema chan struct{}) error {
}
addJobs(job)
waiting := make(map[*compileJob]map[*compileJob]struct{}, len(jobs))
dependents := make(map[*compileJob][]*compileJob, len(jobs))
jidx := make(map[*compileJob]int)
var ready intHeap
for i, job := range jobs {
jidx[job] = i
if len(job.dependencies) == 0 {
// This job is ready to run.
ready.Push(i)
continue
}
// Construct a map for dependencies which the job is currently waiting on.
waitDeps := make(map[*compileJob]struct{})
waiting[job] = waitDeps
// Add the job to the dependents list of each dependency.
for _, dep := range job.dependencies {
dependents[dep] = append(dependents[dep], job)
waitDeps[dep] = struct{}{}
}
}
// Create a channel to accept notifications of completion.
// Create channels to communicate with the workers.
doneChan := make(chan *compileJob)
workerChan := make(chan *compileJob)
defer close(workerChan)
// Start a number of workers.
for i := 0; i < parallelism; i++ {
if jobRunnerDebug {
fmt.Println("## starting worker", i)
}
go jobWorker(workerChan, doneChan)
}
// Send each job in the jobs slice to a worker, taking care of job
// dependencies.
numRunningJobs := 0
var totalTime time.Duration
start := time.Now()
for len(ready.IntSlice) > 0 || numRunningJobs != 0 {
var completed *compileJob
if len(ready.IntSlice) > 0 {
select {
case sema <- struct{}{}:
// Start a job.
job := jobs[heap.Pop(&ready).(int)]
for {
// If there are free workers, try starting a new job (if one is
// available). If it succeeds, try again to fill the entire worker pool.
if numRunningJobs < parallelism {
jobToRun := nextJob(jobs)
if jobToRun != nil {
// Start job.
if jobRunnerDebug {
fmt.Println("## start: ", job.description)
fmt.Println("## start: ", jobToRun.description)
}
go runJob(job, doneChan)
jobToRun.state = jobStateRunning
workerChan <- jobToRun
numRunningJobs++
continue
case completed = <-doneChan:
// A job completed.
}
} else {
// Wait for a job to complete.
completed = <-doneChan
}
// When there are no jobs running, all jobs in the jobs slice must have
// been finished. Therefore, the work is done.
if numRunningJobs == 0 {
break
}
// Wait until a job is finished.
job := <-doneChan
job.state = jobStateFinished
numRunningJobs--
<-sema
totalTime += job.duration
if jobRunnerDebug {
fmt.Println("## finished:", job.description, "(time "+job.duration.String()+")")
}
if completed.err != nil {
// Wait for any current jobs to finish.
if job.err != nil {
// Wait for running jobs to finish.
for numRunningJobs != 0 {
<-doneChan
numRunningJobs--
}
// The build failed.
return completed.err
// Return error of first failing job.
return job.err
}
// Update total run time.
totalTime += completed.duration
// Update dependent jobs.
for _, j := range dependents[completed] {
wait := waiting[j]
delete(wait, completed)
if len(wait) == 0 {
// This job is now ready to run.
ready.Push(jidx[j])
delete(waiting, j)
}
}
}
if len(waiting) != 0 {
// There is a dependency cycle preventing some jobs from running.
return errDependencyCycle{waiting}
}
// Some statistics, if debugging.
@@ -180,50 +171,29 @@ func runJobs(job *compileJob, sema chan struct{}) error {
return nil
}
type errDependencyCycle struct {
waiting map[*compileJob]map[*compileJob]struct{}
}
func (err errDependencyCycle) Error() string {
waits := make([]string, 0, len(err.waiting))
for j, wait := range err.waiting {
deps := make([]string, 0, len(wait))
for dep := range wait {
deps = append(deps, dep.description)
}
sort.Strings(deps)
waits = append(waits, fmt.Sprintf("\t%s is waiting for [%s]",
j.description, strings.Join(deps, ", "),
))
}
sort.Strings(waits)
return "deadlock:\n" + strings.Join(waits, "\n")
}
type intHeap struct {
sort.IntSlice
}
func (h *intHeap) Push(x interface{}) {
h.IntSlice = append(h.IntSlice, x.(int))
}
func (h *intHeap) Pop() interface{} {
x := h.IntSlice[len(h.IntSlice)-1]
h.IntSlice = h.IntSlice[:len(h.IntSlice)-1]
return x
}
// runJob runs a compile job and notifies doneChan of completion.
func runJob(job *compileJob, doneChan chan *compileJob) {
start := time.Now()
if job.run != nil {
err := job.run(job)
if err != nil {
job.err = err
// nextJob returns the first ready-to-run job.
// This is an implementation detail of runJobs.
func nextJob(jobs []*compileJob) *compileJob {
for _, job := range jobs {
if job.readyToRun() {
return job
}
}
job.duration = time.Since(start)
doneChan <- job
return nil
}
// jobWorker is the goroutine that runs received jobs.
// This is an implementation detail of runJobs.
func jobWorker(workerChan, doneChan chan *compileJob) {
for job := range workerChan {
start := time.Now()
if job.run != nil {
err := job.run(job)
if err != nil {
job.err = err
}
}
job.duration = time.Since(start)
doneChan <- job
}
}
+13 -57
View File
@@ -4,9 +4,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
@@ -38,12 +36,11 @@ type Library struct {
// The resulting directory may be stored in the provided tmpdir, which is
// expected to be removed after the Load call.
func (l *Library) Load(config *compileopts.Config, tmpdir string) (dir string, err error) {
job, unlock, err := l.load(config, tmpdir)
job, err := l.load(config, tmpdir)
if err != nil {
return "", err
}
defer unlock()
err = runJobs(job, config.Options.Semaphore)
err = runJobs(job, config.Options.Parallelism)
return filepath.Dir(job.result), err
}
@@ -55,38 +52,28 @@ func (l *Library) Load(config *compileopts.Config, tmpdir string) (dir string, e
// output archive file, it is expected to be removed after use.
// As a side effect, this call creates the library header files if they didn't
// exist yet.
func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJob, abortLock func(), err error) {
func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJob, err error) {
outdir, precompiled := config.LibcPath(l.name)
archiveFilePath := filepath.Join(outdir, "lib.a")
if precompiled {
// Found a precompiled library for this OS/architecture. Return the path
// directly.
return dummyCompileJob(archiveFilePath), func() {}, nil
return dummyCompileJob(archiveFilePath), nil
}
// Create a lock on the output (if supported).
// This is a bit messy, but avoids a deadlock because it is ordered consistently with other library loads within a build.
outname := filepath.Base(outdir)
unlock := lock(filepath.Join(goenv.Get("GOCACHE"), outname+".lock"))
var ok bool
defer func() {
if !ok {
unlock()
}
}()
// Try to fetch this library from the cache.
if _, err := os.Stat(archiveFilePath); err == nil {
return dummyCompileJob(archiveFilePath), func() {}, nil
return dummyCompileJob(archiveFilePath), nil
}
// Cache miss, build it now.
// Create the destination directory where the components of this library
// (lib.a file, include directory) are placed.
outname := filepath.Base(outdir)
err = os.MkdirAll(filepath.Join(goenv.Get("GOCACHE"), outname), 0o777)
if err != nil {
// Could not create directory (and not because it already exists).
return nil, nil, err
return nil, err
}
// Make headers if needed.
@@ -96,36 +83,16 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
if _, err = os.Stat(headerPath); err != nil {
temporaryHeaderPath, err := ioutil.TempDir(outdir, "include.tmp*")
if err != nil {
return nil, nil, err
return nil, err
}
defer os.RemoveAll(temporaryHeaderPath)
err = l.makeHeaders(target, temporaryHeaderPath)
if err != nil {
return nil, nil, err
}
err = os.Chmod(temporaryHeaderPath, 0o755) // TempDir uses 0o700 by default
if err != nil {
return nil, nil, err
return nil, err
}
err = os.Rename(temporaryHeaderPath, headerPath)
if err != nil {
switch {
case os.IsExist(err):
// Another invocation of TinyGo also seems to have already created the headers.
case runtime.GOOS == "windows" && os.IsPermission(err):
// On Windows, a rename with a destination directory that already
// exists does not result in an IsExist error, but rather in an
// access denied error. To be sure, check for this case by checking
// whether the target directory exists.
if _, err := os.Stat(headerPath); err == nil {
break
}
fallthrough
default:
return nil, nil, err
}
return nil, err
}
}
}
@@ -134,7 +101,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
dir := filepath.Join(tmpdir, "build-lib-"+l.name)
err = os.Mkdir(dir, 0777)
if err != nil {
return nil, nil, err
return nil, err
}
// Precalculate the flags to the compiler invocation.
@@ -153,7 +120,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
}
}
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft", "-fno-unwind-tables")
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft")
}
if strings.HasPrefix(target, "riscv32-") {
args = append(args, "-march=rv32imac", "-mabi=ilp32", "-fforce-enable-int128")
@@ -162,8 +129,6 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
args = append(args, "-march=rv64gc", "-mabi=lp64")
}
var once sync.Once
// Create job to put all the object files in a single archive. This archive
// file is the (static) library file.
var objs []string
@@ -171,8 +136,6 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
description: "ar " + l.name + "/lib.a",
result: filepath.Join(goenv.Get("GOCACHE"), outname, "lib.a"),
run: func(*compileJob) error {
defer once.Do(unlock)
// Create an archive of all object files.
f, err := ioutil.TempFile(outdir, "libc.a.tmp*")
if err != nil {
@@ -186,10 +149,6 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
if err != nil {
return err
}
err = os.Chmod(f.Name(), 0o644) // TempFile uses 0o600 by default
if err != nil {
return err
}
// Store this archive in the cache.
return os.Rename(f.Name(), archiveFilePath)
},
@@ -248,8 +207,5 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
})
}
ok = true
return job, func() {
once.Do(unlock)
}, nil
return job, nil
}
-5
View File
@@ -11,11 +11,6 @@ bool tinygo_link_elf(int argc, char **argv) {
return lld::elf::link(args, false, llvm::outs(), llvm::errs());
}
bool tinygo_link_macho(int argc, char **argv) {
std::vector<const char*> args(argv, argv + argc);
return lld::macho::link(args, false, llvm::outs(), llvm::errs());
}
bool tinygo_link_mingw(int argc, char **argv) {
std::vector<const char*> args(argv, argv + argc);
return lld::mingw::link(args, false, llvm::outs(), llvm::errs());
-1
View File
@@ -101,7 +101,6 @@ var Musl = Library{
"-I" + muslDir + "/src/internal",
"-I" + headerPath,
"-I" + muslDir + "/include",
"-fno-stack-protector",
}
},
sourceDir: "lib/musl/src",
+1 -1
View File
@@ -28,7 +28,7 @@ var Picolibc = Library{
"-DHAVE_ALIAS_ATTRIBUTE",
"-DTINY_STDIO",
"-nostdlibinc",
"-isystem", picolibcDir + "/include",
"-Xclang", "-internal-isystem", "-Xclang", picolibcDir + "/include",
"-I" + picolibcDir + "/tinystdio",
"-I" + headerPath,
}
+2 -11
View File
@@ -1,4 +1,3 @@
//go:build byollvm
// +build byollvm
package builder
@@ -14,7 +13,6 @@ import (
#include <stdlib.h>
bool tinygo_clang_driver(int argc, char **argv);
bool tinygo_link_elf(int argc, char **argv);
bool tinygo_link_macho(int argc, char **argv);
bool tinygo_link_mingw(int argc, char **argv);
bool tinygo_link_wasm(int argc, char **argv);
*/
@@ -28,13 +26,8 @@ const hasBuiltinTools = true
// linking statically with LLVM (with the byollvm build tag).
func RunTool(tool string, args ...string) error {
linker := "elf"
if tool == "ld.lld" && len(args) >= 2 {
if args[0] == "-m" && args[1] == "i386pep" {
linker = "mingw"
} else if args[0] == "-flavor" {
linker = args[1]
args = args[2:]
}
if tool == "ld.lld" && len(args) >= 2 && args[0] == "-m" && args[1] == "i386pep" {
linker = "mingw"
}
args = append([]string{"tinygo:" + tool}, args...)
@@ -54,8 +47,6 @@ func RunTool(tool string, args ...string) error {
ok = C.tinygo_clang_driver(C.int(len(args)), (**C.char)(buf))
case "ld.lld":
switch linker {
case "darwinnew":
ok = C.tinygo_link_macho(C.int(len(args)), (**C.char)(buf))
case "elf":
ok = C.tinygo_link_elf(C.int(len(args)), (**C.char)(buf))
case "mingw":
-1
View File
@@ -1,4 +1,3 @@
//go:build !byollvm
// +build !byollvm
package builder
+7 -4
View File
@@ -26,6 +26,12 @@ import (
"golang.org/x/tools/go/ast/astutil"
)
// Version of the cgo package. It must be incremented whenever the cgo package
// is changed in a way that affects the output so that cached package builds
// will be invalidated.
// This version is independent of the TinyGo version number.
const Version = 1 // last change: run libclang once per Go file
// cgoPackage holds all CGo-related information of a package.
type cgoPackage struct {
generated *ast.File
@@ -197,7 +203,7 @@ func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
// functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
// hashes of the accessed C header files. If there is one or more error, it
// returns these in the []error slice but still modifies the AST.
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string, clangHeaders string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
p := &cgoPackage{
currentDir: dir,
fset: fset,
@@ -333,9 +339,6 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
// have better alternatives anyway.
cflagsForCGo := append([]string{"-D_FORTIFY_SOURCE=0"}, cflags...)
cflagsForCGo = append(cflagsForCGo, p.cflags...)
if clangHeaders != "" {
cflagsForCGo = append(cflagsForCGo, "-isystem", clangHeaders)
}
// Process CGo imports for each file.
for i, f := range files {
+1 -1
View File
@@ -63,7 +63,7 @@ func TestCGo(t *testing.T) {
}
// Process the AST with CGo.
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags, "")
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags)
// Check the AST for type errors.
var typecheckErrors []error
+1 -1
View File
@@ -16,7 +16,7 @@ import (
)
/*
#include <clang-c/Index.h> // If this fails, libclang headers aren't available. Please take a look here: https://tinygo.org/docs/guides/build/
#include <clang-c/Index.h> // if this fails, install libclang-11-dev
#include <stdlib.h>
#include <stdint.h>
+14
View File
@@ -0,0 +1,14 @@
// +build !byollvm
// +build !llvm12
package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-11/include
#cgo darwin CFLAGS: -I/usr/local/opt/llvm@11/include
#cgo freebsd CFLAGS: -I/usr/local/llvm11/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-11/lib -lclang
#cgo darwin LDFLAGS: -L/usr/local/opt/llvm@11/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm11/lib -lclang
*/
import "C"
-16
View File
@@ -1,16 +0,0 @@
//go:build !byollvm && llvm11
// +build !byollvm,llvm11
package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-11/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@11/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@11/include
#cgo freebsd CFLAGS: -I/usr/local/llvm11/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-11/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@11/lib -lclang -lffi
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@11/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm11/lib -lclang
*/
import "C"
+8 -10
View File
@@ -1,16 +1,14 @@
//go:build !byollvm && llvm12
// +build !byollvm,llvm12
// +build !byollvm
// +build llvm12
package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-12/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@12/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@12/include
#cgo freebsd CFLAGS: -I/usr/local/llvm12/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-12/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@12/lib -lclang -lffi
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@12/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm12/lib -lclang
#cgo linux CFLAGS: -I/usr/lib/llvm-12/include
#cgo darwin CFLAGS: -I/usr/local/opt/llvm@12/include
#cgo freebsd CFLAGS: -I/usr/local/llvm12/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-12/lib -lclang
#cgo darwin LDFLAGS: -L/usr/local/opt/llvm@12/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm12/lib -lclang
*/
import "C"
-16
View File
@@ -1,16 +0,0 @@
//go:build !byollvm && !llvm11 && !llvm12
// +build !byollvm,!llvm11,!llvm12
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"
+1 -1
View File
@@ -3,7 +3,7 @@
// are slightly different from the ones defined in libclang.go, but they
// should be ABI compatible.
#include <clang-c/Index.h> // If this fails, libclang headers aren't available. Please take a look here: https://tinygo.org/docs/guides/build/
#include <clang-c/Index.h> // if this fails, install libclang-11-dev
CXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu) {
return clang_getTranslationUnitCursor(tu);
+44 -84
View File
@@ -85,7 +85,7 @@ func (c *Config) CgoEnabled() bool {
}
// GC returns the garbage collection strategy in use on this platform. Valid
// values are "none", "leaking", and "conservative".
// values are "none", "leaking", "extalloc", and "conservative".
func (c *Config) GC() string {
if c.Options.GC != "" {
return c.Options.GC
@@ -100,7 +100,7 @@ func (c *Config) GC() string {
// that can be traced by the garbage collector.
func (c *Config) NeedsStackObjects() bool {
switch c.GC() {
case "conservative":
case "conservative", "extalloc":
for _, tag := range c.BuildTags() {
if tag == "tinygo.wasm" {
return true
@@ -114,7 +114,7 @@ func (c *Config) NeedsStackObjects() bool {
}
// Scheduler returns the scheduler implementation. Valid values are "none",
// "asyncify" and "tasks".
//"coroutines" and "tasks".
func (c *Config) Scheduler() string {
if c.Options.Scheduler != "" {
return c.Options.Scheduler
@@ -122,8 +122,8 @@ func (c *Config) Scheduler() string {
if c.Target.Scheduler != "" {
return c.Target.Scheduler
}
// Fall back to none.
return "none"
// Fall back to coroutines, which are supported everywhere.
return "coroutines"
}
// Serial returns the serial implementation for this build configuration: uart,
@@ -159,6 +159,31 @@ func (c *Config) OptLevels() (optLevel, sizeLevel int, inlinerThreshold uint) {
}
}
// FuncImplementation picks an appropriate func value implementation for the
// target.
func (c *Config) FuncImplementation() string {
switch c.Scheduler() {
case "tasks", "asyncify":
// A func value is implemented as a pair of pointers:
// {context, function pointer}
// where the context may be a pointer to a heap-allocated struct
// containing the free variables, or it may be undef if the function
// being pointed to doesn't need a context. The function pointer is a
// regular function pointer.
return "doubleword"
case "none", "coroutines":
// As "doubleword", but with the function pointer replaced by a unique
// ID per function signature. Function values are called by using a
// switch statement and choosing which function to call.
// Pick the switch implementation with the coroutines scheduler, as it
// allows the use of blocking inside a function that is used as a func
// value.
return "switch"
default:
panic("unknown scheduler type")
}
}
// PanicStrategy returns the panic strategy selected for this target. Valid
// values are "print" (print the panic value, then exit) or "trap" (issue a trap
// instruction).
@@ -176,34 +201,6 @@ func (c *Config) AutomaticStackSize() bool {
return false
}
// UseThinLTO returns whether ThinLTO should be used for the given target. Some
// targets (such as wasm) are not yet supported.
// We should try and remove as many exceptions as possible in the future, so
// that this optimization can be applied in more places.
func (c *Config) UseThinLTO() bool {
parts := strings.Split(c.Triple(), "-")
if parts[0] == "wasm32" {
// wasm-ld doesn't seem to support ThinLTO yet.
return false
}
if parts[0] == "avr" || parts[0] == "xtensa" {
// These use external (GNU) linkers which might perhaps support ThinLTO
// through a plugin, but it's too much hassle to set up.
return false
}
if len(parts) >= 2 && strings.HasPrefix(parts[2], "macos") {
// We use an external linker here at the moment.
return false
}
if len(parts) >= 2 && parts[2] == "windows" {
// Linker error (undefined runtime.trackedGlobalsBitmap) when linking
// for Windows. Disable it for now until that's figured out and fixed.
return false
}
// Other architectures support ThinLTO.
return true
}
// RP2040BootPatch returns whether the RP2040 boot patch should be applied that
// calculates and patches in the checksum for the 2nd stage bootloader.
func (c *Config) RP2040BootPatch() bool {
@@ -227,13 +224,8 @@ func MuslArchitecture(triple string) string {
// a precompiled libc shipped with a TinyGo build, or a libc path in the cache
// directory (which might not yet be built).
func (c *Config) LibcPath(name string) (path string, precompiled bool) {
archname := c.Triple()
if c.CPU() != "" {
archname += "-" + c.CPU()
}
// Try to load a precompiled library.
precompiledDir := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", archname, name)
precompiledDir := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", c.Triple(), name)
if _, err := os.Stat(precompiledDir); err == nil {
// Found a precompiled library for this OS/architecture. Return the path
// directly.
@@ -242,30 +234,13 @@ func (c *Config) LibcPath(name string) (path string, precompiled bool) {
// No precompiled library found. Determine the path name that will be used
// in the build cache.
return filepath.Join(goenv.Get("GOCACHE"), name+"-"+archname), false
}
// DefaultBinaryExtension returns the default extension for binaries, such as
// .exe, .wasm, or no extension (depending on the target).
func (c *Config) DefaultBinaryExtension() string {
parts := strings.Split(c.Triple(), "-")
if parts[0] == "wasm32" {
// WebAssembly files always have the .wasm file extension.
return ".wasm"
var outname string
if c.CPU() != "" {
outname = name + "-" + c.Triple() + "-" + c.CPU()
} else {
outname = name + "-" + c.Triple()
}
if len(parts) >= 3 && parts[2] == "windows" {
// Windows uses .exe.
return ".exe"
}
if len(parts) >= 3 && parts[2] == "unknown" {
// There appears to be a convention to use the .elf file extension for
// ELF files intended for microcontrollers. I'm not aware of the origin
// of this, it's just something that is used by many projects.
// I think it's a good tradition, so let's keep it.
return ".elf"
}
// Linux, MacOS, etc, don't use a file extension. Use it as a fallback.
return ""
return filepath.Join(goenv.Get("GOCACHE"), outname), false
}
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo
@@ -276,29 +251,23 @@ func (c *Config) CFlags() []string {
cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT")))
}
switch c.Target.Libc {
case "darwin-libSystem":
root := goenv.Get("TINYGOROOT")
cflags = append(cflags,
"--sysroot="+filepath.Join(root, "lib/macos-minimal-sdk/src"),
)
case "picolibc":
root := goenv.Get("TINYGOROOT")
picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc")
path, _ := c.LibcPath("picolibc")
cflags = append(cflags,
"--sysroot="+path,
"-isystem", filepath.Join(picolibcDir, "include"),
"-isystem", filepath.Join(picolibcDir, "tinystdio"),
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "include"),
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "tinystdio"),
)
case "musl":
root := goenv.Get("TINYGOROOT")
path, _ := c.LibcPath("musl")
arch := MuslArchitecture(c.Triple())
cflags = append(cflags,
"-nostdlibinc",
"-isystem", filepath.Join(path, "include"),
"-isystem", filepath.Join(root, "lib", "musl", "arch", arch),
"-isystem", filepath.Join(root, "lib", "musl", "include"),
"--sysroot="+path,
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "musl", "arch", arch),
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "musl", "include"),
)
case "wasi-libc":
root := goenv.Get("TINYGOROOT")
@@ -308,8 +277,8 @@ func (c *Config) CFlags() []string {
path, _ := c.LibcPath("mingw-w64")
cflags = append(cflags,
"--sysroot="+path,
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "crt"),
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "defaults", "include"),
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "crt"),
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "defaults", "include"),
"-D_UCRT",
)
case "":
@@ -493,15 +462,6 @@ func (c *Config) WasmAbi() string {
return c.Target.WasmAbi
}
// Emulator returns the emulator target config
func (c *Config) Emulator() []string {
var emulator []string
for _, s := range c.Target.Emulator {
emulator = append(emulator, strings.ReplaceAll(s, "{root}", goenv.Get("TINYGOROOT")))
}
return emulator
}
type TestConfig struct {
CompileTestBinary bool
// TODO: Filter the test functions to run, include verbose flag, etc
+4 -7
View File
@@ -7,8 +7,8 @@ import (
)
var (
validGCOptions = []string{"none", "leaking", "conservative"}
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
validGCOptions = []string{"none", "leaking", "extalloc", "conservative"}
validSchedulerOptions = []string{"none", "tasks", "coroutines", "asyncify"}
validSerialOptions = []string{"none", "uart", "usb"}
validPrintSizeOptions = []string{"none", "short", "full"}
validPanicStrategyOptions = []string{"print", "trap"}
@@ -28,12 +28,11 @@ type Options struct {
PanicStrategy string
Scheduler string
Serial string
Work bool // -work flag to print temporary build directory
PrintIR bool
DumpSSA bool
VerifyIR bool
PrintCommands func(cmd string, args ...string) `json:"-"`
Semaphore chan struct{} `json:"-"` // -p flag controls cap
PrintCommands func(cmd string, args ...string)
Parallelism int // -p flag
Debug bool
PrintSizes string
PrintAllocs *regexp.Regexp // regexp string
@@ -45,8 +44,6 @@ type Options struct {
Programmer string
OpenOCDCommands []string
LLVMFeatures string
Directory string
PrintJSON bool
}
// Verify performs a validation on the given options, raising an error if options are not valid.
+14 -2
View File
@@ -9,8 +9,8 @@ import (
func TestVerifyOptions(t *testing.T) {
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, conservative`)
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, asyncify`)
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, extalloc, conservative`)
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, coroutines, asyncify`)
expectedPrintSizeError := errors.New(`invalid size option 'incorrect': valid values are none, short, full`)
expectedPanicStrategyError := errors.New(`invalid panic option 'incorrect': valid values are print, trap`)
@@ -42,6 +42,12 @@ func TestVerifyOptions(t *testing.T) {
GC: "leaking",
},
},
{
name: "GCOptionExtalloc",
opts: compileopts.Options{
GC: "extalloc",
},
},
{
name: "GCOptionConservative",
opts: compileopts.Options{
@@ -67,6 +73,12 @@ func TestVerifyOptions(t *testing.T) {
Scheduler: "tasks",
},
},
{
name: "SchedulerOptionCoroutines",
opts: compileopts.Options{
Scheduler: "coroutines",
},
},
{
name: "InvalidPrintSizeOption",
opts: compileopts.Options{
+10 -28
View File
@@ -258,30 +258,21 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
spec.Features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
case "arm":
spec.CPU = "generic"
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables")
switch strings.Split(triple, "-")[0] {
case "armv5":
spec.Features = "+armv5t,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
spec.Features = "+armv5t,+strict-align,-thumb-mode"
case "armv6":
spec.Features = "+armv6,+dsp,+fp64,+strict-align,+vfp2,+vfp2sp,-aes,-d32,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-neon,-sha2,-thumb-mode,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
spec.Features = "+armv6,+dsp,+fp64,+strict-align,+vfp2,+vfp2sp,-thumb-mode"
case "armv7":
spec.Features = "+armv7-a,+d32,+dsp,+fp64,+neon,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-aes,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-sha2,-thumb-mode,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
spec.Features = "+armv7-a,+d32,+dsp,+fp64,+neon,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-thumb-mode"
}
case "arm64":
spec.CPU = "generic"
spec.Features = "+neon"
}
if goos == "darwin" {
spec.Linker = "ld.lld"
spec.Libc = "darwin-libSystem"
arch := strings.Split(triple, "-")[0]
platformVersion := strings.TrimPrefix(strings.Split(triple, "-")[2], "macosx")
spec.LDFlags = append(spec.LDFlags,
"-flavor", "darwinnew",
"-dead_strip",
"-arch", arch,
"-platform_version", "macos", platformVersion, platformVersion,
)
spec.CFlags = append(spec.CFlags, "-isysroot", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk")
spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip")
} else if goos == "linux" {
spec.Linker = "ld.lld"
spec.RTLib = "compiler-rt"
@@ -325,20 +316,11 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
if goarch != runtime.GOARCH {
// Some educated guesses as to how to invoke helper programs.
spec.GDB = []string{"gdb-multiarch"}
if goos == "linux" {
switch goarch {
case "386":
// amd64 can _usually_ run 32-bit programs, so skip the emulator in that case.
if runtime.GOARCH != "amd64" {
spec.Emulator = []string{"qemu-i386"}
}
case "amd64":
spec.Emulator = []string{"qemu-x86_64"}
case "arm":
spec.Emulator = []string{"qemu-arm"}
case "arm64":
spec.Emulator = []string{"qemu-aarch64"}
}
if goarch == "arm" && goos == "linux" {
spec.Emulator = []string{"qemu-arm"}
}
if goarch == "arm64" && goos == "linux" {
spec.Emulator = []string{"qemu-aarch64"}
}
}
if goos != runtime.GOOS {
-32
View File
@@ -1,7 +1,6 @@
package compiler
import (
"fmt"
"strings"
"golang.org/x/tools/go/ssa"
@@ -17,20 +16,6 @@ func (b *builder) createAtomicOp(call *ssa.CallCommon) (llvm.Value, bool) {
case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
ptr := b.getValue(call.Args[0])
val := b.getValue(call.Args[1])
if strings.HasPrefix(b.Triple, "avr") {
// AtomicRMW does not work on AVR as intended:
// - There are some register allocation issues (fixed by https://reviews.llvm.org/D97127 which is not yet in a usable LLVM release)
// - The result is the new value instead of the old value
vType := val.Type()
name := fmt.Sprintf("__sync_fetch_and_add_%d", vType.IntTypeWidth()/8)
fn := b.mod.NamedFunction(name)
if fn.IsNil() {
fn = llvm.AddFunction(b.mod, name, llvm.FunctionType(vType, []llvm.Type{ptr.Type(), vType}, false))
}
oldVal := b.createCall(fn, []llvm.Value{ptr, val}, "")
// Return the new value, not the original value returned.
return b.CreateAdd(oldVal, val, ""), true
}
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAdd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
// Return the new value, not the original value returned by atomicrmw.
return b.CreateAdd(oldVal, val, ""), true
@@ -88,23 +73,6 @@ func (b *builder) createAtomicOp(call *ssa.CallCommon) (llvm.Value, bool) {
case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer":
ptr := b.getValue(call.Args[0])
val := b.getValue(call.Args[1])
if strings.HasPrefix(b.Triple, "avr") {
// SelectionDAGBuilder is currently missing the "are unaligned atomics allowed" check for stores.
vType := val.Type()
isPointer := vType.TypeKind() == llvm.PointerTypeKind
if isPointer {
// libcalls only supports integers, so cast to an integer.
vType = b.uintptrType
val = b.CreatePtrToInt(val, vType, "")
ptr = b.CreateBitCast(ptr, llvm.PointerType(vType, 0), "")
}
name := fmt.Sprintf("__atomic_store_%d", vType.IntTypeWidth()/8)
fn := b.mod.NamedFunction(name)
if fn.IsNil() {
fn = llvm.AddFunction(b.mod, name, llvm.FunctionType(vType, []llvm.Type{ptr.Type(), vType, b.uintptrType}, false))
}
return b.createCall(fn, []llvm.Value{ptr, val, llvm.ConstInt(b.uintptrType, 5, false)}, ""), true
}
store := b.CreateStore(val, ptr)
store.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
store.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
+2 -1
View File
@@ -40,7 +40,8 @@ func (b *builder) createRuntimeCall(fnName string, args []llvm.Value, name strin
if llvmFn.IsNil() {
panic("trying to call non-existent function: " + fn.RelString(nil))
}
args = append(args, llvm.Undef(b.i8ptrType)) // unused context parameter
args = append(args, llvm.Undef(b.i8ptrType)) // unused context parameter
args = append(args, llvm.ConstPointerNull(b.i8ptrType)) // coroutine handle
return b.createCall(llvmFn, args, name)
}
+38 -80
View File
@@ -20,6 +20,11 @@ import (
"tinygo.org/x/go-llvm"
)
// Version of the compiler pacakge. Must be incremented each time the compiler
// package changes in a way that affects the generated LLVM module.
// This version is independent of the TinyGo version number.
const Version = 25 // last change: add "target-cpu" and "target-features" attributes
func init() {
llvm.InitializeAllTargets()
llvm.InitializeAllTargetMCs()
@@ -47,6 +52,7 @@ type Config struct {
// Various compiler options that determine how code is generated.
Scheduler string
FuncImplementation string
AutomaticStackSize bool
DefaultStackSize uint64
NeedsStackObjects bool
@@ -77,7 +83,6 @@ type compilerContext struct {
diagnostics []error
astComments map[string]*ast.CommentGroup
pkg *types.Package
packageDir string // directory for this package
runtimePkg *types.Package
}
@@ -139,8 +144,6 @@ type builder struct {
deferPtr llvm.Value
difunc llvm.Metadata
dilocals map[*types.Var]llvm.Metadata
initInlinedAt llvm.Metadata // fake inlinedAt position
initPseudoFuncs map[string]llvm.Metadata // fake "inlined" functions for proper init debug locations
allDeferFuncs []interface{}
deferFuncs map[*ssa.Function]int
deferInvokeFuncs map[string]int
@@ -234,22 +237,16 @@ func Sizes(machine llvm.TargetMachine) types.Sizes {
panic("unknown pointer size")
}
// Construct a complex128 type because that's likely the type with the
// biggest alignment on most/all ABIs.
ctx := llvm.NewContext()
defer ctx.Dispose()
complex128Type := ctx.StructType([]llvm.Type{ctx.DoubleType(), ctx.DoubleType()}, false)
return &stdSizes{
IntSize: int64(intWidth / 8),
PtrSize: int64(targetData.PointerSize()),
MaxAlign: int64(targetData.ABITypeAlignment(complex128Type)),
MaxAlign: int64(targetData.PrefTypeAlignment(targetData.IntPtrType())),
}
}
// CompilePackage compiles a single package to a LLVM module.
func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package, machine llvm.TargetMachine, config *Config, dumpSSA bool) (llvm.Module, []error) {
c := newCompilerContext(moduleName, machine, config, dumpSSA)
c.packageDir = pkg.OriginalDir()
c.pkg = pkg.Pkg
c.runtimePkg = ssaPkg.Prog.ImportedPackage("runtime").Pkg
c.program = ssaPkg.Prog
@@ -274,10 +271,6 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
// Predeclare the runtime.alloc function, which is used by the wordpack
// functionality.
c.getFunction(c.program.ImportedPackage("runtime").Members["alloc"].(*ssa.Function))
if c.NeedsStackObjects {
// Predeclare trackPointer, which is used everywhere we use runtime.alloc.
c.getFunction(c.program.ImportedPackage("runtime").Members["trackPointer"].(*ssa.Function))
}
// Compile all functions, methods, and global variables in this package.
irbuilder := c.ctx.NewBuilder()
@@ -608,51 +601,6 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
}
}
// setDebugLocation sets the current debug location for the builder.
func (b *builder) setDebugLocation(pos token.Pos) {
if pos == token.NoPos {
// No debug information available for this instruction.
b.SetCurrentDebugLocation(0, 0, b.difunc, llvm.Metadata{})
return
}
position := b.program.Fset.Position(pos)
if b.fn.Synthetic == "package initializer" {
// Package initializers are treated specially, because while individual
// Go SSA instructions have file/line/col information, the parent
// function does not. LLVM doesn't store filename information per
// instruction, only per function. We work around this difference by
// creating a fake DIFunction for each Go file and say that the
// instruction really came from that (fake) function but was inlined in
// the package initializer function.
position := b.program.Fset.Position(pos)
name := filepath.Base(position.Filename)
difunc, ok := b.initPseudoFuncs[name]
if !ok {
diFuncType := b.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
File: b.getDIFile(position.Filename),
})
difunc = b.dibuilder.CreateFunction(b.getDIFile(position.Filename), llvm.DIFunction{
Name: b.fn.RelString(nil) + "#" + name,
File: b.getDIFile(position.Filename),
Line: 0,
Type: diFuncType,
LocalToUnit: true,
IsDefinition: true,
ScopeLine: 0,
Flags: llvm.FlagPrototyped,
Optimized: true,
})
b.initPseudoFuncs[name] = difunc
}
b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), difunc, b.initInlinedAt)
return
}
// Regular debug information.
b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), b.difunc, llvm.Metadata{})
}
// getLocalVariable returns a debug info entry for a local variable, which may
// either be a parameter or a regular variable. It will create a new metadata
// entry if there isn't one for the variable yet.
@@ -905,14 +853,16 @@ func (b *builder) createFunction() {
// Add debug info, if needed.
if b.Debug {
if b.fn.Synthetic == "package initializer" {
// Package initializer functions have no debug info. Create some
// fake debug info to at least have *something*.
b.difunc = b.attachDebugInfoRaw(b.fn, b.llvmFn, "", b.packageDir, 0)
// Package initializers have no debug info. Create some fake debug
// info to at least have *something*.
filename := b.fn.Package().Pkg.Path() + "/<init>"
b.difunc = b.attachDebugInfoRaw(b.fn, b.llvmFn, "", filename, 0)
} else if b.fn.Syntax() != nil {
// Create debug info file if needed.
b.difunc = b.attachDebugInfo(b.fn)
}
b.setDebugLocation(b.fn.Pos())
pos := b.program.Fset.Position(b.fn.Pos())
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
}
// Pre-create all basic blocks in the function.
@@ -924,16 +874,6 @@ func (b *builder) createFunction() {
entryBlock := b.blockEntries[b.fn.Blocks[0]]
b.SetInsertPointAtEnd(entryBlock)
if b.fn.Synthetic == "package initializer" {
b.initPseudoFuncs = make(map[string]llvm.Metadata)
// Create a fake 'inlined at' metadata node.
// See setDebugLocation for details.
alloca := b.CreateAlloca(b.uintptrType, "")
b.initInlinedAt = alloca.InstructionDebugLoc()
alloca.EraseFromParentAsInstruction()
}
// Load function parameters
llvmParamIndex := 0
for _, param := range b.fn.Params {
@@ -972,7 +912,9 @@ func (b *builder) createFunction() {
// method).
var context llvm.Value
if !b.info.exported {
context = b.llvmFn.LastParam()
parentHandle := b.llvmFn.LastParam()
parentHandle.SetName("parentHandle")
context = llvm.PrevParam(parentHandle)
context.SetName("context")
}
if len(b.fn.FreeVars) != 0 {
@@ -1126,7 +1068,8 @@ func getPos(val posser) token.Pos {
// particular Go SSA instruction.
func (b *builder) createInstruction(instr ssa.Instruction) {
if b.Debug {
b.setDebugLocation(getPos(instr))
pos := b.program.Fset.Position(getPos(instr))
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
}
switch instr := instr.(type) {
@@ -1233,7 +1176,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
case "cap":
value := argValues[0]
var llvmCap llvm.Value
switch argTypes[0].Underlying().(type) {
switch argTypes[0].(type) {
case *types.Chan:
llvmCap = b.createRuntimeCall("chanCap", []llvm.Value{value}, "cap")
case *types.Slice:
@@ -1508,6 +1451,9 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
// This function takes a context parameter.
// Add it to the end of the parameter list.
params = append(params, context)
// Parent coroutine handle.
params = append(params, llvm.Undef(b.i8ptrType))
}
return b.createCall(callee, params, ""), nil
@@ -1576,9 +1522,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
switch expr := expr.(type) {
case *ssa.Alloc:
typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
size := b.targetData.TypeAllocSize(typ)
// Move all "large" allocations to the heap. This value is also transform.maxStackAlloc.
if expr.Heap || size > 256 {
if expr.Heap {
size := b.targetData.TypeAllocSize(typ)
// Calculate ^uintptr(0)
maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue()
if size > maxSize {
@@ -1847,7 +1792,20 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
if expr.IsString {
return b.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil
} else { // map
return b.createMapIteratorNext(rangeVal, llvmRangeVal, it), nil
llvmKeyType := b.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
llvmValueType := b.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
mapKeyAlloca, mapKeyPtr, mapKeySize := b.createTemporaryAlloca(llvmKeyType, "range.key")
mapValueAlloca, mapValuePtr, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyPtr, mapValuePtr}, "range.next")
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
tuple = b.CreateInsertValue(tuple, ok, 0, "")
tuple = b.CreateInsertValue(tuple, b.CreateLoad(mapKeyAlloca, ""), 1, "")
tuple = b.CreateInsertValue(tuple, b.CreateLoad(mapValueAlloca, ""), 2, "")
b.emitLifetimeEnd(mapKeyPtr, mapKeySize)
b.emitLifetimeEnd(mapValuePtr, mapValueSize)
return tuple, nil
}
case *ssa.Phi:
phi := b.CreatePHI(b.getLLVMType(expr.Type()), "")
+4 -8
View File
@@ -55,9 +55,10 @@ func TestCompiler(t *testing.T) {
{"string.go", "", ""},
{"float.go", "", ""},
{"interface.go", "", ""},
{"func.go", "", ""},
{"func.go", "", "coroutines"},
{"pragma.go", "", ""},
{"goroutine.go", "wasm", "asyncify"},
{"goroutine.go", "wasm", "coroutines"},
{"goroutine.go", "cortex-m-qemu", "tasks"},
{"channel.go", "", ""},
{"intrinsics.go", "cortex-m-qemu", ""},
@@ -105,9 +106,9 @@ func TestCompiler(t *testing.T) {
CodeModel: config.CodeModel(),
RelocationModel: config.RelocationModel(),
Scheduler: config.Scheduler(),
FuncImplementation: config.FuncImplementation(),
AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.Target.DefaultStackSize,
NeedsStackObjects: config.NeedsStackObjects(),
}
machine, err := NewTargetMachine(compilerConfig)
if err != nil {
@@ -223,12 +224,7 @@ func filterIrrelevantIRLines(lines []string) []string {
}
if llvmVersion < 12 && strings.HasPrefix(line, "attributes ") {
// Ignore attribute groups. These may change between LLVM versions.
// Right now test outputs are for LLVM 12 and higher.
continue
}
if llvmVersion < 13 && strings.HasPrefix(line, "target datalayout = ") {
// The datalayout string may vary betewen LLVM versions.
// Right now test outputs are for LLVM 13 and higher.
// Right now test outputs are for LLVM 12.
continue
}
out = append(out, line)
+9
View File
@@ -343,6 +343,9 @@ func (b *builder) createRunDefers() {
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
}
// Parent coroutine handle.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
b.createCall(fnPtr, forwardParams, "")
case *ssa.Function:
@@ -371,6 +374,9 @@ func (b *builder) createRunDefers() {
// Add the context parameter. We know it is ignored by the receiving
// function, but we have to pass one anyway.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
// Parent coroutine handle.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
}
// Call real function.
@@ -397,6 +403,9 @@ func (b *builder) createRunDefers() {
forwardParams = append(forwardParams, forwardParam)
}
// Parent coroutine handle.
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
// Call deferred function.
b.createCall(b.getFunction(fn), forwardParams, "")
case *ssa.Builtin:
+55 -9
View File
@@ -19,8 +19,29 @@ func (b *builder) createFuncValue(funcPtr, context llvm.Value, sig *types.Signat
// createFuncValue creates a function value from a raw function pointer with no
// context.
func (c *compilerContext) createFuncValue(builder llvm.Builder, funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
// Closure is: {context, function pointer}
funcValueScalar := llvm.ConstBitCast(funcPtr, c.rawVoidFuncType)
var funcValueScalar llvm.Value
switch c.FuncImplementation {
case "doubleword":
// Closure is: {context, function pointer}
funcValueScalar = llvm.ConstBitCast(funcPtr, c.rawVoidFuncType)
case "switch":
funcValueWithSignatureGlobalName := funcPtr.Name() + "$withSignature"
funcValueWithSignatureGlobal := c.mod.NamedGlobal(funcValueWithSignatureGlobalName)
if funcValueWithSignatureGlobal.IsNil() {
funcValueWithSignatureType := c.getLLVMRuntimeType("funcValueWithSignature")
funcValueWithSignature := llvm.ConstNamedStruct(funcValueWithSignatureType, []llvm.Value{
llvm.ConstPtrToInt(funcPtr, c.uintptrType),
c.getFuncSignatureID(sig),
})
funcValueWithSignatureGlobal = llvm.AddGlobal(c.mod, funcValueWithSignatureType, funcValueWithSignatureGlobalName)
funcValueWithSignatureGlobal.SetInitializer(funcValueWithSignature)
funcValueWithSignatureGlobal.SetGlobalConstant(true)
funcValueWithSignatureGlobal.SetLinkage(llvm.LinkOnceODRLinkage)
}
funcValueScalar = llvm.ConstPtrToInt(funcValueWithSignatureGlobal, c.uintptrType)
default:
panic("unimplemented func value variant")
}
funcValueType := c.getFuncType(sig)
funcValue := llvm.Undef(funcValueType)
funcValue = builder.CreateInsertValue(funcValue, context, 0, "")
@@ -57,19 +78,43 @@ func (b *builder) extractFuncContext(funcValue llvm.Value) llvm.Value {
// value. This may be an expensive operation.
func (b *builder) decodeFuncValue(funcValue llvm.Value, sig *types.Signature) (funcPtr, context llvm.Value) {
context = b.CreateExtractValue(funcValue, 0, "")
bitcast := b.CreateExtractValue(funcValue, 1, "")
if !bitcast.IsAConstantExpr().IsNil() && bitcast.Opcode() == llvm.BitCast {
funcPtr = bitcast.Operand(0)
return
switch b.FuncImplementation {
case "doubleword":
bitcast := b.CreateExtractValue(funcValue, 1, "")
if !bitcast.IsAConstantExpr().IsNil() && bitcast.Opcode() == llvm.BitCast {
funcPtr = bitcast.Operand(0)
return
}
llvmSig := b.getRawFuncType(sig)
funcPtr = b.CreateBitCast(bitcast, llvmSig, "")
case "switch":
if !funcValue.IsAConstant().IsNil() {
// If this is a constant func value, the underlying function is
// known and can be returned directly.
funcValueWithSignatureGlobal := llvm.ConstExtractValue(funcValue, []uint32{1}).Operand(0)
funcPtr = llvm.ConstExtractValue(funcValueWithSignatureGlobal.Initializer(), []uint32{0}).Operand(0)
return
}
llvmSig := b.getRawFuncType(sig)
sigGlobal := b.getFuncSignatureID(sig)
funcPtr = b.createRuntimeCall("getFuncPtr", []llvm.Value{funcValue, sigGlobal}, "")
funcPtr = b.CreateIntToPtr(funcPtr, llvmSig, "")
default:
panic("unimplemented func value variant")
}
llvmSig := b.getRawFuncType(sig)
funcPtr = b.CreateBitCast(bitcast, llvmSig, "")
return
}
// getFuncType returns the type of a func value given a signature.
func (c *compilerContext) getFuncType(typ *types.Signature) llvm.Type {
return c.ctx.StructType([]llvm.Type{c.i8ptrType, c.rawVoidFuncType}, false)
switch c.FuncImplementation {
case "doubleword":
return c.ctx.StructType([]llvm.Type{c.i8ptrType, c.rawVoidFuncType}, false)
case "switch":
return c.getLLVMRuntimeType("funcValue")
default:
panic("unimplemented func value variant")
}
}
// getRawFuncType returns a LLVM function pointer type for a given signature.
@@ -115,6 +160,7 @@ func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
}
// All functions take these parameters at the end.
paramTypes = append(paramTypes, c.i8ptrType) // context
paramTypes = append(paramTypes, c.i8ptrType) // parent coroutine
// Make a func type out of the signature.
return llvm.PointerType(llvm.FunctionType(returnType, paramTypes, false), c.funcPtrAddrSpace)
+53 -21
View File
@@ -30,6 +30,11 @@ func (b *builder) createGo(instr *ssa.Go) {
switch value := instr.Call.Value.(type) {
case *ssa.Function:
// Goroutine call is regular function call. No context is necessary.
if b.Scheduler == "coroutines" {
// The context parameter is assumed to be always present in the
// coroutines scheduler.
context = llvm.Undef(b.i8ptrType)
}
case *ssa.MakeClosure:
// A goroutine call on a func value, but the callee is trivial to find. For
// example: immediately applied functions.
@@ -90,31 +95,50 @@ func (b *builder) createGo(instr *ssa.Go) {
// * The function pointer (for tasks).
var context llvm.Value
funcPtr, context = b.decodeFuncValue(b.getValue(instr.Call.Value), instr.Call.Value.Type().Underlying().(*types.Signature))
params = append(params, context, funcPtr)
params = append(params, context) // context parameter
hasContext = true
switch b.Scheduler {
case "none", "coroutines":
// There are no additional parameters needed for the goroutine start operation.
case "tasks", "asyncify":
// Add the function pointer as a parameter to start the goroutine.
params = append(params, funcPtr)
default:
panic("unknown scheduler type")
}
prefix = b.fn.RelString(nil)
}
paramBundle := b.emitPointerPack(params)
var stackSize llvm.Value
callee := b.createGoroutineStartWrapper(funcPtr, prefix, hasContext, instr.Pos())
if b.AutomaticStackSize {
// The stack size is not known until after linking. Call a dummy
// function that will be replaced with a load from a special ELF
// section that contains the stack size (and is modified after
// linking).
stackSizeFn := b.getFunction(b.program.ImportedPackage("internal/task").Members["getGoroutineStackSize"].(*ssa.Function))
stackSize = b.createCall(stackSizeFn, []llvm.Value{callee, llvm.Undef(b.i8ptrType)}, "stacksize")
} else {
// The stack size is fixed at compile time. By emitting it here as a
// constant, it can be optimized.
if (b.Scheduler == "tasks" || b.Scheduler == "asyncify") && b.DefaultStackSize == 0 {
b.addError(instr.Pos(), "default stack size for goroutines is not set")
var callee, stackSize llvm.Value
switch b.Scheduler {
case "none", "tasks", "asyncify":
callee = b.createGoroutineStartWrapper(funcPtr, prefix, hasContext, instr.Pos())
if b.AutomaticStackSize {
// The stack size is not known until after linking. Call a dummy
// function that will be replaced with a load from a special ELF
// section that contains the stack size (and is modified after
// linking).
stackSizeFn := b.getFunction(b.program.ImportedPackage("internal/task").Members["getGoroutineStackSize"].(*ssa.Function))
stackSize = b.createCall(stackSizeFn, []llvm.Value{callee, llvm.Undef(b.i8ptrType), llvm.Undef(b.i8ptrType)}, "stacksize")
} else {
// The stack size is fixed at compile time. By emitting it here as a
// constant, it can be optimized.
if (b.Scheduler == "tasks" || b.Scheduler == "asyncify") && b.DefaultStackSize == 0 {
b.addError(instr.Pos(), "default stack size for goroutines is not set")
}
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
}
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
case "coroutines":
callee = b.CreatePtrToInt(funcPtr, b.uintptrType, "")
// There is no goroutine stack size: coroutines are used instead of
// stacks.
stackSize = llvm.Undef(b.uintptrType)
default:
panic("unreachable")
}
start := b.getFunction(b.program.ImportedPackage("internal/task").Members["start"].(*ssa.Function))
b.createCall(start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.i8ptrType)}, "")
b.createCall(start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.i8ptrType), llvm.ConstPointerNull(b.i8ptrType)}, "")
}
// createGoroutineStartWrapper creates a wrapper for the task-based
@@ -193,6 +217,7 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
// Create the list of params for the call.
paramTypes := fn.Type().ElementType().ParamTypes()
paramTypes = paramTypes[:len(paramTypes)-1] // strip parentHandle parameter
if !hasContext {
paramTypes = paramTypes[:len(paramTypes)-1] // strip context parameter
}
@@ -200,13 +225,14 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
if !hasContext {
params = append(params, llvm.Undef(c.i8ptrType)) // add dummy context parameter
}
params = append(params, llvm.Undef(c.i8ptrType)) // add dummy parentHandle parameter
// Create the call.
builder.CreateCall(fn, params, "")
if c.Scheduler == "asyncify" {
builder.CreateCall(deadlock, []llvm.Value{
llvm.Undef(c.i8ptrType),
llvm.Undef(c.i8ptrType), llvm.Undef(c.i8ptrType),
}, "")
}
@@ -262,19 +288,25 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
// Get the list of parameters, with the extra parameters at the end.
paramTypes := fn.Type().ElementType().ParamTypes()
paramTypes = append(paramTypes, fn.Type()) // the last element is the function pointer
paramTypes[len(paramTypes)-1] = fn.Type() // the last element is the function pointer
params := llvmutil.EmitPointerUnpack(builder, c.mod, wrapper.Param(0), paramTypes)
// Get the function pointer.
fnPtr := params[len(params)-1]
params = params[:len(params)-1]
// The last parameter in the packed object has somewhat of a dual role.
// Inside the parameter bundle it's the function pointer, stored right
// after the context pointer. But in the IR call instruction, it's the
// parentHandle function that's always undef outside of the coroutines
// scheduler. Thus, make the parameter undef here.
params[len(params)-1] = llvm.Undef(c.i8ptrType)
// Create the call.
builder.CreateCall(fnPtr, params, "")
if c.Scheduler == "asyncify" {
builder.CreateCall(deadlock, []llvm.Value{
llvm.Undef(c.i8ptrType),
llvm.Undef(c.i8ptrType), llvm.Undef(c.i8ptrType),
}, "")
}
}
+8 -8
View File
@@ -24,7 +24,7 @@ func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
// Magic function: insert inline assembly instead of calling it.
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{}, false)
asm := constant.StringVal(args[0].(*ssa.Const).Value)
target := llvm.InlineAsm(fnType, asm, "", true, false, 0, false)
target := llvm.InlineAsm(fnType, asm, "", true, false, 0)
return b.CreateCall(target, nil, ""), nil
}
@@ -116,7 +116,7 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
outputType = b.ctx.VoidType()
}
fnType := llvm.FunctionType(outputType, argTypes, false)
target := llvm.InlineAsm(fnType, asmString, strings.Join(constraints, ","), true, false, 0, false)
target := llvm.InlineAsm(fnType, asmString, strings.Join(constraints, ","), true, false, 0)
result := b.CreateCall(target, args, "")
if hasOutput {
return result, nil
@@ -159,7 +159,7 @@ func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
// marked as clobbered.
constraints += ",~{r1},~{r2},~{r3}"
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0, false)
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0)
return b.CreateCall(target, llvmArgs, ""), nil
}
@@ -197,7 +197,7 @@ func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
// marked as clobbered.
constraints += ",~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7}"
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0, false)
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0)
return b.CreateCall(target, llvmArgs, ""), nil
}
@@ -222,24 +222,24 @@ func (b *builder) emitCSROperation(call *ssa.CallCommon) (llvm.Value, error) {
// marked as such.
fnType := llvm.FunctionType(b.uintptrType, nil, false)
asm := fmt.Sprintf("csrr $0, %d", csr)
target := llvm.InlineAsm(fnType, asm, "=r", true, false, 0, false)
target := llvm.InlineAsm(fnType, asm, "=r", true, false, 0)
return b.CreateCall(target, nil, ""), nil
case "Set":
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.uintptrType}, false)
asm := fmt.Sprintf("csrw %d, $0", csr)
target := llvm.InlineAsm(fnType, asm, "r", true, false, 0, false)
target := llvm.InlineAsm(fnType, asm, "r", true, false, 0)
return b.CreateCall(target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
case "SetBits":
// Note: it may be possible to optimize this to csrrsi in many cases.
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType}, false)
asm := fmt.Sprintf("csrrs $0, %d, $1", csr)
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0, false)
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0)
return b.CreateCall(target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
case "ClearBits":
// Note: it may be possible to optimize this to csrrci in many cases.
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType}, false)
asm := fmt.Sprintf("csrrc $0, %d, $1", csr)
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0, false)
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0)
return b.CreateCall(target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
default:
return llvm.Value{}, b.makeError(call.Pos(), "unknown CSR operation: "+name)
+3 -10
View File
@@ -31,15 +31,6 @@ func (b *builder) createMakeInterface(val llvm.Value, typ types.Type, pos token.
return itf
}
// extractValueFromInterface extract the value from an interface value
// (runtime._interface) under the assumption that it is of the type given in
// llvmType. The behavior is undefied if the interface is nil or llvmType
// doesn't match the underlying type of the interface.
func (b *builder) extractValueFromInterface(itf llvm.Value, llvmType llvm.Type) llvm.Value {
valuePtr := b.CreateExtractValue(itf, 1, "typeassert.value.ptr")
return b.emitPointerUnpack(valuePtr, []llvm.Type{llvmType})[0]
}
// getTypeCode returns a reference to a type code.
// It returns a pointer to an external global which should be replaced with the
// real type in the interface lowering pass.
@@ -425,7 +416,8 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
} else {
// Type assert on concrete type. Extract the underlying type from
// the interface (but only after checking it matches).
valueOk = b.extractValueFromInterface(itf, assertedType)
valuePtr := b.CreateExtractValue(itf, 1, "typeassert.value.ptr")
valueOk = b.emitPointerUnpack(valuePtr, []llvm.Type{assertedType})[0]
}
b.CreateBr(nextBlock)
@@ -530,6 +522,7 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFn llv
wrapFnType := llvm.FunctionType(fnType.ReturnType(), paramTypes, false)
wrapper = llvm.AddFunction(c.mod, wrapperName, wrapFnType)
c.addStandardAttributes(wrapper)
wrapper.LastParam().SetName("parentHandle")
wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
wrapper.SetUnnamedAddr(true)
+1 -1
View File
@@ -147,7 +147,7 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
// Create the global initializer.
bitmapBytes := make([]byte, int(objectSizeWords+7)/8)
bitmap.FillBytes(bitmapBytes)
copy(bitmapBytes, bitmap.Bytes())
var bitmapByteValues []llvm.Value
for _, b := range bitmapBytes {
bitmapByteValues = append(bitmapByteValues, llvm.ConstInt(c.ctx.Int8Type(), uint64(b), false))
+4 -2
View File
@@ -97,13 +97,15 @@ func EmitPointerPack(builder llvm.Builder, mod llvm.Module, prefix string, needs
packedHeapAlloc := builder.CreateCall(alloc, []llvm.Value{
sizeValue,
llvm.ConstNull(i8ptrType),
llvm.Undef(i8ptrType), // unused context parameter
llvm.Undef(i8ptrType), // unused context parameter
llvm.ConstPointerNull(i8ptrType), // coroutine handle
}, "")
if needsStackObjects {
trackPointer := mod.NamedFunction("runtime.trackPointer")
builder.CreateCall(trackPointer, []llvm.Value{
packedHeapAlloc,
llvm.Undef(i8ptrType), // unused context parameter
llvm.Undef(i8ptrType), // unused context parameter
llvm.ConstPointerNull(i8ptrType), // coroutine handle
}, "")
}
packedAlloc := builder.CreateBitCast(packedHeapAlloc, llvm.PointerType(packedType, 0), "")
-60
View File
@@ -167,66 +167,6 @@ func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos tok
}
}
// createMapIteratorNext lowers the *ssa.Next instruction for iterating over a
// map. It returns a tuple of {bool, key, value} with the result of the
// iteration.
func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llvm.Value) llvm.Value {
// Determine the type of the values to return from the *ssa.Next
// instruction. It is returned as {bool, keyType, valueType}.
keyType := rangeVal.Type().Underlying().(*types.Map).Key()
valueType := rangeVal.Type().Underlying().(*types.Map).Elem()
llvmKeyType := b.getLLVMType(keyType)
llvmValueType := b.getLLVMType(valueType)
// There is a special case in which keys are stored as an interface value
// instead of the value they normally are. This happens for non-trivially
// comparable types such as float32 or some structs.
isKeyStoredAsInterface := false
if t, ok := keyType.Underlying().(*types.Basic); ok && t.Info()&types.IsString != 0 {
// key is a string
} else if hashmapIsBinaryKey(keyType) {
// key can be compared with runtime.memequal
} else {
// The key is stored as an interface value, and may or may not be an
// interface type (for example, float32 keys are stored as an interface
// value).
if _, ok := keyType.Underlying().(*types.Interface); !ok {
isKeyStoredAsInterface = true
}
}
// Determine the type of the key as stored in the map.
llvmStoredKeyType := llvmKeyType
if isKeyStoredAsInterface {
llvmStoredKeyType = b.getLLVMRuntimeType("_interface")
}
// Extract the key and value from the map.
mapKeyAlloca, mapKeyPtr, mapKeySize := b.createTemporaryAlloca(llvmStoredKeyType, "range.key")
mapValueAlloca, mapValuePtr, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyPtr, mapValuePtr}, "range.next")
mapKey := b.CreateLoad(mapKeyAlloca, "")
mapValue := b.CreateLoad(mapValueAlloca, "")
if isKeyStoredAsInterface {
// The key is stored as an interface but it isn't of interface type.
// Extract the underlying value.
mapKey = b.extractValueFromInterface(mapKey, llvmKeyType)
}
// End the lifetimes of the allocas, because we're done with them.
b.emitLifetimeEnd(mapKeyPtr, mapKeySize)
b.emitLifetimeEnd(mapValuePtr, mapValueSize)
// Construct the *ssa.Next return value: {ok, mapKey, mapValue}
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
tuple = b.CreateInsertValue(tuple, ok, 0, "")
tuple = b.CreateInsertValue(tuple, mapKey, 1, "")
tuple = b.CreateInsertValue(tuple, mapValue, 2, "")
return tuple
}
// Returns true if this key type does not contain strings, interfaces etc., so
// can be compared with runtime.memequal.
func hashmapIsBinaryKey(keyType types.Type) bool {
+1
View File
@@ -84,6 +84,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
// closures and bound methods, but should be optimized away when not used.
if !info.exported {
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "context", flags: 0})
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "parentHandle", flags: 0})
}
var paramTypes []llvm.Type
+4 -4
View File
@@ -56,7 +56,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
}
constraints += ",~{rcx},~{r11}"
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel, false)
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel)
return b.CreateCall(target, args, ""), nil
case b.GOARCH == "386" && b.GOOS == "linux":
// Sources:
@@ -82,7 +82,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
argTypes = append(argTypes, llvmValue.Type())
}
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel, false)
target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel)
return b.CreateCall(target, args, ""), nil
case b.GOARCH == "arm" && b.GOOS == "linux":
// Implement the EABI system call convention for Linux.
@@ -114,7 +114,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
constraints += ",~{r" + strconv.Itoa(i) + "}"
}
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0, false)
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
return b.CreateCall(target, args, ""), nil
case b.GOARCH == "arm64" && b.GOOS == "linux":
// Source: syscall(2) man page.
@@ -146,7 +146,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
}
constraints += ",~{x16},~{x17}" // scratch registers
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0, false)
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
return b.CreateCall(target, args, ""), nil
default:
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
+28 -30
View File
@@ -1,43 +1,41 @@
; ModuleID = 'basic.go'
source_filename = "basic.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
%main.kv = type { float }
%main.kv.0 = type { i8 }
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.addInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
define hidden i32 @main.addInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = add i32 %x, %y
ret i32 %0
}
; Function Attrs: nounwind
define hidden i1 @main.equalInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
define hidden i1 @main.equalInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = icmp eq i32 %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i32 @main.divInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
define hidden i32 @main.divInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(i8* undef) #0
call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0
unreachable
divbyzero.next: ; preds = %entry
@@ -49,16 +47,16 @@ divbyzero.next: ; preds = %entry
ret i32 %5
}
declare void @runtime.divideByZeroPanic(i8*)
declare void @runtime.divideByZeroPanic(i8*, i8*)
; Function Attrs: nounwind
define hidden i32 @main.divUint(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
define hidden i32 @main.divUint(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(i8* undef) #0
call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0
unreachable
divbyzero.next: ; preds = %entry
@@ -67,13 +65,13 @@ divbyzero.next: ; preds = %entry
}
; Function Attrs: nounwind
define hidden i32 @main.remInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
define hidden i32 @main.remInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(i8* undef) #0
call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0
unreachable
divbyzero.next: ; preds = %entry
@@ -86,13 +84,13 @@ divbyzero.next: ; preds = %entry
}
; Function Attrs: nounwind
define hidden i32 @main.remUint(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
define hidden i32 @main.remUint(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(i8* undef) #0
call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0
unreachable
divbyzero.next: ; preds = %entry
@@ -101,61 +99,61 @@ divbyzero.next: ; preds = %entry
}
; Function Attrs: nounwind
define hidden i1 @main.floatEQ(float %x, float %y, i8* %context) unnamed_addr #0 {
define hidden i1 @main.floatEQ(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = fcmp oeq float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatNE(float %x, float %y, i8* %context) unnamed_addr #0 {
define hidden i1 @main.floatNE(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = fcmp une float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatLower(float %x, float %y, i8* %context) unnamed_addr #0 {
define hidden i1 @main.floatLower(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = fcmp olt float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatLowerEqual(float %x, float %y, i8* %context) unnamed_addr #0 {
define hidden i1 @main.floatLowerEqual(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = fcmp ole float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatGreater(float %x, float %y, i8* %context) unnamed_addr #0 {
define hidden i1 @main.floatGreater(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = fcmp ogt float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden i1 @main.floatGreaterEqual(float %x, float %y, i8* %context) unnamed_addr #0 {
define hidden i1 @main.floatGreaterEqual(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = fcmp oge float %x, %y
ret i1 %0
}
; Function Attrs: nounwind
define hidden float @main.complexReal(float %x.r, float %x.i, i8* %context) unnamed_addr #0 {
define hidden float @main.complexReal(float %x.r, float %x.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret float %x.r
}
; Function Attrs: nounwind
define hidden float @main.complexImag(float %x.r, float %x.i, i8* %context) unnamed_addr #0 {
define hidden float @main.complexImag(float %x.r, float %x.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret float %x.i
}
; Function Attrs: nounwind
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #0 {
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = fadd float %x.r, %y.r
%1 = fadd float %x.i, %y.i
@@ -165,7 +163,7 @@ entry:
}
; Function Attrs: nounwind
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #0 {
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = fsub float %x.r, %y.r
%1 = fsub float %x.i, %y.i
@@ -175,7 +173,7 @@ entry:
}
; Function Attrs: nounwind
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #0 {
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = fmul float %x.r, %y.r
%1 = fmul float %x.i, %y.i
@@ -189,14 +187,14 @@ entry:
}
; Function Attrs: nounwind
define hidden void @main.foo(%main.kv* dereferenceable_or_null(4) %a, i8* %context) unnamed_addr #0 {
define hidden void @main.foo(%main.kv* dereferenceable_or_null(4) %a, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @"main.foo$1"(%main.kv.0* null, i8* undef)
call void @"main.foo$1"(%main.kv.0* null, i8* undef, i8* undef)
ret void
}
; Function Attrs: nounwind
define hidden void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #0 {
define hidden void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
+17 -23
View File
@@ -1,28 +1,25 @@
; ModuleID = 'channel.go'
source_filename = "channel.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
%"internal/task.gcData" = type { i8* }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
%"internal/task.state" = type { i32, i8*, %"internal/task.stackState", i1 }
%"internal/task.stackState" = type { i32, i32 }
%runtime.chanSelectState = type { %runtime.channel*, i8* }
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.chanIntSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
define hidden void @main.chanIntSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
%chan.value = alloca i32, align 4
@@ -31,7 +28,7 @@ entry:
store i32 3, i32* %chan.value, align 4
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
call void @runtime.chanSend(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
call void @runtime.chanSend(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef, i8* null) #0
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
ret void
@@ -40,13 +37,13 @@ entry:
; Function Attrs: argmemonly nofree nosync nounwind willreturn
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
declare void @runtime.chanSend(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*)
declare void @runtime.chanSend(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*, i8*)
; Function Attrs: argmemonly nofree nosync nounwind willreturn
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
; Function Attrs: nounwind
define hidden void @main.chanIntRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
define hidden void @main.chanIntRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
%chan.value = alloca i32, align 4
@@ -54,41 +51,38 @@ entry:
call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef, i8* null) #0
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
ret void
}
declare i1 @runtime.chanRecv(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*)
declare i1 @runtime.chanRecv(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.chanZeroSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
define hidden void @main.chanZeroSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%complit = alloca {}, align 8
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
%0 = bitcast {}* %complit to i8*
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
call void @runtime.chanSend(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
call void @runtime.chanSend(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef, i8* null) #0
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
ret void
}
; Function Attrs: nounwind
define hidden void @main.chanZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
define hidden void @main.chanZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef, i8* null) #0
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
ret void
}
; Function Attrs: nounwind
define hidden void @main.selectZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch1, %runtime.channel* dereferenceable_or_null(32) %ch2, i8* %context) unnamed_addr #0 {
define hidden void @main.selectZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch1, %runtime.channel* dereferenceable_or_null(32) %ch2, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8
%select.send.value = alloca i32, align 4
@@ -105,7 +99,7 @@ entry:
%.repack4 = getelementptr inbounds [2 x %runtime.chanSelectState], [2 x %runtime.chanSelectState]* %select.states.alloca, i32 0, i32 1, i32 1
store i8* null, i8** %.repack4, align 4
%select.states = getelementptr inbounds [2 x %runtime.chanSelectState], [2 x %runtime.chanSelectState]* %select.states.alloca, i32 0, i32 0
%select.result = call { i32, i1 } @runtime.tryChanSelect(i8* undef, %runtime.chanSelectState* nonnull %select.states, i32 2, i32 2, i8* undef) #0
%select.result = call { i32, i1 } @runtime.tryChanSelect(i8* undef, %runtime.chanSelectState* nonnull %select.states, i32 2, i32 2, i8* undef, i8* null) #0
call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %select.states.alloca.bitcast)
%1 = extractvalue { i32, i1 } %select.result, 0
%2 = icmp eq i32 %1, 0
@@ -122,7 +116,7 @@ select.body: ; preds = %select.next
br label %select.done
}
declare { i32, i1 } @runtime.tryChanSelect(i8*, %runtime.chanSelectState*, i32, i32, i8*)
declare { i32, i1 } @runtime.tryChanSelect(i8*, %runtime.chanSelectState*, i32, i32, i8*, i8*)
attributes #0 = { nounwind }
attributes #1 = { argmemonly nofree nosync nounwind willreturn }
+11 -13
View File
@@ -1,20 +1,18 @@
; ModuleID = 'float.go'
source_filename = "float.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.f32tou32(float %v, i8* %context) unnamed_addr #0 {
define hidden i32 @main.f32tou32(float %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
@@ -26,25 +24,25 @@ entry:
}
; Function Attrs: nounwind
define hidden float @main.maxu32f(i8* %context) unnamed_addr #0 {
define hidden float @main.maxu32f(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret float 0x41F0000000000000
}
; Function Attrs: nounwind
define hidden i32 @main.maxu32tof32(i8* %context) unnamed_addr #0 {
define hidden i32 @main.maxu32tof32(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret i32 -1
}
; Function Attrs: nounwind
define hidden { i32, i32, i32, i32 } @main.inftoi32(i8* %context) unnamed_addr #0 {
define hidden { i32, i32, i32, i32 } @main.inftoi32(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 }
}
; Function Attrs: nounwind
define hidden i32 @main.u32tof32tou32(i32 %v, i8* %context) unnamed_addr #0 {
define hidden i32 @main.u32tof32tou32(i32 %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = uitofp i32 %v to float
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
@@ -54,7 +52,7 @@ entry:
}
; Function Attrs: nounwind
define hidden float @main.f32tou32tof32(float %v, i8* %context) unnamed_addr #0 {
define hidden float @main.f32tou32tof32(float %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
@@ -67,7 +65,7 @@ entry:
}
; Function Attrs: nounwind
define hidden i8 @main.f32tou8(float %v, i8* %context) unnamed_addr #0 {
define hidden i8 @main.f32tou8(float %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%positive = fcmp oge float %v, 0.000000e+00
%withinmax = fcmp ole float %v, 2.550000e+02
@@ -79,7 +77,7 @@ entry:
}
; Function Attrs: nounwind
define hidden i8 @main.f32toi8(float %v, i8* %context) unnamed_addr #0 {
define hidden i8 @main.f32toi8(float %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%abovemin = fcmp oge float %v, -1.280000e+02
%belowmax = fcmp ole float %v, 1.270000e+02
+53
View File
@@ -0,0 +1,53 @@
; ModuleID = 'func.go'
source_filename = "func.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
%runtime.funcValueWithSignature = type { i32, i8* }
@"reflect/types.funcid:func:{basic:int}{}" = external constant i8
@"main.someFunc$withSignature" = linkonce_odr constant %runtime.funcValueWithSignature { i32 ptrtoint (void (i32, i8*, i8*)* @main.someFunc to i32), i8* @"reflect/types.funcid:func:{basic:int}{}" }
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.foo(i8* %callback.context, i32 %callback.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i32 @runtime.getFuncPtr(i8* %callback.context, i32 %callback.funcptr, i8* nonnull @"reflect/types.funcid:func:{basic:int}{}", i8* undef, i8* null) #0
%1 = icmp eq i32 %0, 0
br i1 %1, label %fpcall.throw, label %fpcall.next
fpcall.throw: ; preds = %entry
call void @runtime.nilPanic(i8* undef, i8* null) #0
unreachable
fpcall.next: ; preds = %entry
%2 = inttoptr i32 %0 to void (i32, i8*, i8*)*
call void %2(i32 3, i8* %callback.context, i8* undef) #0
ret void
}
declare i32 @runtime.getFuncPtr(i8*, i32, i8* dereferenceable_or_null(1), i8*, i8*)
declare void @runtime.nilPanic(i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.bar(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @main.foo(i8* undef, i32 ptrtoint (%runtime.funcValueWithSignature* @"main.someFunc$withSignature" to i32), i8* undef, i8* undef)
ret void
}
; Function Attrs: nounwind
define hidden void @main.someFunc(i32 %arg0, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
attributes #0 = { nounwind }
-47
View File
@@ -1,47 +0,0 @@
; ModuleID = 'func.go'
source_filename = "func.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.foo(i8* %callback.context, void ()* %callback.funcptr, i8* %context) unnamed_addr #0 {
entry:
%0 = icmp eq void ()* %callback.funcptr, null
br i1 %0, label %fpcall.throw, label %fpcall.next
fpcall.throw: ; preds = %entry
call void @runtime.nilPanic(i8* undef) #0
unreachable
fpcall.next: ; preds = %entry
%1 = bitcast void ()* %callback.funcptr to void (i32, i8*)*
call void %1(i32 3, i8* %callback.context) #0
ret void
}
declare void @runtime.nilPanic(i8*)
; Function Attrs: nounwind
define hidden void @main.bar(i8* %context) unnamed_addr #0 {
entry:
call void @main.foo(i8* undef, void ()* bitcast (void (i32, i8*)* @main.someFunc to void ()*), i8* undef)
ret void
}
; Function Attrs: nounwind
define hidden void @main.someFunc(i32 %arg0, i8* %context) unnamed_addr #0 {
entry:
ret void
}
attributes #0 = { nounwind }
+5 -8
View File
@@ -20,10 +20,6 @@ var (
y [60]uintptr
z *byte
}
struct4 *struct {
x *byte
y [61]uintptr
}
slice1 []byte
slice2 []*int
@@ -54,13 +50,14 @@ func newStruct() {
y [60]uintptr
z *byte
})
struct4 = new(struct {
x *byte
y [61]uintptr
})
}
func newFuncValue() *func() {
// On some platforms that use runtime.funcValue ("switch" style) function
// values, a func value is allocated as having two pointer words while the
// struct looks like {unsafe.Pointer; uintptr}. This is so that the interp
// package won't get confused, see getPointerBitmap in compiler/llvm.go for
// details.
return new(func())
}
+24 -47
View File
@@ -1,6 +1,6 @@
; ModuleID = 'gc.go'
source_filename = "gc.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID*, i32 }
@@ -17,100 +17,79 @@ target triple = "wasm32-unknown-wasi"
@main.struct1 = hidden global {}* null, align 4
@main.struct2 = hidden global { i32, i32 }* null, align 4
@main.struct3 = hidden global { i8*, [60 x i32], i8* }* null, align 4
@main.struct4 = hidden global { i8*, [61 x i32] }* null, align 4
@main.slice1 = hidden global { i8*, i32, i32 } zeroinitializer, align 8
@main.slice2 = hidden global { i32**, i32, i32 } zeroinitializer, align 8
@main.slice3 = hidden global { { i8*, i32, i32 }*, i32, i32 } zeroinitializer, align 8
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c" \00\00\00\00\00\00\01" }
@"runtime/gc.layout:62-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\00\00\00\00\00\00\00\01" }
@"reflect/types.type:basic:complex128" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* null, i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:basic:complex128", i32 0 }
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:complex128", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null, i32 0 }
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.newScalar(i8* %context) unnamed_addr #0 {
define hidden void @main.newScalar(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%new = call i8* @runtime.alloc(i32 1, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
%new = call i8* @runtime.alloc(i32 1, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
store i8* %new, i8** @main.scalar1, align 4
%new1 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #0
%new1 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
store i8* %new1, i8** bitcast (i32** @main.scalar2 to i8**), align 4
%new2 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #0
%new2 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
store i8* %new2, i8** bitcast (i64** @main.scalar3 to i8**), align 4
%new3 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new3, i8* undef) #0
%new3 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
store i8* %new3, i8** bitcast (float** @main.scalar4 to i8**), align 4
ret void
}
; Function Attrs: nounwind
define hidden void @main.newArray(i8* %context) unnamed_addr #0 {
define hidden void @main.newArray(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%new = call i8* @runtime.alloc(i32 3, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
%new = call i8* @runtime.alloc(i32 3, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
store i8* %new, i8** bitcast ([3 x i8]** @main.array1 to i8**), align 4
%new1 = call i8* @runtime.alloc(i32 71, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #0
%new1 = call i8* @runtime.alloc(i32 71, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
store i8* %new1, i8** bitcast ([71 x i8]** @main.array2 to i8**), align 4
%new2 = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 67 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #0
%new2 = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 67 to i8*), i8* undef, i8* null) #0
store i8* %new2, i8** bitcast ([3 x i8*]** @main.array3 to i8**), align 4
ret void
}
; Function Attrs: nounwind
define hidden void @main.newStruct(i8* %context) unnamed_addr #0 {
define hidden void @main.newStruct(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%new = call i8* @runtime.alloc(i32 0, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
%new = call i8* @runtime.alloc(i32 0, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
store i8* %new, i8** bitcast ({}** @main.struct1 to i8**), align 4
%new1 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #0
%new1 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
store i8* %new1, i8** bitcast ({ i32, i32 }** @main.struct2 to i8**), align 4
%new2 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-2000000000000001" to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #0
%new2 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-2000000000000001" to i8*), i8* undef, i8* null) #0
store i8* %new2, i8** bitcast ({ i8*, [60 x i32], i8* }** @main.struct3 to i8**), align 4
%new3 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-0001" to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %new3, i8* undef) #0
store i8* %new3, i8** bitcast ({ i8*, [61 x i32] }** @main.struct4 to i8**), align 4
ret void
}
; Function Attrs: nounwind
define hidden { i8*, void ()* }* @main.newFuncValue(i8* %context) unnamed_addr #0 {
define hidden { i8*, void ()* }* @main.newFuncValue(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%new = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 197 to i8*), i8* undef) #0
%new = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 197 to i8*), i8* undef, i8* null) #0
%0 = bitcast i8* %new to { i8*, void ()* }*
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
ret { i8*, void ()* }* %0
}
; Function Attrs: nounwind
define hidden void @main.makeSlice(i8* %context) unnamed_addr #0 {
define hidden void @main.makeSlice(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%makeslice = call i8* @runtime.alloc(i32 5, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #0
%makeslice = call i8* @runtime.alloc(i32 5, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
store i8* %makeslice, i8** getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 0), align 8
store i32 5, i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 1), align 4
store i32 5, i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 2), align 8
%makeslice1 = call i8* @runtime.alloc(i32 20, i8* nonnull inttoptr (i32 67 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %makeslice1, i8* undef) #0
%makeslice1 = call i8* @runtime.alloc(i32 20, i8* nonnull inttoptr (i32 67 to i8*), i8* undef, i8* null) #0
store i8* %makeslice1, i8** bitcast ({ i32**, i32, i32 }* @main.slice2 to i8**), align 8
store i32 5, i32* getelementptr inbounds ({ i32**, i32, i32 }, { i32**, i32, i32 }* @main.slice2, i32 0, i32 1), align 4
store i32 5, i32* getelementptr inbounds ({ i32**, i32, i32 }, { i32**, i32, i32 }* @main.slice2, i32 0, i32 2), align 8
%makeslice3 = call i8* @runtime.alloc(i32 60, i8* nonnull inttoptr (i32 71 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %makeslice3, i8* undef) #0
%makeslice3 = call i8* @runtime.alloc(i32 60, i8* nonnull inttoptr (i32 71 to i8*), i8* undef, i8* null) #0
store i8* %makeslice3, i8** bitcast ({ { i8*, i32, i32 }*, i32, i32 }* @main.slice3 to i8**), align 8
store i32 5, i32* getelementptr inbounds ({ { i8*, i32, i32 }*, i32, i32 }, { { i8*, i32, i32 }*, i32, i32 }* @main.slice3, i32 0, i32 1), align 4
store i32 5, i32* getelementptr inbounds ({ { i8*, i32, i32 }*, i32, i32 }, { { i8*, i32, i32 }*, i32, i32 }* @main.slice3, i32 0, i32 2), align 8
@@ -118,17 +97,15 @@ entry:
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, i8* %context) unnamed_addr #0 {
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef, i8* null) #0
%.repack = bitcast i8* %0 to double*
store double %v.r, double* %.repack, align 8
%.repack1 = getelementptr inbounds i8, i8* %0, i32 8
%1 = bitcast i8* %.repack1 to double*
store double %v.i, double* %1, align 8
%2 = insertvalue %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:basic:complex128" to i32), i8* undef }, i8* %0, 1
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
ret %runtime._interface %2
}
+19 -31
View File
@@ -1,43 +1,39 @@
; ModuleID = 'go1.17.go'
source_filename = "go1.17.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i8* @main.Add32(i8* %p, i32 %len, i8* %context) unnamed_addr #0 {
define hidden i8* @main.Add32(i8* %p, i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = getelementptr i8, i8* %p, i32 %len
call void @runtime.trackPointer(i8* %0, i8* undef) #0
ret i8* %0
}
; Function Attrs: nounwind
define hidden i8* @main.Add64(i8* %p, i64 %len, i8* %context) unnamed_addr #0 {
define hidden i8* @main.Add64(i8* %p, i64 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = trunc i64 %len to i32
%1 = getelementptr i8, i8* %p, i32 %0
call void @runtime.trackPointer(i8* %1, i8* undef) #0
ret i8* %1
}
; Function Attrs: nounwind
define hidden [4 x i32]* @main.SliceToArray(i32* %s.data, i32 %s.len, i32 %s.cap, i8* %context) unnamed_addr #0 {
define hidden [4 x i32]* @main.SliceToArray(i32* %s.data, i32 %s.len, i32 %s.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = icmp ult i32 %s.len, 4
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
slicetoarray.throw: ; preds = %entry
call void @runtime.sliceToArrayPointerPanic(i8* undef) #0
call void @runtime.sliceToArrayPointerPanic(i8* undef, i8* null) #0
unreachable
slicetoarray.next: ; preds = %entry
@@ -45,13 +41,12 @@ slicetoarray.next: ; preds = %entry
ret [4 x i32]* %1
}
declare void @runtime.sliceToArrayPointerPanic(i8*)
declare void @runtime.sliceToArrayPointerPanic(i8*, i8*)
; Function Attrs: nounwind
define hidden [4 x i32]* @main.SliceToArrayConst(i8* %context) unnamed_addr #0 {
define hidden [4 x i32]* @main.SliceToArrayConst(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%makeslice = call i8* @runtime.alloc(i32 24, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #0
%makeslice = call i8* @runtime.alloc(i32 24, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
slicetoarray.throw: ; preds = %entry
@@ -63,7 +58,7 @@ slicetoarray.next: ; preds = %entry
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.SliceInt(i32* dereferenceable_or_null(4) %ptr, i32 %len, i8* %context) unnamed_addr #0 {
define hidden { i32*, i32, i32 } @main.SliceInt(i32* dereferenceable_or_null(4) %ptr, i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = icmp ugt i32 %len, 1073741823
%1 = icmp eq i32* %ptr, null
@@ -73,22 +68,20 @@ entry:
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #0
call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0
unreachable
unsafe.Slice.next: ; preds = %entry
%5 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
%6 = insertvalue { i32*, i32, i32 } %5, i32 %len, 1
%7 = insertvalue { i32*, i32, i32 } %6, i32 %len, 2
%8 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %8, i8* undef) #0
ret { i32*, i32, i32 } %7
}
declare void @runtime.unsafeSlicePanic(i8*)
declare void @runtime.unsafeSlicePanic(i8*, i8*)
; Function Attrs: nounwind
define hidden { i8*, i32, i32 } @main.SliceUint16(i8* dereferenceable_or_null(1) %ptr, i16 %len, i8* %context) unnamed_addr #0 {
define hidden { i8*, i32, i32 } @main.SliceUint16(i8* dereferenceable_or_null(1) %ptr, i16 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = icmp eq i8* %ptr, null
%1 = icmp ne i16 %len, 0
@@ -96,7 +89,7 @@ entry:
br i1 %2, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #0
call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0
unreachable
unsafe.Slice.next: ; preds = %entry
@@ -104,12 +97,11 @@ unsafe.Slice.next: ; preds = %entry
%4 = insertvalue { i8*, i32, i32 } undef, i8* %ptr, 0
%5 = insertvalue { i8*, i32, i32 } %4, i32 %3, 1
%6 = insertvalue { i8*, i32, i32 } %5, i32 %3, 2
call void @runtime.trackPointer(i8* %ptr, i8* undef) #0
ret { i8*, i32, i32 } %6
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.SliceUint64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #0 {
define hidden { i32*, i32, i32 } @main.SliceUint64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = icmp ugt i64 %len, 1073741823
%1 = icmp eq i32* %ptr, null
@@ -119,7 +111,7 @@ entry:
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #0
call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0
unreachable
unsafe.Slice.next: ; preds = %entry
@@ -127,13 +119,11 @@ unsafe.Slice.next: ; preds = %entry
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
%7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2
%9 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %9, i8* undef) #0
ret { i32*, i32, i32 } %8
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.SliceInt64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #0 {
define hidden { i32*, i32, i32 } @main.SliceInt64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = icmp ugt i64 %len, 1073741823
%1 = icmp eq i32* %ptr, null
@@ -143,7 +133,7 @@ entry:
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #0
call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0
unreachable
unsafe.Slice.next: ; preds = %entry
@@ -151,8 +141,6 @@ unsafe.Slice.next: ; preds = %entry
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
%7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1
%8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2
%9 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %9, i8* undef) #0
ret { i32*, i32, i32 } %8
}
+44 -45
View File
@@ -5,53 +5,52 @@ target triple = "thumbv7m-unknown-unknown-eabi"
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
%"internal/task.gcData" = type {}
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
%"internal/task.state" = type { i32, i32* }
%runtime.chanSelectState = type { %runtime.channel*, i8* }
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(i8* %context) unnamed_addr #0 {
define hidden void @main.regularFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef) #0
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* undef, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef, i8* null) #0
ret void
}
declare void @main.regularFunction(i32, i8*)
declare void @main.regularFunction(i32, i8*, i8*)
; Function Attrs: nounwind
define linkonce_odr void @"main.regularFunction$gowrapper"(i8* %0) unnamed_addr #1 {
entry:
%unpack.int = ptrtoint i8* %0 to i32
call void @main.regularFunction(i32 %unpack.int, i8* undef) #0
call void @main.regularFunction(i32 %unpack.int, i8* undef, i8* undef) #0
ret void
}
declare i32 @"internal/task.getGoroutineStackSize"(i32, i8*)
declare i32 @"internal/task.getGoroutineStackSize"(i32, i8*, i8*)
declare void @"internal/task.start"(i32, i8*, i32, i8*)
declare void @"internal/task.start"(i32, i8*, i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(i8* %context) unnamed_addr #0 {
define hidden void @main.inlineFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef) #0
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* undef, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef, i8* null) #0
ret void
}
; Function Attrs: nounwind
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
@@ -60,31 +59,31 @@ entry:
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #2 {
entry:
%unpack.int = ptrtoint i8* %0 to i32
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef)
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef, i8* undef)
ret void
}
; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(i8* %context) unnamed_addr #0 {
define hidden void @main.closureFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%0 = bitcast i8* %n to i32*
store i32 3, i32* %0, align 4
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef) #0
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef, i8* null) #0
%2 = bitcast i8* %1 to i32*
store i32 5, i32* %2, align 4
%3 = getelementptr inbounds i8, i8* %1, i32 4
%4 = bitcast i8* %3 to i8**
store i8* %n, i8** %4, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 %stacksize, i8* undef) #0
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* undef, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 %stacksize, i8* undef, i8* null) #0
%5 = load i32, i32* %0, align 4
call void @runtime.printint32(i32 %5, i8* undef) #0
call void @runtime.printint32(i32 %5, i8* undef, i8* null) #0
ret void
}
; Function Attrs: nounwind
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%unpack.ptr = bitcast i8* %context to i32*
store i32 7, i32* %unpack.ptr, align 4
@@ -99,16 +98,16 @@ entry:
%3 = getelementptr inbounds i8, i8* %0, i32 4
%4 = bitcast i8* %3 to i8**
%5 = load i8*, i8** %4, align 4
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5)
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5, i8* undef)
ret void
}
declare void @runtime.printint32(i32, i8*)
declare void @runtime.printint32(i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context) unnamed_addr #0 {
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef) #0
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef, i8* null) #0
%1 = bitcast i8* %0 to i32*
store i32 5, i32* %1, align 4
%2 = getelementptr inbounds i8, i8* %0, i32 4
@@ -117,8 +116,8 @@ entry:
%4 = getelementptr inbounds i8, i8* %0, i32 8
%5 = bitcast i8* %4 to void ()**
store void ()* %fn.funcptr, void ()** %5, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 %stacksize, i8* undef) #0
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* undef, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 %stacksize, i8* undef, i8* null) #0
ret void
}
@@ -131,40 +130,40 @@ entry:
%4 = bitcast i8* %3 to i8**
%5 = load i8*, i8** %4, align 4
%6 = getelementptr inbounds i8, i8* %0, i32 8
%7 = bitcast i8* %6 to void (i32, i8*)**
%8 = load void (i32, i8*)*, void (i32, i8*)** %7, align 4
call void %8(i32 %2, i8* %5) #0
%7 = bitcast i8* %6 to void (i32, i8*, i8*)**
%8 = load void (i32, i8*, i8*)*, void (i32, i8*, i8*)** %7, align 4
call void %8(i32 %2, i8* %5, i8* undef) #0
ret void
}
; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(i8* %context) unnamed_addr #0 {
define hidden void @main.recoverBuiltinGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #0 {
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef) #0
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef, i8* null) #0
ret void
}
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*)
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef) #0
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef, i8* null) #0
ret void
}
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*)
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #0
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef, i8* null) #0
%1 = bitcast i8* %0 to i8**
store i8* %itf.value, i8** %1, align 4
%2 = getelementptr inbounds i8, i8* %0, i32 4
@@ -176,12 +175,12 @@ entry:
%4 = getelementptr inbounds i8, i8* %0, i32 12
%5 = bitcast i8* %4 to i32*
store i32 %itf.typecode, i32* %5, align 4
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 %stacksize, i8* undef) #0
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* undef, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 %stacksize, i8* undef, i8* null) #0
ret void
}
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*) #5
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*, i8*) #5
; Function Attrs: nounwind
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(i8* %0) unnamed_addr #6 {
@@ -197,7 +196,7 @@ entry:
%9 = getelementptr inbounds i8, i8* %0, i32 12
%10 = bitcast i8* %9 to i32*
%11 = load i32, i32* %10, align 4
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef) #0
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef, i8* undef) #0
ret void
}
+45 -54
View File
@@ -1,59 +1,56 @@
; ModuleID = 'goroutine.go'
source_filename = "goroutine.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
%"internal/task.gcData" = type { i8* }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
%"internal/task.state" = type { i32, i8*, %"internal/task.stackState", i1 }
%"internal/task.stackState" = type { i32, i32 }
%runtime.chanSelectState = type { %runtime.channel*, i8* }
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(i8* %context) unnamed_addr #0 {
define hidden void @main.regularFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 16384, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 8192, i8* undef, i8* null) #0
ret void
}
declare void @main.regularFunction(i32, i8*)
declare void @main.regularFunction(i32, i8*, i8*)
declare void @runtime.deadlock(i8*)
declare void @runtime.deadlock(i8*, i8*)
; Function Attrs: nounwind
define linkonce_odr void @"main.regularFunction$gowrapper"(i8* %0) unnamed_addr #1 {
entry:
%unpack.int = ptrtoint i8* %0 to i32
call void @main.regularFunction(i32 %unpack.int, i8* undef) #0
call void @runtime.deadlock(i8* undef) #0
call void @main.regularFunction(i32 %unpack.int, i8* undef, i8* undef) #0
call void @runtime.deadlock(i8* undef, i8* undef) #0
unreachable
}
declare void @"internal/task.start"(i32, i8*, i32, i8*)
declare void @"internal/task.start"(i32, i8*, i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(i8* %context) unnamed_addr #0 {
define hidden void @main.inlineFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 16384, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 8192, i8* undef, i8* null) #0
ret void
}
; Function Attrs: nounwind
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
@@ -62,35 +59,31 @@ entry:
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #2 {
entry:
%unpack.int = ptrtoint i8* %0 to i32
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef)
call void @runtime.deadlock(i8* undef) #0
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef, i8* undef)
call void @runtime.deadlock(i8* undef, i8* undef) #0
unreachable
}
; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(i8* %context) unnamed_addr #0 {
define hidden void @main.closureFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%0 = bitcast i8* %n to i32*
call void @runtime.trackPointer(i8* nonnull %n, i8* undef) #0
store i32 3, i32* %0, align 4
call void @runtime.trackPointer(i8* nonnull %n, i8* undef) #0
call void @runtime.trackPointer(i8* bitcast (void (i32, i8*)* @"main.closureFunctionGoroutine$1" to i8*), i8* undef) #0
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #0
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef, i8* null) #0
%2 = bitcast i8* %1 to i32*
store i32 5, i32* %2, align 4
%3 = getelementptr inbounds i8, i8* %1, i32 4
%4 = bitcast i8* %3 to i8**
store i8* %n, i8** %4, align 4
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 16384, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 8192, i8* undef, i8* null) #0
%5 = load i32, i32* %0, align 4
call void @runtime.printint32(i32 %5, i8* undef) #0
call void @runtime.printint32(i32 %5, i8* undef, i8* null) #0
ret void
}
; Function Attrs: nounwind
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%unpack.ptr = bitcast i8* %context to i32*
store i32 7, i32* %unpack.ptr, align 4
@@ -105,18 +98,17 @@ entry:
%3 = getelementptr inbounds i8, i8* %0, i32 4
%4 = bitcast i8* %3 to i8**
%5 = load i8*, i8** %4, align 4
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5)
call void @runtime.deadlock(i8* undef) #0
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5, i8* undef)
call void @runtime.deadlock(i8* undef, i8* undef) #0
unreachable
}
declare void @runtime.printint32(i32, i8*)
declare void @runtime.printint32(i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context) unnamed_addr #0 {
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef, i8* null) #0
%1 = bitcast i8* %0 to i32*
store i32 5, i32* %1, align 4
%2 = getelementptr inbounds i8, i8* %0, i32 4
@@ -125,7 +117,7 @@ entry:
%4 = getelementptr inbounds i8, i8* %0, i32 8
%5 = bitcast i8* %4 to void ()**
store void ()* %fn.funcptr, void ()** %5, align 4
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 16384, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 8192, i8* undef, i8* null) #0
ret void
}
@@ -138,42 +130,41 @@ entry:
%4 = bitcast i8* %3 to i8**
%5 = load i8*, i8** %4, align 4
%6 = getelementptr inbounds i8, i8* %0, i32 8
%7 = bitcast i8* %6 to void (i32, i8*)**
%8 = load void (i32, i8*)*, void (i32, i8*)** %7, align 4
call void %8(i32 %2, i8* %5) #0
call void @runtime.deadlock(i8* undef) #0
%7 = bitcast i8* %6 to void (i32, i8*, i8*)**
%8 = load void (i32, i8*, i8*)*, void (i32, i8*, i8*)** %7, align 4
call void %8(i32 %2, i8* %5, i8* undef) #0
call void @runtime.deadlock(i8* undef, i8* undef) #0
unreachable
}
; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(i8* %context) unnamed_addr #0 {
define hidden void @main.recoverBuiltinGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #0 {
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef) #0
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef, i8* null) #0
ret void
}
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*)
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef) #0
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef, i8* null) #0
ret void
}
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*)
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef, i8* null) #0
%1 = bitcast i8* %0 to i8**
store i8* %itf.value, i8** %1, align 4
%2 = getelementptr inbounds i8, i8* %0, i32 4
@@ -185,11 +176,11 @@ entry:
%4 = getelementptr inbounds i8, i8* %0, i32 12
%5 = bitcast i8* %4 to i32*
store i32 %itf.typecode, i32* %5, align 4
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 16384, i8* undef) #0
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 8192, i8* undef, i8* null) #0
ret void
}
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*) #5
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*, i8*) #5
; Function Attrs: nounwind
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(i8* %0) unnamed_addr #6 {
@@ -205,8 +196,8 @@ entry:
%9 = getelementptr inbounds i8, i8* %0, i32 12
%10 = bitcast i8* %9 to i32*
%11 = load i32, i32* %10, align 4
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef) #0
call void @runtime.deadlock(i8* undef) #0
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef, i8* undef) #0
call void @runtime.deadlock(i8* undef, i8* undef) #0
unreachable
}
+141
View File
@@ -0,0 +1,141 @@
; ModuleID = 'goroutine.go'
source_filename = "goroutine.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
%runtime.funcValueWithSignature = type { i32, i8* }
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
%"internal/task.state" = type { i8* }
%runtime.chanSelectState = type { %runtime.channel*, i8* }
@"main$pack" = internal unnamed_addr constant { i32, i8* } { i32 5, i8* undef }
@"main$pack.1" = internal unnamed_addr constant { i32, i8* } { i32 5, i8* undef }
@"reflect/types.funcid:func:{basic:int}{}" = external constant i8
@"main.closureFunctionGoroutine$1$withSignature" = linkonce_odr constant %runtime.funcValueWithSignature { i32 ptrtoint (void (i32, i8*, i8*)* @"main.closureFunctionGoroutine$1" to i32), i8* @"reflect/types.funcid:func:{basic:int}{}" }
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @main.regularFunction to i32), i8* bitcast ({ i32, i8* }* @"main$pack" to i8*), i32 undef, i8* undef, i8* null) #0
ret void
}
declare void @main.regularFunction(i32, i8*, i8*)
declare void @"internal/task.start"(i32, i8*, i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @"main.inlineFunctionGoroutine$1" to i32), i8* bitcast ({ i32, i8* }* @"main$pack.1" to i8*), i32 undef, i8* undef, i8* null) #0
ret void
}
; Function Attrs: nounwind
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.closureFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%0 = bitcast i8* %n to i32*
store i32 3, i32* %0, align 4
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef, i8* null) #0
%2 = bitcast i8* %1 to i32*
store i32 5, i32* %2, align 4
%3 = getelementptr inbounds i8, i8* %1, i32 4
%4 = bitcast i8* %3 to i8**
store i8* %n, i8** %4, align 4
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @"main.closureFunctionGoroutine$1" to i32), i8* nonnull %1, i32 undef, i8* undef, i8* null) #0
%5 = load i32, i32* %0, align 4
call void @runtime.printint32(i32 %5, i8* undef, i8* null) #0
ret void
}
; Function Attrs: nounwind
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%unpack.ptr = bitcast i8* %context to i32*
store i32 7, i32* %unpack.ptr, align 4
ret void
}
declare void @runtime.printint32(i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.funcGoroutine(i8* %fn.context, i32 %fn.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i32 @runtime.getFuncPtr(i8* %fn.context, i32 %fn.funcptr, i8* nonnull @"reflect/types.funcid:func:{basic:int}{}", i8* undef, i8* null) #0
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef, i8* null) #0
%2 = bitcast i8* %1 to i32*
store i32 5, i32* %2, align 4
%3 = getelementptr inbounds i8, i8* %1, i32 4
%4 = bitcast i8* %3 to i8**
store i8* %fn.context, i8** %4, align 4
call void @"internal/task.start"(i32 %0, i8* nonnull %1, i32 undef, i8* undef, i8* null) #0
ret void
}
declare i32 @runtime.getFuncPtr(i8*, i32, i8* dereferenceable_or_null(1), i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.recoverBuiltinGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef, i8* null) #0
ret void
}
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef, i8* null) #0
ret void
}
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef, i8* null) #0
%1 = bitcast i8* %0 to i8**
store i8* %itf.value, i8** %1, align 4
%2 = getelementptr inbounds i8, i8* %0, i32 4
%.repack = bitcast i8* %2 to i8**
store i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"main$string", i32 0, i32 0), i8** %.repack, align 4
%.repack1 = getelementptr inbounds i8, i8* %0, i32 8
%3 = bitcast i8* %.repack1 to i32*
store i32 4, i32* %3, align 4
%4 = getelementptr inbounds i8, i8* %0, i32 12
%5 = bitcast i8* %4 to i32*
store i32 %itf.typecode, i32* %5, align 4
call void @"internal/task.start"(i32 ptrtoint (void (i8*, i8*, i32, i32, i8*, i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke" to i32), i8* nonnull %0, i32 undef, i8* undef, i8* null) #0
ret void
}
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*, i8*) #1
attributes #0 = { nounwind }
attributes #1 = { "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
+18 -26
View File
@@ -1,6 +1,6 @@
; ModuleID = 'interface.go'
source_filename = "interface.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID*, i32 }
@@ -22,52 +22,46 @@ target triple = "wasm32-unknown-wasi"
@"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"reflect/methods.String() string"]
@"reflect/types.typeid:basic:int" = external constant i8
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.simpleType(i8* %context) unnamed_addr #0 {
define hidden %runtime._interface @main.simpleType(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* null, i8* undef) #0
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:basic:int" to i32), i8* null }
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.pointerType(i8* %context) unnamed_addr #0 {
define hidden %runtime._interface @main.pointerType(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* null, i8* undef) #0
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:basic:int" to i32), i8* null }
}
; Function Attrs: nounwind
define hidden %runtime._interface @main.interfaceType(i8* %context) unnamed_addr #0 {
define hidden %runtime._interface @main.interfaceType(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* null, i8* undef) #0
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:named:error" to i32), i8* null }
}
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i32) #1
; Function Attrs: nounwind
define hidden %runtime._interface @main.anonymousInterfaceType(i8* %context) unnamed_addr #0 {
define hidden %runtime._interface @main.anonymousInterfaceType(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* null, i8* undef) #0
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" to i32), i8* null }
}
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32) #2
; Function Attrs: nounwind
define hidden i1 @main.isInt(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
define hidden i1 @main.isInt(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef) #0
%typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef, i8* null) #0
br i1 %typecode, label %typeassert.ok, label %typeassert.next
typeassert.ok: ; preds = %entry
@@ -77,10 +71,10 @@ typeassert.next: ; preds = %typeassert.ok, %ent
ret i1 %typecode
}
declare i1 @runtime.typeAssert(i32, i8* dereferenceable_or_null(1), i8*)
declare i1 @runtime.typeAssert(i32, i8* dereferenceable_or_null(1), i8*, i8*)
; Function Attrs: nounwind
define hidden i1 @main.isError(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
define hidden i1 @main.isError(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0
br i1 %0, label %typeassert.ok, label %typeassert.next
@@ -93,7 +87,7 @@ typeassert.next: ; preds = %typeassert.ok, %ent
}
; Function Attrs: nounwind
define hidden i1 @main.isStringer(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
define hidden i1 @main.isStringer(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0
br i1 %0, label %typeassert.ok, label %typeassert.next
@@ -106,24 +100,22 @@ typeassert.next: ; preds = %typeassert.ok, %ent
}
; Function Attrs: nounwind
define hidden i8 @main.callFooMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
define hidden i8 @main.callFooMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8* %itf.value, i32 3, i32 %itf.typecode, i8* undef) #0
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8* %itf.value, i32 3, i32 %itf.typecode, i8* undef, i8* undef) #0
ret i8 %0
}
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8*, i32, i32, i8*) #3
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8*, i32, i32, i8*, i8*) #3
; Function Attrs: nounwind
define hidden %runtime._string @main.callErrorMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
define hidden %runtime._string @main.callErrorMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8* %itf.value, i32 %itf.typecode, i8* undef) #0
%1 = extractvalue %runtime._string %0, 0
call void @runtime.trackPointer(i8* %1, i8* undef) #0
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8* %itf.value, i32 %itf.typecode, i8* undef, i8* undef) #0
ret %runtime._string %0
}
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8*, i32, i8*) #4
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8*, i32, i8*, i8*) #4
attributes #0 = { nounwind }
attributes #1 = { "tinygo-methods"="reflect/methods.Error() string" }
+8 -8
View File
@@ -3,30 +3,30 @@ source_filename = "intrinsics.go"
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "thumbv7m-unknown-unknown-eabi"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden double @main.mySqrt(double %x, i8* %context) unnamed_addr #0 {
define hidden double @main.mySqrt(double %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call double @math.Sqrt(double %x, i8* undef) #0
%0 = call double @math.Sqrt(double %x, i8* undef, i8* undef) #0
ret double %0
}
declare double @math.Sqrt(double, i8*)
declare double @math.Sqrt(double, i8*, i8*)
; Function Attrs: nounwind
define hidden double @main.myTrunc(double %x, i8* %context) unnamed_addr #0 {
define hidden double @main.myTrunc(double %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call double @math.Trunc(double %x, i8* undef) #0
%0 = call double @math.Trunc(double %x, i8* undef, i8* undef) #0
ret double %0
}
declare double @math.Trunc(double, i8*)
declare double @math.Trunc(double, i8*, i8*)
attributes #0 = { nounwind }
+5 -7
View File
@@ -1,20 +1,18 @@
; ModuleID = 'intrinsics.go'
source_filename = "intrinsics.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden double @main.mySqrt(double %x, i8* %context) unnamed_addr #0 {
define hidden double @main.mySqrt(double %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call double @llvm.sqrt.f64(double %x)
ret double %0
@@ -24,7 +22,7 @@ entry:
declare double @llvm.sqrt.f64(double) #1
; Function Attrs: nounwind
define hidden double @main.myTrunc(double %x, i8* %context) unnamed_addr #0 {
define hidden double @main.myTrunc(double %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call double @llvm.trunc.f64(double %x)
ret double %0
+12 -29
View File
@@ -1,78 +1,61 @@
; ModuleID = 'pointer.go'
source_filename = "pointer.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden [0 x i32] @main.pointerDerefZero([0 x i32]* %x, i8* %context) unnamed_addr #0 {
define hidden [0 x i32] @main.pointerDerefZero([0 x i32]* %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret [0 x i32] zeroinitializer
}
; Function Attrs: nounwind
define hidden i32* @main.pointerCastFromUnsafe(i8* %x, i8* %context) unnamed_addr #0 {
define hidden i32* @main.pointerCastFromUnsafe(i8* %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = bitcast i8* %x to i32*
call void @runtime.trackPointer(i8* %x, i8* undef) #0
ret i32* %0
}
; Function Attrs: nounwind
define hidden i8* @main.pointerCastToUnsafe(i32* dereferenceable_or_null(4) %x, i8* %context) unnamed_addr #0 {
define hidden i8* @main.pointerCastToUnsafe(i32* dereferenceable_or_null(4) %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = bitcast i32* %x to i8*
call void @runtime.trackPointer(i8* %0, i8* undef) #0
ret i8* %0
}
; Function Attrs: nounwind
define hidden i8* @main.pointerCastToUnsafeNoop(i8* dereferenceable_or_null(1) %x, i8* %context) unnamed_addr #0 {
define hidden i8* @main.pointerCastToUnsafeNoop(i8* dereferenceable_or_null(1) %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* %x, i8* undef) #0
ret i8* %x
}
; Function Attrs: nounwind
define hidden i8* @main.pointerUnsafeGEPFixedOffset(i8* dereferenceable_or_null(1) %ptr, i8* %context) unnamed_addr #0 {
define hidden i8* @main.pointerUnsafeGEPFixedOffset(i8* dereferenceable_or_null(1) %ptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* %ptr, i8* undef) #0
%0 = getelementptr inbounds i8, i8* %ptr, i32 10
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
ret i8* %0
}
; Function Attrs: nounwind
define hidden i8* @main.pointerUnsafeGEPByteOffset(i8* dereferenceable_or_null(1) %ptr, i32 %offset, i8* %context) unnamed_addr #0 {
define hidden i8* @main.pointerUnsafeGEPByteOffset(i8* dereferenceable_or_null(1) %ptr, i32 %offset, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
call void @runtime.trackPointer(i8* %ptr, i8* undef) #0
%0 = getelementptr inbounds i8, i8* %ptr, i32 %offset
call void @runtime.trackPointer(i8* %0, i8* undef) #0
call void @runtime.trackPointer(i8* %0, i8* undef) #0
ret i8* %0
}
; Function Attrs: nounwind
define hidden i32* @main.pointerUnsafeGEPIntOffset(i32* dereferenceable_or_null(4) %ptr, i32 %offset, i8* %context) unnamed_addr #0 {
define hidden i32* @main.pointerUnsafeGEPIntOffset(i32* dereferenceable_or_null(4) %ptr, i32 %offset, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %0, i8* undef) #0
%1 = getelementptr i32, i32* %ptr, i32 %offset
%2 = bitcast i32* %1 to i8*
call void @runtime.trackPointer(i8* %2, i8* undef) #0
%3 = bitcast i32* %1 to i8*
call void @runtime.trackPointer(i8* %3, i8* undef) #0
ret i32* %1
%0 = getelementptr i32, i32* %ptr, i32 %offset
ret i32* %0
}
attributes #0 = { nounwind }
+9 -11
View File
@@ -1,6 +1,6 @@
; ModuleID = 'pragma.go'
source_filename = "pragma.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
@extern_global = external global [0 x i8], align 1
@@ -10,12 +10,10 @@ target triple = "wasm32-unknown-wasi"
@undefinedGlobalNotInSection = external global i32, align 4
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
@@ -27,27 +25,27 @@ entry:
}
; Function Attrs: nounwind
define hidden void @somepkg.someFunction1(i8* %context) unnamed_addr #0 {
define hidden void @somepkg.someFunction1(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
declare void @somepkg.someFunction2(i8*)
declare void @somepkg.someFunction2(i8*, i8*)
; Function Attrs: inlinehint nounwind
define hidden void @main.inlineFunc(i8* %context) unnamed_addr #2 {
define hidden void @main.inlineFunc(i8* %context, i8* %parentHandle) unnamed_addr #2 {
entry:
ret void
}
; Function Attrs: noinline nounwind
define hidden void @main.noinlineFunc(i8* %context) unnamed_addr #3 {
define hidden void @main.noinlineFunc(i8* %context, i8* %parentHandle) unnamed_addr #3 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden void @main.functionInSection(i8* %context) unnamed_addr #0 section ".special_function_section" {
define hidden void @main.functionInSection(i8* %context, i8* %parentHandle) unnamed_addr #0 section ".special_function_section" {
entry:
ret void
}
@@ -58,7 +56,7 @@ entry:
ret void
}
declare void @main.undefinedFunctionNotInSection(i8*)
declare void @main.undefinedFunctionNotInSection(i8*, i8*)
attributes #0 = { nounwind }
attributes #1 = { nounwind "wasm-export-name"="extern_func" }
+30 -39
View File
@@ -1,38 +1,36 @@
; ModuleID = 'slice.go'
source_filename = "slice.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden i32 @main.sliceLen(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #0 {
define hidden i32 @main.sliceLen(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret i32 %ints.len
}
; Function Attrs: nounwind
define hidden i32 @main.sliceCap(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #0 {
define hidden i32 @main.sliceCap(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret i32 %ints.cap
}
; Function Attrs: nounwind
define hidden i32 @main.sliceElement(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, i8* %context) unnamed_addr #0 {
define hidden i32 @main.sliceElement(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%.not = icmp ult i32 %index, %ints.len
br i1 %.not, label %lookup.next, label %lookup.throw
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(i8* undef) #0
call void @runtime.lookupPanic(i8* undef, i8* null) #0
unreachable
lookup.next: ; preds = %entry
@@ -41,13 +39,12 @@ lookup.next: ; preds = %entry
ret i32 %1
}
declare void @runtime.lookupPanic(i8*)
declare void @runtime.lookupPanic(i8*, i8*)
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.sliceAppendValues(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #0 {
define hidden { i32*, i32, i32 } @main.sliceAppendValues(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%varargs = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
call void @runtime.trackPointer(i8* nonnull %varargs, i8* undef) #0
%varargs = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%0 = bitcast i8* %varargs to i32*
store i32 1, i32* %0, align 4
%1 = getelementptr inbounds i8, i8* %varargs, i32 4
@@ -57,7 +54,7 @@ entry:
%4 = bitcast i8* %3 to i32*
store i32 3, i32* %4, align 4
%append.srcPtr = bitcast i32* %ints.data to i8*
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, i8* undef) #0
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, i8* undef, i8* null) #0
%append.newPtr = extractvalue { i8*, i32, i32 } %append.new, 0
%append.newBuf = bitcast i8* %append.newPtr to i32*
%append.newLen = extractvalue { i8*, i32, i32 } %append.new, 1
@@ -65,18 +62,17 @@ entry:
%5 = insertvalue { i32*, i32, i32 } undef, i32* %append.newBuf, 0
%6 = insertvalue { i32*, i32, i32 } %5, i32 %append.newLen, 1
%7 = insertvalue { i32*, i32, i32 } %6, i32 %append.newCap, 2
call void @runtime.trackPointer(i8* %append.newPtr, i8* undef) #0
ret { i32*, i32, i32 } %7
}
declare { i8*, i32, i32 } @runtime.sliceAppend(i8*, i8* nocapture readonly, i32, i32, i32, i32, i8*)
declare { i8*, i32, i32 } @runtime.sliceAppend(i8*, i8* nocapture readonly, i32, i32, i32, i32, i8*, i8*)
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.sliceAppendSlice(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32* %added.data, i32 %added.len, i32 %added.cap, i8* %context) unnamed_addr #0 {
define hidden { i32*, i32, i32 } @main.sliceAppendSlice(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32* %added.data, i32 %added.len, i32 %added.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%append.srcPtr = bitcast i32* %ints.data to i8*
%append.srcPtr1 = bitcast i32* %added.data to i8*
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* %append.srcPtr1, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, i8* undef) #0
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* %append.srcPtr1, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, i8* undef, i8* null) #0
%append.newPtr = extractvalue { i8*, i32, i32 } %append.new, 0
%append.newBuf = bitcast i8* %append.newPtr to i32*
%append.newLen = extractvalue { i8*, i32, i32 } %append.new, 1
@@ -84,102 +80,97 @@ entry:
%0 = insertvalue { i32*, i32, i32 } undef, i32* %append.newBuf, 0
%1 = insertvalue { i32*, i32, i32 } %0, i32 %append.newLen, 1
%2 = insertvalue { i32*, i32, i32 } %1, i32 %append.newCap, 2
call void @runtime.trackPointer(i8* %append.newPtr, i8* undef) #0
ret { i32*, i32, i32 } %2
}
; Function Attrs: nounwind
define hidden i32 @main.sliceCopy(i32* %dst.data, i32 %dst.len, i32 %dst.cap, i32* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #0 {
define hidden i32 @main.sliceCopy(i32* %dst.data, i32 %dst.len, i32 %dst.cap, i32* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%copy.dstPtr = bitcast i32* %dst.data to i8*
%copy.srcPtr = bitcast i32* %src.data to i8*
%copy.n = call i32 @runtime.sliceCopy(i8* %copy.dstPtr, i8* %copy.srcPtr, i32 %dst.len, i32 %src.len, i32 4, i8* undef) #0
%copy.n = call i32 @runtime.sliceCopy(i8* %copy.dstPtr, i8* %copy.srcPtr, i32 %dst.len, i32 %src.len, i32 4, i8* undef, i8* null) #0
ret i32 %copy.n
}
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*)
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
; Function Attrs: nounwind
define hidden { i8*, i32, i32 } @main.makeByteSlice(i32 %len, i8* %context) unnamed_addr #0 {
define hidden { i8*, i32, i32 } @main.makeByteSlice(i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%slice.maxcap = icmp slt i32 %len, 0
br i1 %slice.maxcap, label %slice.throw, label %slice.next
slice.throw: ; preds = %entry
call void @runtime.slicePanic(i8* undef) #0
call void @runtime.slicePanic(i8* undef, i8* null) #0
unreachable
slice.next: ; preds = %entry
%makeslice.buf = call i8* @runtime.alloc(i32 %len, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
%makeslice.buf = call i8* @runtime.alloc(i32 %len, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%0 = insertvalue { i8*, i32, i32 } undef, i8* %makeslice.buf, 0
%1 = insertvalue { i8*, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { i8*, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
ret { i8*, i32, i32 } %2
}
declare void @runtime.slicePanic(i8*)
declare void @runtime.slicePanic(i8*, i8*)
; Function Attrs: nounwind
define hidden { i16*, i32, i32 } @main.makeInt16Slice(i32 %len, i8* %context) unnamed_addr #0 {
define hidden { i16*, i32, i32 } @main.makeInt16Slice(i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%slice.maxcap = icmp slt i32 %len, 0
br i1 %slice.maxcap, label %slice.throw, label %slice.next
slice.throw: ; preds = %entry
call void @runtime.slicePanic(i8* undef) #0
call void @runtime.slicePanic(i8* undef, i8* null) #0
unreachable
slice.next: ; preds = %entry
%makeslice.cap = shl i32 %len, 1
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%makeslice.array = bitcast i8* %makeslice.buf to i16*
%0 = insertvalue { i16*, i32, i32 } undef, i16* %makeslice.array, 0
%1 = insertvalue { i16*, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { i16*, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
ret { i16*, i32, i32 } %2
}
; Function Attrs: nounwind
define hidden { [3 x i8]*, i32, i32 } @main.makeArraySlice(i32 %len, i8* %context) unnamed_addr #0 {
define hidden { [3 x i8]*, i32, i32 } @main.makeArraySlice(i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%slice.maxcap = icmp ugt i32 %len, 1431655765
br i1 %slice.maxcap, label %slice.throw, label %slice.next
slice.throw: ; preds = %entry
call void @runtime.slicePanic(i8* undef) #0
call void @runtime.slicePanic(i8* undef, i8* null) #0
unreachable
slice.next: ; preds = %entry
%makeslice.cap = mul i32 %len, 3
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%makeslice.array = bitcast i8* %makeslice.buf to [3 x i8]*
%0 = insertvalue { [3 x i8]*, i32, i32 } undef, [3 x i8]* %makeslice.array, 0
%1 = insertvalue { [3 x i8]*, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { [3 x i8]*, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
ret { [3 x i8]*, i32, i32 } %2
}
; Function Attrs: nounwind
define hidden { i32*, i32, i32 } @main.makeInt32Slice(i32 %len, i8* %context) unnamed_addr #0 {
define hidden { i32*, i32, i32 } @main.makeInt32Slice(i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%slice.maxcap = icmp ugt i32 %len, 1073741823
br i1 %slice.maxcap, label %slice.throw, label %slice.next
slice.throw: ; preds = %entry
call void @runtime.slicePanic(i8* undef) #0
call void @runtime.slicePanic(i8* undef, i8* null) #0
unreachable
slice.next: ; preds = %entry
%makeslice.cap = shl i32 %len, 2
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
%makeslice.array = bitcast i8* %makeslice.buf to i32*
%0 = insertvalue { i32*, i32, i32 } undef, i32* %makeslice.array, 0
%1 = insertvalue { i32*, i32, i32 } %0, i32 %len, 1
%2 = insertvalue { i32*, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
ret { i32*, i32, i32 } %2
}
+19 -21
View File
@@ -1,48 +1,46 @@
; ModuleID = 'string.go'
source_filename = "string.go"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-wasi"
%runtime._string = type { i8*, i32 }
@"main$string" = internal unnamed_addr constant [3 x i8] c"foo", align 1
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
; Function Attrs: nounwind
define hidden void @main.init(i8* %context) unnamed_addr #0 {
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret void
}
; Function Attrs: nounwind
define hidden %runtime._string @main.someString(i8* %context) unnamed_addr #0 {
define hidden %runtime._string @main.someString(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret %runtime._string { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"main$string", i32 0, i32 0), i32 3 }
}
; Function Attrs: nounwind
define hidden %runtime._string @main.zeroLengthString(i8* %context) unnamed_addr #0 {
define hidden %runtime._string @main.zeroLengthString(i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret %runtime._string zeroinitializer
}
; Function Attrs: nounwind
define hidden i32 @main.stringLen(i8* %s.data, i32 %s.len, i8* %context) unnamed_addr #0 {
define hidden i32 @main.stringLen(i8* %s.data, i32 %s.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
ret i32 %s.len
}
; Function Attrs: nounwind
define hidden i8 @main.stringIndex(i8* %s.data, i32 %s.len, i32 %index, i8* %context) unnamed_addr #0 {
define hidden i8 @main.stringIndex(i8* %s.data, i32 %s.len, i32 %index, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%.not = icmp ult i32 %index, %s.len
br i1 %.not, label %lookup.next, label %lookup.throw
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(i8* undef) #0
call void @runtime.lookupPanic(i8* undef, i8* null) #0
unreachable
lookup.next: ; preds = %entry
@@ -51,43 +49,43 @@ lookup.next: ; preds = %entry
ret i8 %1
}
declare void @runtime.lookupPanic(i8*)
declare void @runtime.lookupPanic(i8*, i8*)
; Function Attrs: nounwind
define hidden i1 @main.stringCompareEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #0 {
define hidden i1 @main.stringCompareEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef) #0
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef, i8* null) #0
ret i1 %0
}
declare i1 @runtime.stringEqual(i8*, i32, i8*, i32, i8*)
declare i1 @runtime.stringEqual(i8*, i32, i8*, i32, i8*, i8*)
; Function Attrs: nounwind
define hidden i1 @main.stringCompareUnequal(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #0 {
define hidden i1 @main.stringCompareUnequal(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef) #0
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef, i8* null) #0
%1 = xor i1 %0, true
ret i1 %1
}
; Function Attrs: nounwind
define hidden i1 @main.stringCompareLarger(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #0 {
define hidden i1 @main.stringCompareLarger(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = call i1 @runtime.stringLess(i8* %s2.data, i32 %s2.len, i8* %s1.data, i32 %s1.len, i8* undef) #0
%0 = call i1 @runtime.stringLess(i8* %s2.data, i32 %s2.len, i8* %s1.data, i32 %s1.len, i8* undef, i8* null) #0
ret i1 %0
}
declare i1 @runtime.stringLess(i8*, i32, i8*, i32, i8*)
declare i1 @runtime.stringLess(i8*, i32, i8*, i32, i8*, i8*)
; Function Attrs: nounwind
define hidden i8 @main.stringLookup(i8* %s.data, i32 %s.len, i8 %x, i8* %context) unnamed_addr #0 {
define hidden i8 @main.stringLookup(i8* %s.data, i32 %s.len, i8 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry:
%0 = zext i8 %x to i32
%.not = icmp ult i32 %0, %s.len
br i1 %.not, label %lookup.next, label %lookup.throw
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(i8* undef) #0
call void @runtime.lookupPanic(i8* undef, i8* null) #0
unreachable
lookup.next: ; preds = %entry
-177
View File
@@ -1,177 +0,0 @@
package main
import (
"flag"
"os"
"os/exec"
"strings"
"sync"
"testing"
yaml "gopkg.in/yaml.v2"
)
/*
This contains code from https://github.com/dgryski/tinygo-test-corpus
The MIT License (MIT)
Copyright (c) 2020 Damian Gryski <damian@gryski.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
var corpus = flag.String("corpus", "", "path to test corpus")
func TestCorpus(t *testing.T) {
t.Parallel()
if *corpus == "" {
t.Skip()
}
var target string
if *testTarget != "" {
target = *testTarget
}
repos, err := loadRepos(*corpus)
if err != nil {
t.Fatalf("loading corpus: %v", err)
}
for _, repo := range repos {
repo := repo
name := repo.Repo
if repo.Tags != "" {
name += "(" + strings.ReplaceAll(repo.Tags, " ", "-") + ")"
}
if repo.Version != "" {
name += "@" + repo.Version
}
t.Run(name, func(t *testing.T) {
t.Parallel()
if target == "wasi" && repo.SkipWASI {
t.Skip("skip wasi")
}
if repo.Slow && testing.Short() {
t.Skip("slow test")
}
var wg sync.WaitGroup
defer wg.Wait()
out := ioLogger(t, &wg)
defer out.Close()
dir := t.TempDir()
cmd := exec.Command("go", "mod", "init", "github.com/tinygo/tinygo-corpus-test")
cmd.Dir = dir
cmd.Stdout, cmd.Stderr = out, out
err := cmd.Run()
if err != nil {
t.Errorf("failed to init: %s", err.Error())
return
}
var ver string
if repo.Version != "" {
ver = "@" + repo.Version
}
cmd = exec.Command("go", "get", "-t", "-d", repo.Repo+"/..."+ver)
cmd.Dir = dir
cmd.Stdout, cmd.Stderr = out, out
err = cmd.Run()
if err != nil {
t.Errorf("failed to get: %s", err.Error())
return
}
doTest := func(t *testing.T, path string) {
var wg sync.WaitGroup
defer wg.Wait()
out := ioLogger(t, &wg)
defer out.Close()
opts := optionsFromTarget(target, sema)
opts.Directory = dir
opts.Tags = repo.Tags
passed, err := Test(path, out, out, &opts, false, testing.Verbose(), false, "", "", "", "")
if err != nil {
t.Errorf("test error: %v", err)
}
if !passed {
t.Error("test failed")
}
}
if len(repo.Subdirs) == 0 {
doTest(t, repo.Repo)
return
}
for _, dir := range repo.Subdirs {
dir := dir
t.Run(dir.Pkg, func(t *testing.T) {
t.Parallel()
if target == "wasi" && dir.SkipWASI {
t.Skip("skip wasi")
}
if dir.Slow && testing.Short() {
t.Skip("slow test")
}
doTest(t, repo.Repo+"/"+dir.Pkg)
})
}
})
}
}
type T struct {
Repo string
Tags string
Subdirs []Subdir
SkipWASI bool
Slow bool
Version string
}
type Subdir struct {
Pkg string
SkipWASI bool
Slow bool
}
func loadRepos(f string) ([]T, error) {
yf, err := os.ReadFile(f)
if err != nil {
return nil, err
}
var repos []T
err = yaml.Unmarshal(yf, &repos)
if err != nil {
return nil, err
}
return repos, nil
}
+6 -7
View File
@@ -3,17 +3,16 @@ module github.com/tinygo-org/tinygo
go 1.15
require (
github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a
github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a // indirect
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
github.com/chromedp/chromedp v0.7.6
github.com/gofrs/flock v0.8.1
github.com/chromedp/cdproto v0.0.0-20210113043257-dabd2f2e7693
github.com/chromedp/chromedp v0.6.4
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
github.com/mattn/go-colorable v0.1.8
go.bug.st/serial v1.1.3
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210510120138-977fb7262007
golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9
gopkg.in/yaml.v2 v2.4.0
tinygo.org/x/go-llvm v0.0.0-20220211075103-ee4aad45c3a1
tinygo.org/x/go-llvm v0.0.0-20210907125547-fd2d62ea06be
)
+16 -27
View File
@@ -2,55 +2,50 @@ github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a h1:QPU7APo6y/6VkC
github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee h1:+SFdIVfQpG0s0DHYzou0kgfE0n0ZjKPwbiRJsXrZegU=
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
github.com/chromedp/chromedp v0.7.6 h1:2juGaktzjwULlsn+DnvIZXFUckEp5xs+GOBroaea+jA=
github.com/chromedp/chromedp v0.7.6/go.mod h1:ayT4YU/MGAALNfOg9gNrpGSAdnU51PMx+FCeuT1iXzo=
github.com/chromedp/cdproto v0.0.0-20210113043257-dabd2f2e7693 h1:11eq/RkpaotwdF6b1TRMcdgQUPNmyFEJOB7zLvh0O/Y=
github.com/chromedp/cdproto v0.0.0-20210113043257-dabd2f2e7693/go.mod h1:55pim6Ht4LJKdVLlyFJV/g++HsEA1hQxPbB5JyNdZC0=
github.com/chromedp/chromedp v0.6.4 h1:Gx7ZkRyrSVmbbDDja/ieNgNGJIvElroPOyeqYQGVDSY=
github.com/chromedp/chromedp v0.6.4/go.mod h1:vodUdJf5dF/b8n0UBJv6NeM/QK28RjP3j+eM7fq4+84=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs=
github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.bug.st/serial v1.1.3 h1:YEBxJa9pKS9Wdg46B/jiaKbvvbUrjhZZZITfJHEJhaE=
go.bug.st/serial v1.1.3/go.mod h1:8TT7u/SwwNIpJ8QaG4s+HTjFt9ReXs2cdOU7ZEk50Dk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -58,12 +53,10 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -73,12 +66,8 @@ golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9 h1:nvvuMxmx1q0gfRki3T0hj
golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
tinygo.org/x/go-llvm v0.0.0-20220211075103-ee4aad45c3a1 h1:6G8AxueDdqobCEqQrmHPLaEH1AZ1p6Y7rGElDNT7N98=
tinygo.org/x/go-llvm v0.0.0-20220211075103-ee4aad45c3a1/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
tinygo.org/x/go-llvm v0.0.0-20210907125547-fd2d62ea06be h1:syIpWbi/yESuoyijF2nhRdgX4422sNfmij+o73B3+vU=
tinygo.org/x/go-llvm v0.0.0-20210907125547-fd2d62ea06be/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
+1 -7
View File
@@ -12,13 +12,7 @@ import (
// Version of TinyGo.
// Update this value before release of new version of software.
const Version = "0.23.0-dev"
var (
// This variable is set at build time using -ldflags parameters.
// See: https://stackoverflow.com/a/11355611
GitSha1 string
)
const Version = "0.22.0-dev"
// GetGorootVersion returns the major and minor version for a given GOROOT path.
// If the goroot cannot be determined, (0, 0) is returned.
+7 -3
View File
@@ -11,6 +11,12 @@ import (
"tinygo.org/x/go-llvm"
)
// Version of the interp package. It must be incremented whenever the interp
// package is changed in a way that affects the output so that cached package
// builds will be invalidated.
// This version is independent of the TinyGo version number.
const Version = 2 // last change: fix GEP on untyped pointers
// Enable extra checks, which should be disabled by default.
// This may help track down bugs by adding a few more sanity checks.
const checks = true
@@ -22,7 +28,6 @@ type runner struct {
builder llvm.Builder
pointerSize uint32 // cached pointer size from the TargetData
i8ptrType llvm.Type // often used type so created in advance
uintptrType llvm.Type // equivalent to uintptr in Go
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
debug bool // log debug messages
pkgName string // package name of the currently executing package
@@ -45,7 +50,6 @@ func newRunner(mod llvm.Module, debug bool) *runner {
}
r.pointerSize = uint32(r.targetData.PointerSize())
r.i8ptrType = llvm.PointerType(mod.Context().Int8Type(), 0)
r.uintptrType = mod.Context().IntType(r.targetData.PointerSize() * 8)
r.maxAlign = r.targetData.PrefTypeAlignment(r.i8ptrType) // assume pointers are maximally aligned (this is not always the case)
return &r
}
@@ -118,7 +122,7 @@ func Run(mod llvm.Module, debug bool) error {
// Create a call to the package initializer (which was
// previously deleted).
i8undef := llvm.Undef(r.i8ptrType)
r.builder.CreateCall(fn, []llvm.Value{i8undef}, "")
r.builder.CreateCall(fn, []llvm.Value{i8undef, i8undef}, "")
// Make sure that any globals touched by the package
// initializer, won't be accessed by later package initializers.
r.markExternalLoad(fn)
+10 -27
View File
@@ -17,7 +17,10 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
locals := make([]value, len(fn.locals))
r.callsExecuted++
t0 := time.Since(r.start)
if time.Since(r.start) > time.Minute {
// Running for more than a minute. This should never happen.
return nil, mem, r.errorAt(fn.blocks[0].instructions[0], fmt.Errorf("interp: running for more than a minute, timing out (executed calls: %d)", r.callsExecuted))
}
// Parameters are considered a kind of local values.
for i, param := range params {
@@ -103,13 +106,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
}
switch inst.opcode {
case llvm.Ret:
const maxInterpSeconds = 180
if t0 > maxInterpSeconds*time.Second {
// Running for more than maxInterpSeconds seconds. This should never happen, but does.
// See github.com/tinygo-org/tinygo/issues/2124
return nil, mem, r.errorAt(fn.blocks[0].instructions[0], fmt.Errorf("interp: running for more than %d seconds, timing out (executed calls: %d)", maxInterpSeconds, r.callsExecuted))
}
if len(operands) != 0 {
if r.debug {
fmt.Fprintln(os.Stderr, indent+"ret", operands[0])
@@ -201,8 +197,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// which case this call won't even get to this point but will
// already be emitted in initAll.
continue
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet" ||
callFn.name == "os.runtime_args" || callFn.name == "internal/task.start" || callFn.name == "internal/task.Current":
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet" || callFn.name == "os.runtime_args":
// These functions should be run at runtime. Specifically:
// * Print and panic functions are best emitted directly without
// interpreting them, otherwise we get a ton of putchar (etc.)
@@ -213,8 +208,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// * os.runtime_args reads globals that are initialized outside
// the view of the interp package so it always needs to be run
// at runtime.
// * internal/task.start, internal/task.Current: start and read shcheduler state,
// which is modified elsewhere.
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
if err != nil {
return nil, mem, err
@@ -383,10 +376,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
if !actualTypePtrToInt.IsAConstantInt().IsNil() && actualTypePtrToInt.ZExtValue() == 0 {
locals[inst.localIndex] = literalValue{uint8(0)}
break
}
actualType := actualTypePtrToInt.Operand(0)
if strings.TrimPrefix(actualType.Name(), "reflect/types.type:") == strings.TrimPrefix(assertedType.Name(), "reflect/types.typeid:") {
locals[inst.localIndex] = literalValue{uint8(1)}
@@ -444,7 +433,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
}
// Load the type code of the interface value.
typecodeIDBitCast, err := operands[len(operands)-2].toLLVMValue(inst.llvmInst.Operand(len(operands)-3).Type(), &mem)
typecodeIDBitCast, err := operands[len(operands)-3].toLLVMValue(inst.llvmInst.Operand(len(operands)-4).Type(), &mem)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
@@ -493,8 +482,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// possibly trying to recover from it if it failed to execute.
if r.debug {
argStrings := make([]string, len(operands)-1)
for i, v := range operands[1:] {
argStrings[i] = v.String()
for i := range argStrings {
argStrings[i] = operands[i+1].String()
}
fmt.Fprintln(os.Stderr, indent+"call:", callFn.name+"("+strings.Join(argStrings, ", ")+")")
}
@@ -532,7 +521,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
return nil, mem, r.errorAt(inst, err)
}
size := operands[1].(literalValue).value.(uint64)
if inst.llvmInst.IsVolatile() || inst.llvmInst.Ordering() != llvm.AtomicOrderingNotAtomic || mem.hasExternalStore(ptr) {
if mem.hasExternalStore(ptr) {
// If there could be an external store (for example, because a
// pointer to the object was passed to a function that could not
// be interpreted at compile time) then the load must be done at
@@ -562,7 +551,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
if inst.llvmInst.IsVolatile() || inst.llvmInst.Ordering() != llvm.AtomicOrderingNotAtomic || mem.hasExternalLoadOrStore(ptr) {
if mem.hasExternalLoadOrStore(ptr) {
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
if err != nil {
return nil, mem, err
@@ -936,18 +925,12 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me
if inst.llvmInst.IsVolatile() {
result.SetVolatile(true)
}
if ordering := inst.llvmInst.Ordering(); ordering != llvm.AtomicOrderingNotAtomic {
result.SetOrdering(ordering)
}
case llvm.Store:
mem.markExternalStore(operands[1])
result = r.builder.CreateStore(operands[0], operands[1])
if inst.llvmInst.IsVolatile() {
result.SetVolatile(true)
}
if ordering := inst.llvmInst.Ordering(); ordering != llvm.AtomicOrderingNotAtomic {
result.SetOrdering(ordering)
}
case llvm.BitCast:
result = r.builder.CreateBitCast(operands[0], inst.llvmInst.Type(), inst.name)
case llvm.ExtractValue:
+1 -8
View File
@@ -903,14 +903,7 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value,
return llvm.Value{}, err
}
if llvmValue.Type() != llvmType {
if llvmValue.Type().PointerAddressSpace() != llvmType.PointerAddressSpace() {
// Special case for AVR function pointers.
// Because go-llvm doesn't have addrspacecast at the moment,
// do it indirectly with a ptrtoint/inttoptr pair.
llvmValue = llvm.ConstIntToPtr(llvm.ConstPtrToInt(llvmValue, mem.r.uintptrType), llvmType)
} else {
llvmValue = llvm.ConstBitCast(llvmValue, llvmType)
}
llvmValue = llvm.ConstBitCast(llvmValue, llvmType)
}
return llvmValue, nil
}
-3
View File
@@ -5,7 +5,6 @@ target triple = "x86_64--linux"
%runtime.interfaceMethodInfo = type { i8*, i64 }
@main.v1 = global i1 0
@main.v2 = global i1 0
@"reflect/types.type:named:main.foo" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i64 0, %runtime.interfaceMethodInfo* null }
@"reflect/types.typeid:named:main.foo" = external constant i8
@"reflect/types.type:basic:int" = external constant %runtime.typecodeID
@@ -24,7 +23,5 @@ entry:
; Test type asserts.
%typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typecodeID* @"reflect/types.type:named:main.foo" to i64), i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
store i1 %typecode, i1* @main.v1
%typecode2 = call i1 @runtime.typeAssert(i64 0, i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
store i1 %typecode2, i1* @main.v2
ret void
}
-1
View File
@@ -2,7 +2,6 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@main.v1 = local_unnamed_addr global i1 true
@main.v2 = local_unnamed_addr global i1 false
define void @runtime.initAll() unnamed_addr {
entry:
+8 -39
View File
@@ -7,33 +7,28 @@ declare void @externalCall(i64)
@bar.knownAtRuntime = global i64 0
@baz.someGlobal = external global [3 x {i64, i32}]
@baz.someInt = global i32 0
@x.atomicNum = global i32 0
@x.volatileNum = global i32 0
@y.ready = global i32 0
define void @runtime.initAll() unnamed_addr {
entry:
call void @baz.init(i8* undef)
call void @foo.init(i8* undef)
call void @bar.init(i8* undef)
call void @main.init(i8* undef)
call void @x.init(i8* undef)
call void @y.init(i8* undef)
call void @baz.init(i8* undef, i8* undef)
call void @foo.init(i8* undef, i8* undef)
call void @bar.init(i8* undef, i8* undef)
call void @main.init(i8* undef, i8* undef)
ret void
}
define internal void @foo.init(i8* %context) unnamed_addr {
define internal void @foo.init(i8* %context, i8* %parentHandle) unnamed_addr {
store i64 5, i64* @foo.knownAtRuntime
unreachable ; this triggers a revert of @foo.init.
}
define internal void @bar.init(i8* %context) unnamed_addr {
define internal void @bar.init(i8* %context, i8* %parentHandle) unnamed_addr {
%val = load i64, i64* @foo.knownAtRuntime
store i64 %val, i64* @bar.knownAtRuntime
ret void
}
define internal void @baz.init(i8* %context) unnamed_addr {
define internal void @baz.init(i8* %context, i8* %parentHandle) unnamed_addr {
; Test extractvalue/insertvalue with more than one index.
%val = load [3 x {i64, i32}], [3 x {i64, i32}]* @baz.someGlobal
%part = extractvalue [3 x {i64, i32}] %val, 0, 1
@@ -41,34 +36,8 @@ define internal void @baz.init(i8* %context) unnamed_addr {
unreachable ; trigger revert
}
define internal void @main.init(i8* %context) unnamed_addr {
define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
call void @externalCall(i64 3)
ret void
}
define internal void @x.init(i8* %context) unnamed_addr {
; Test atomic and volatile memory accesses.
store atomic i32 1, i32* @x.atomicNum seq_cst, align 4
%x = load atomic i32, i32* @x.atomicNum seq_cst, align 4
store i32 %x, i32* @x.atomicNum
%y = load volatile i32, i32* @x.volatileNum
store volatile i32 %y, i32* @x.volatileNum
ret void
}
define internal void @y.init(i8* %context) unnamed_addr {
entry:
br label %loop
loop:
; Test a wait-loop.
; This function must be reverted.
%val = load atomic i32, i32* @y.ready seq_cst, align 4
%ready = icmp eq i32 %val, 1
br i1 %ready, label %end, label %loop
end:
ret void
}
+4 -26
View File
@@ -5,46 +5,24 @@ target triple = "x86_64--linux"
@bar.knownAtRuntime = local_unnamed_addr global i64 0
@baz.someGlobal = external local_unnamed_addr global [3 x { i64, i32 }]
@baz.someInt = local_unnamed_addr global i32 0
@x.atomicNum = local_unnamed_addr global i32 0
@x.volatileNum = global i32 0
@y.ready = local_unnamed_addr global i32 0
declare void @externalCall(i64) local_unnamed_addr
define void @runtime.initAll() unnamed_addr {
entry:
call fastcc void @baz.init(i8* undef)
call fastcc void @foo.init(i8* undef)
call fastcc void @baz.init(i8* undef, i8* undef)
call fastcc void @foo.init(i8* undef, i8* undef)
%val = load i64, i64* @foo.knownAtRuntime, align 8
store i64 %val, i64* @bar.knownAtRuntime, align 8
call void @externalCall(i64 3)
store atomic i32 1, i32* @x.atomicNum seq_cst, align 4
%x = load atomic i32, i32* @x.atomicNum seq_cst, align 4
store i32 %x, i32* @x.atomicNum, align 4
%y = load volatile i32, i32* @x.volatileNum, align 4
store volatile i32 %y, i32* @x.volatileNum, align 4
call fastcc void @y.init(i8* undef)
ret void
}
define internal fastcc void @foo.init(i8* %context) unnamed_addr {
define internal fastcc void @foo.init(i8* %context, i8* %parentHandle) unnamed_addr {
store i64 5, i64* @foo.knownAtRuntime, align 8
unreachable
}
define internal fastcc void @baz.init(i8* %context) unnamed_addr {
define internal fastcc void @baz.init(i8* %context, i8* %parentHandle) unnamed_addr {
unreachable
}
define internal fastcc void @y.init(i8* %context) unnamed_addr {
entry:
br label %loop
loop: ; preds = %loop, %entry
%val = load atomic i32, i32* @y.ready seq_cst, align 4
%ready = icmp eq i32 %val, 1
br i1 %ready, label %end, label %loop
end: ; preds = %loop
ret void
}
+88 -93
View File
@@ -14,8 +14,8 @@ package loader
import (
"crypto/sha512"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
@@ -23,7 +23,6 @@ import (
"path"
"path/filepath"
"runtime"
"sort"
"sync"
"github.com/tinygo-org/tinygo/compileopts"
@@ -44,21 +43,27 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
return "", errors.New("could not determine TINYGOROOT")
}
// Find the overrides needed for the goroot.
overrides := pathsToOverride(needsSyscallPackage(config.BuildTags()))
// Resolve the merge links within the goroot.
merge, err := listGorootMergeLinks(goroot, tinygoroot, overrides)
// Determine the location of the cached GOROOT.
version, err := goenv.GorootVersionString(goroot)
if err != nil {
return "", err
}
// Hash the merge links to create a cache key.
data, err := json.Marshal(merge)
if err != nil {
return "", err
// This hash is really a cache key, that contains (hopefully) enough
// information to make collisions unlikely during development.
// By including the Go version and TinyGo version, cache collisions should
// not happen outside of development.
hash := sha512.New512_256()
fmt.Fprintln(hash, goroot)
fmt.Fprintln(hash, version)
fmt.Fprintln(hash, goenv.Version)
fmt.Fprintln(hash, tinygoroot)
gorootsHash := hash.Sum(nil)
gorootsHashHex := hex.EncodeToString(gorootsHash[:])
cachedgorootName := "goroot-" + version + "-" + gorootsHashHex
cachedgoroot := filepath.Join(goenv.Get("GOCACHE"), cachedgorootName)
if needsSyscallPackage(config.BuildTags()) {
cachedgoroot += "-syscall"
}
hash := sha512.Sum512_256(data)
// Do not try to create the cached GOROOT in parallel, that's only a waste
// of I/O bandwidth and thus speed. Instead, use a mutex to make sure only
@@ -69,21 +74,14 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
gorootCreateMutex.Lock()
defer gorootCreateMutex.Unlock()
// Check if the goroot already exists.
cachedGorootName := "goroot-" + hex.EncodeToString(hash[:])
cachedgoroot := filepath.Join(goenv.Get("GOCACHE"), cachedGorootName)
if _, err := os.Stat(cachedgoroot); err == nil {
return cachedgoroot, nil
}
// Create the cache directory if it does not already exist.
err = os.MkdirAll(goenv.Get("GOCACHE"), 0777)
if err != nil {
return "", err
}
// Create a temporary directory to construct the goroot within.
tmpgoroot, err := ioutil.TempDir(goenv.Get("GOCACHE"), cachedGorootName+".tmp")
tmpgoroot, err := ioutil.TempDir(goenv.Get("GOCACHE"), cachedgorootName+".tmp")
if err != nil {
return "", err
}
@@ -92,34 +90,16 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
// (for example, when there was an error).
defer os.RemoveAll(tmpgoroot)
// Create the directory structure.
// The directories are created in sorted order so that nested directories are created without extra work.
{
var dirs []string
for dir, merge := range overrides {
if merge {
dirs = append(dirs, filepath.Join(tmpgoroot, "src", dir))
}
}
sort.Strings(dirs)
for _, dir := range dirs {
err := os.Mkdir(dir, 0777)
if err != nil {
return "", err
}
}
}
// Create all symlinks.
for dst, src := range merge {
err := symlink(src, filepath.Join(tmpgoroot, dst))
for _, name := range []string{"bin", "lib", "pkg"} {
err = symlink(filepath.Join(goroot, name), filepath.Join(tmpgoroot, name))
if err != nil {
return "", err
}
}
// Rename the new merged gorooot into place.
err = mergeDirectory(goroot, tinygoroot, tmpgoroot, "", pathsToOverride(needsSyscallPackage(config.BuildTags())))
if err != nil {
return "", err
}
err = os.Rename(tmpgoroot, cachedgoroot)
if err != nil {
if os.IsExist(err) {
@@ -142,71 +122,86 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
return cachedgoroot, nil
}
// listGorootMergeLinks searches goroot and tinygoroot for all symlinks that must be created within the merged goroot.
func listGorootMergeLinks(goroot, tinygoroot string, overrides map[string]bool) (map[string]string, error) {
goSrc := filepath.Join(goroot, "src")
tinygoSrc := filepath.Join(tinygoroot, "src")
merges := make(map[string]string)
for dir, merge := range overrides {
if !merge {
// Use the TinyGo version.
merges[filepath.Join("src", dir)] = filepath.Join(tinygoSrc, dir)
continue
// mergeDirectory merges two roots recursively. The tmpgoroot is the directory
// that will be created by this call by either symlinking the directory from
// goroot or tinygoroot, or by creating the directory and merging the contents.
func mergeDirectory(goroot, tinygoroot, tmpgoroot, importPath string, overrides map[string]bool) error {
if mergeSubdirs, ok := overrides[importPath+"/"]; ok {
if !mergeSubdirs {
// This directory and all subdirectories should come from the TinyGo
// root, so simply make a symlink.
newname := filepath.Join(tmpgoroot, "src", importPath)
oldname := filepath.Join(tinygoroot, "src", importPath)
return symlink(oldname, newname)
}
// Add files from TinyGo.
tinygoDir := filepath.Join(tinygoSrc, dir)
tinygoEntries, err := ioutil.ReadDir(tinygoDir)
// Merge subdirectories. Start by making the directory to merge.
err := os.Mkdir(filepath.Join(tmpgoroot, "src", importPath), 0777)
if err != nil {
return nil, err
return err
}
var hasTinyGoFiles bool
// Symlink all files from TinyGo, and symlink directories from TinyGo
// that need to be overridden.
tinygoEntries, err := ioutil.ReadDir(filepath.Join(tinygoroot, "src", importPath))
if err != nil {
return err
}
hasTinyGoFiles := false
for _, e := range tinygoEntries {
if e.IsDir() {
continue
// A directory, so merge this thing.
err := mergeDirectory(goroot, tinygoroot, tmpgoroot, path.Join(importPath, e.Name()), overrides)
if err != nil {
return err
}
} else {
// A file, so symlink this.
newname := filepath.Join(tmpgoroot, "src", importPath, e.Name())
oldname := filepath.Join(tinygoroot, "src", importPath, e.Name())
err := symlink(oldname, newname)
if err != nil {
return err
}
hasTinyGoFiles = true
}
// Link this file.
name := e.Name()
merges[filepath.Join("src", dir, name)] = filepath.Join(tinygoDir, name)
hasTinyGoFiles = true
}
// Add all directories from $GOROOT that are not part of the TinyGo
// Symlink all directories from $GOROOT that are not part of the TinyGo
// overrides.
goDir := filepath.Join(goSrc, dir)
goEntries, err := ioutil.ReadDir(goDir)
gorootEntries, err := ioutil.ReadDir(filepath.Join(goroot, "src", importPath))
if err != nil {
return nil, err
return err
}
for _, e := range goEntries {
isDir := e.IsDir()
if hasTinyGoFiles && !isDir {
for _, e := range gorootEntries {
if e.IsDir() {
if _, ok := overrides[path.Join(importPath, e.Name())+"/"]; ok {
// Already included above, so don't bother trying to create this
// symlink.
continue
}
newname := filepath.Join(tmpgoroot, "src", importPath, e.Name())
oldname := filepath.Join(goroot, "src", importPath, e.Name())
err := symlink(oldname, newname)
if err != nil {
return err
}
} else {
// Only merge files from Go if TinyGo does not have any files.
// Otherwise we'd end up with a weird mix from both Go
// implementations.
continue
if !hasTinyGoFiles {
newname := filepath.Join(tmpgoroot, "src", importPath, e.Name())
oldname := filepath.Join(goroot, "src", importPath, e.Name())
err := symlink(oldname, newname)
if err != nil {
return err
}
}
}
name := e.Name()
if _, ok := overrides[path.Join(dir, name)+"/"]; ok {
// This entry is overridden by TinyGo.
// It has/will be merged elsewhere.
continue
}
// Add a link to this entry
merges[filepath.Join("src", dir, name)] = filepath.Join(goDir, name)
}
}
// Merge the special directories from goroot.
for _, dir := range []string{"bin", "lib", "pkg"} {
merges[dir] = filepath.Join(goroot, dir)
}
return merges, nil
return nil
}
// needsSyscallPackage returns whether the syscall package should be overriden
@@ -224,7 +219,7 @@ func needsSyscallPackage(buildTags []string) bool {
// means use the TinyGo version.
func pathsToOverride(needsSyscallPackage bool) map[string]bool {
paths := map[string]bool{
"": true,
"/": true,
"crypto/": true,
"crypto/rand/": false,
"device/": false,
+1 -6
View File
@@ -3,11 +3,9 @@ package loader
import (
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
)
// List returns a ready-to-run *exec.Cmd for running the `go list` command with
@@ -26,10 +24,7 @@ func List(config *compileopts.Config, extraArgs, pkgs []string) (*exec.Cmd, erro
if config.CgoEnabled() {
cgoEnabled = "1"
}
cmd := exec.Command(filepath.Join(goenv.Get("GOROOT"), "bin", "go"), args...)
cmd := exec.Command("go", args...)
cmd.Env = append(os.Environ(), "GOROOT="+goroot, "GOOS="+config.GOOS(), "GOARCH="+config.GOARCH(), "CGO_ENABLED="+cgoEnabled)
if config.Options.Directory != "" {
cmd.Dir = config.Options.Directory
}
return cmd, nil
}
+7 -17
View File
@@ -47,14 +47,6 @@ type PackageJSON struct {
ImportPath string
Name string
ForTest string
Root string
Module struct {
Path string
Main bool
Dir string
GoMod string
GoVersion string
}
// Source files
GoFiles []string
@@ -94,14 +86,9 @@ func Load(config *compileopts.Config, inputPkgs []string, clangHeaders string, t
if err != nil {
return nil, err
}
var wd string
if config.Options.Directory != "" {
wd = config.Options.Directory
} else {
wd, err = os.Getwd()
if err != nil {
return nil, err
}
wd, err := os.Getwd()
if err != nil {
return nil, err
}
p := &Program{
config: config,
@@ -418,7 +405,10 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
var initialCFlags []string
initialCFlags = append(initialCFlags, p.program.config.CFlags()...)
initialCFlags = append(initialCFlags, "-I"+p.Dir)
generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.program.fset, initialCFlags, p.program.clangHeaders)
if p.program.clangHeaders != "" {
initialCFlags = append(initialCFlags, "-Xclang", "-internal-isystem", "-Xclang", p.program.clangHeaders)
}
generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.program.fset, initialCFlags)
p.CFlags = append(initialCFlags, cflags...)
p.CGoHeaders = headerCode
for path, hash := range accessedFiles {
+91 -346
View File
@@ -2,7 +2,6 @@ package main
import (
"bytes"
"encoding/json"
"errors"
"flag"
"fmt"
@@ -19,7 +18,6 @@ import (
"runtime/pprof"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
@@ -30,12 +28,19 @@ import (
"github.com/tinygo-org/tinygo/goenv"
"github.com/tinygo-org/tinygo/interp"
"github.com/tinygo-org/tinygo/loader"
"github.com/tinygo-org/tinygo/transform"
"tinygo.org/x/go-llvm"
"go.bug.st/serial"
"go.bug.st/serial/enumerator"
)
var (
// This variable is set at build time using -ldflags parameters.
// See: https://stackoverflow.com/a/11355611
gitSha1 string
)
// commandError is an error type to wrap os/exec.Command errors. This provides
// some more information regarding what went wrong while running a command.
type commandError struct {
@@ -142,27 +147,7 @@ func Build(pkgName, outpath string, options *compileopts.Options) error {
return err
}
if options.PrintJSON {
b, err := json.MarshalIndent(config, "", " ")
if err != nil {
handleCompilerError(err)
}
fmt.Printf("%s\n", string(b))
return nil
}
return builder.Build(pkgName, outpath, config, func(result builder.BuildResult) error {
if outpath == "" {
if strings.HasSuffix(pkgName, ".go") {
// A Go file was specified directly on the command line.
// Base the binary name off of it.
outpath = filepath.Base(pkgName[:len(pkgName)-3]) + config.DefaultBinaryExtension()
} else {
// Pick a default output path based on the main directory.
outpath = filepath.Base(result.MainDir) + config.DefaultBinaryExtension()
}
}
if err := os.Rename(result.Binary, outpath); err != nil {
// Moving failed. Do a file copy.
inf, err := os.Open(result.Binary)
@@ -192,14 +177,14 @@ func Build(pkgName, outpath string, options *compileopts.Options) error {
// Test runs the tests in the given package. Returns whether the test passed and
// possibly an error if the test failed to run.
func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options, testCompileOnly, testVerbose, testShort bool, testRunRegexp string, testBenchRegexp string, testBenchTime string, outpath string) (bool, error) {
func Test(pkgName string, options *compileopts.Options, testCompileOnly, testVerbose, testShort bool, testRunRegexp string, outpath string) (bool, error) {
options.TestConfig.CompileTestBinary = true
config, err := builder.NewConfig(options)
if err != nil {
return false, err
}
passed := false
passed := true
err = builder.Build(pkgName, outpath, config, func(result builder.BuildResult) error {
if testCompileOnly || outpath != "" {
// Write test binary to the specified file name.
@@ -212,18 +197,13 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
}
if testCompileOnly {
// Do not run the test.
passed = true
return nil
}
// Run the test.
config.Options.Semaphore <- struct{}{}
defer func() {
<-config.Options.Semaphore
}()
start := time.Now()
var err error
passed, err = runPackageTest(config, stdout, stderr, result, testVerbose, testShort, testRunRegexp, testBenchRegexp, testBenchTime)
passed, err = runPackageTest(config, result, testVerbose, testShort, testRunRegexp)
if err != nil {
return err
}
@@ -232,40 +212,26 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
// Print the result.
importPath := strings.TrimSuffix(result.ImportPath, ".test")
if passed {
fmt.Fprintf(stdout, "ok \t%s\t%.3fs\n", importPath, duration.Seconds())
fmt.Printf("ok \t%s\t%.3fs\n", importPath, duration.Seconds())
} else {
fmt.Fprintf(stdout, "FAIL\t%s\t%.3fs\n", importPath, duration.Seconds())
fmt.Printf("FAIL\t%s\t%.3fs\n", importPath, duration.Seconds())
}
return nil
})
if err, ok := err.(loader.NoTestFilesError); ok {
fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", err.ImportPath)
fmt.Printf("? \t%s\t[no test files]\n", err.ImportPath)
// Pretend the test passed - it at least didn't fail.
return true, nil
}
return passed, err
}
func dirsToModuleRoot(maindir, modroot string) []string {
var dirs = []string{"."}
last := ".."
// strip off path elements until we hit the module root
// adding `..`, `../..`, `../../..` until we're done
for maindir != modroot {
dirs = append(dirs, last)
last = filepath.Join(last, "..")
maindir = filepath.Dir(maindir)
}
return dirs
}
// runPackageTest runs a test binary that was previously built. The return
// values are whether the test passed and any errors encountered while trying to
// run the binary.
func runPackageTest(config *compileopts.Config, stdout, stderr io.Writer, result builder.BuildResult, testVerbose, testShort bool, testRunRegexp string, testBenchRegexp string, testBenchTime string) (bool, error) {
func runPackageTest(config *compileopts.Config, result builder.BuildResult, testVerbose, testShort bool, testRunRegexp string) (bool, error) {
var cmd *exec.Cmd
emulator := config.Emulator()
if len(emulator) == 0 {
if len(config.Target.Emulator) == 0 {
// Run directly.
var flags []string
if testVerbose {
@@ -277,33 +243,15 @@ func runPackageTest(config *compileopts.Config, stdout, stderr io.Writer, result
if testRunRegexp != "" {
flags = append(flags, "-test.run="+testRunRegexp)
}
if testBenchRegexp != "" {
flags = append(flags, "-test.bench="+testBenchRegexp)
}
if testBenchTime != "" {
flags = append(flags, "-test.benchtime="+testBenchTime)
}
cmd = executeCommand(config.Options, result.Binary, flags...)
cmd.Dir = result.MainDir
} else {
// Run in an emulator.
args := append(emulator[1:], result.Binary)
if emulator[0] == "wasmtime" {
// create a new temp directory just for this run, announce it to os.TempDir() via TMPDIR
tmpdir, err := ioutil.TempDir("", "tinygotmp")
if err != nil {
return false, &commandError{"failed to create temporary directory", "tinygotmp", err}
}
args = append(args, "--dir="+tmpdir, "--env=TMPDIR="+tmpdir)
// TODO: add option to not delete temp dir for debugging?
defer os.RemoveAll(tmpdir)
// allow reading from directories up to module root
for _, d := range dirsToModuleRoot(result.MainDir, result.ModuleRoot) {
args = append(args, "--dir="+d)
}
args := append(config.Target.Emulator[1:], result.Binary)
if config.Target.Emulator[0] == "wasmtime" {
// allow reading from current directory: --dir=.
// mark end of wasmtime arguments and start of program ones: --
args = append(args, "--")
args = append(args, "--dir=.", "--")
if testVerbose {
args = append(args, "-test.v")
}
@@ -313,15 +261,11 @@ func runPackageTest(config *compileopts.Config, stdout, stderr io.Writer, result
if testRunRegexp != "" {
args = append(args, "-test.run="+testRunRegexp)
}
if testBenchRegexp != "" {
args = append(args, "-test.bench="+testBenchRegexp)
}
}
cmd = executeCommand(config.Options, emulator[0], args...)
cmd = executeCommand(config.Options, config.Target.Emulator[0], args...)
}
cmd.Dir = result.MainDir
cmd.Stdout = stdout
cmd.Stderr = stderr
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
if _, ok := err.(*exec.ExitError); ok {
@@ -515,13 +459,12 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
gdbInterface, openocdInterface := config.Programmer()
switch gdbInterface {
case "msd", "command", "":
emulator := config.Emulator()
if len(emulator) != 0 {
if emulator[0] == "mgba" {
if len(config.Target.Emulator) != 0 {
if config.Target.Emulator[0] == "mgba" {
gdbInterface = "mgba"
} else if emulator[0] == "simavr" {
} else if config.Target.Emulator[0] == "simavr" {
gdbInterface = "simavr"
} else if strings.HasPrefix(emulator[0], "qemu-system-") {
} else if strings.HasPrefix(config.Target.Emulator[0], "qemu-system-") {
gdbInterface = "qemu"
} else {
// Assume QEMU as an emulator.
@@ -589,34 +532,34 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
}
case "qemu":
port = ":1234"
emulator := config.Emulator()
// Run in an emulator.
args := append(emulator[1:], result.Binary, "-s", "-S")
daemon = executeCommand(config.Options, emulator[0], args...)
args := append(config.Target.Emulator[1:], result.Binary, "-s", "-S")
daemon = executeCommand(config.Options, config.Target.Emulator[0], args...)
daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr
case "qemu-user":
port = ":1234"
emulator := config.Emulator()
// Run in an emulator.
args := append(emulator[1:], "-g", "1234", result.Binary)
daemon = executeCommand(config.Options, emulator[0], args...)
args := append(config.Target.Emulator[1:], "-g", "1234", result.Binary)
daemon = executeCommand(config.Options, config.Target.Emulator[0], args...)
daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr
case "mgba":
port = ":2345"
emulator := config.Emulator()
// Run in an emulator.
args := append(emulator[1:], result.Binary, "-g")
daemon = executeCommand(config.Options, emulator[0], args...)
args := append(config.Target.Emulator[1:], result.Binary, "-g")
daemon = executeCommand(config.Options, config.Target.Emulator[0], args...)
daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr
case "simavr":
port = ":1234"
emulator := config.Emulator()
// Run in an emulator.
args := append(emulator[1:], "-g", result.Binary)
daemon = executeCommand(config.Options, emulator[0], args...)
args := append(config.Target.Emulator[1:], "-g", result.Binary)
daemon = executeCommand(config.Options, config.Target.Emulator[0], args...)
daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr
case "msd":
@@ -711,8 +654,7 @@ func Run(pkgName string, options *compileopts.Options) error {
}
return builder.Build(pkgName, ".elf", config, func(result builder.BuildResult) error {
emulator := config.Emulator()
if len(emulator) == 0 {
if len(config.Target.Emulator) == 0 {
// Run directly.
cmd := executeCommand(config.Options, result.Binary)
cmd.Stdout = os.Stdout
@@ -728,8 +670,8 @@ func Run(pkgName string, options *compileopts.Options) error {
return nil
} else {
// Run in an emulator.
args := append(emulator[1:], result.Binary)
cmd := executeCommand(config.Options, emulator[0], args...)
args := append(config.Target.Emulator[1:], result.Binary)
cmd := executeCommand(config.Options, config.Target.Emulator[0], args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
@@ -777,12 +719,7 @@ func flashUF2UsingMSD(volume, tmppath string, options *compileopts.Options) erro
var infoPath string
switch runtime.GOOS {
case "linux", "freebsd":
fi, err := os.Stat("/run/media")
if err != nil || !fi.IsDir() {
infoPath = "/media/*/" + volume + "/INFO_UF2.TXT"
} else {
infoPath = "/run/media/*/" + volume + "/INFO_UF2.TXT"
}
infoPath = "/media/*/" + volume + "/INFO_UF2.TXT"
case "darwin":
infoPath = "/Volumes/" + volume + "/INFO_UF2.TXT"
case "windows":
@@ -806,12 +743,7 @@ func flashHexUsingMSD(volume, tmppath string, options *compileopts.Options) erro
var destPath string
switch runtime.GOOS {
case "linux", "freebsd":
fi, err := os.Stat("/run/media")
if err != nil || !fi.IsDir() {
destPath = "/media/*/" + volume
} else {
destPath = "/run/media/*/" + volume
}
destPath = "/media/*/" + volume
case "darwin":
destPath = "/Volumes/" + volume
case "windows":
@@ -1026,8 +958,8 @@ func getBMPPorts() (gdbPort, uartPort string, err error) {
func usage(command string) {
version := goenv.Version
if strings.HasSuffix(version, "-dev") && goenv.GitSha1 != "" {
version += "-" + goenv.GitSha1
if strings.HasSuffix(version, "-dev") && gitSha1 != "" {
version += "-" + gitSha1
}
switch command {
@@ -1113,6 +1045,15 @@ func printCompilerError(logln func(...interface{}), err error) {
logln()
}
}
case transform.CoroutinesError:
logln(err.Pos.String() + ": " + err.Msg)
logln("\ntraceback:")
for _, line := range err.Traceback {
logln(line.Name)
if line.Position.IsValid() {
logln("\t" + line.Position.String())
}
}
case loader.Errors:
logln("#", err.Pkg.ImportPath)
for _, err := range err.Errs {
@@ -1197,11 +1138,10 @@ func main() {
command := os.Args[1]
opt := flag.String("opt", "z", "optimization level: 0, 1, 2, s, z")
gc := flag.String("gc", "", "garbage collector to use (none, leaking, conservative)")
gc := flag.String("gc", "", "garbage collector to use (none, leaking, extalloc, conservative)")
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
scheduler := flag.String("scheduler", "", "which scheduler to use (none, tasks, asyncify)")
scheduler := flag.String("scheduler", "", "which scheduler to use (none, coroutines, tasks, asyncify)")
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")
printIR := flag.Bool("printir", false, "print LLVM IR")
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR")
@@ -1222,29 +1162,23 @@ func main() {
llvmFeatures := flag.String("llvm-features", "", "comma separated LLVM features to enable")
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
var flagJSON, flagDeps, flagTest bool
if command == "help" || command == "list" || command == "info" || command == "build" {
flag.BoolVar(&flagJSON, "json", false, "print data in JSON format")
}
var flagJSON, flagDeps, flagTest *bool
if command == "help" || command == "list" {
flag.BoolVar(&flagDeps, "deps", false, "supply -deps flag to go list")
flag.BoolVar(&flagTest, "test", false, "supply -test flag to go list")
flagJSON = flag.Bool("json", false, "print data in JSON format")
flagDeps = flag.Bool("deps", false, "supply -deps flag to go list")
flagTest = flag.Bool("test", false, "supply -test flag to go list")
}
var outpath string
if command == "help" || command == "build" || command == "build-library" || command == "test" {
flag.StringVar(&outpath, "o", "", "output filename")
}
var testCompileOnlyFlag, testVerboseFlag, testShortFlag *bool
var testBenchRegexp *string
var testBenchTime *string
var testRunRegexp *string
if command == "help" || command == "test" {
testCompileOnlyFlag = flag.Bool("c", false, "compile the test binary but do not run it")
testVerboseFlag = flag.Bool("v", false, "verbose: print additional output")
testShortFlag = flag.Bool("short", false, "short: run smaller test suite to save time")
testRunRegexp = flag.String("run", "", "run: regexp of tests to run")
testBenchRegexp = flag.String("bench", "", "run: regexp of benchmarks to run")
testBenchTime = flag.String("benchtime", "", "run each benchmark for duration `d`")
}
// Early command processing, before commands are interpreted by the Go flag
@@ -1290,11 +1224,10 @@ func main() {
PanicStrategy: *panicStrategy,
Scheduler: *scheduler,
Serial: *serial,
Work: *work,
PrintIR: *printIR,
DumpSSA: *dumpSSA,
VerifyIR: *verifyIR,
Semaphore: make(chan struct{}, *parallelism),
Parallelism: *parallelism,
Debug: !*nodebug,
PrintSizes: *printSize,
PrintStacks: *printStacks,
@@ -1305,7 +1238,6 @@ func main() {
Programmer: *programmer,
OpenOCDCommands: ocdCommands,
LLVMFeatures: *llvmFeatures,
PrintJSON: flagJSON,
}
if *printCommands {
options.PrintCommands = printCommand
@@ -1334,6 +1266,11 @@ func main() {
switch command {
case "build":
if outpath == "" {
fmt.Fprintln(os.Stderr, "No output filename supplied (-o).")
usage(command)
os.Exit(1)
}
pkgName := "."
if flag.NArg() == 1 {
pkgName = filepath.ToSlash(flag.Arg(0))
@@ -1378,13 +1315,11 @@ func main() {
handleCompilerError(err)
}
defer os.RemoveAll(tmpdir)
spec, err := compileopts.LoadTarget(options)
if err != nil {
handleCompilerError(err)
}
config := &compileopts.Config{
Options: options,
Target: spec,
Target: &compileopts.TargetSpec{
Triple: *target,
},
}
path, err := lib.Load(config, tmpdir)
handleCompilerError(err)
@@ -1423,69 +1358,16 @@ func main() {
if len(pkgNames) == 0 {
pkgNames = []string{"."}
}
if outpath != "" && len(pkgNames) > 1 {
fmt.Println("cannot use -o flag with multiple packages")
os.Exit(1)
}
fail := make(chan struct{}, 1)
var wg sync.WaitGroup
bufs := make([]testOutputBuf, len(pkgNames))
for i := range bufs {
bufs[i].done = make(chan struct{})
}
wg.Add(1)
go func() {
defer wg.Done()
// Flush the output one test at a time.
// This ensures that outputs from different tests are not mixed together.
for i := range bufs {
err := bufs[i].flush(os.Stdout, os.Stderr)
if err != nil {
// There was an error writing to stdout or stderr, so we probbably cannot print this.
select {
case fail <- struct{}{}:
default:
}
}
allTestsPassed := true
for _, pkgName := range pkgNames {
// TODO: parallelize building the test binaries
passed, err := Test(pkgName, options, *testCompileOnlyFlag, *testVerboseFlag, *testShortFlag, *testRunRegexp, outpath)
handleCompilerError(err)
if !passed {
allTestsPassed = false
}
}()
// Build and run the tests concurrently.
// This uses an additional semaphore to reduce the memory usage.
testSema := make(chan struct{}, cap(options.Semaphore))
for i, pkgName := range pkgNames {
pkgName := pkgName
buf := &bufs[i]
testSema <- struct{}{}
wg.Add(1)
go func() {
defer wg.Done()
defer func() { <-testSema }()
defer close(buf.done)
stdout := (*testStdout)(buf)
stderr := (*testStderr)(buf)
passed, err := Test(pkgName, stdout, stderr, options, *testCompileOnlyFlag, *testVerboseFlag, *testShortFlag, *testRunRegexp, *testBenchRegexp, *testBenchTime, outpath)
if err != nil {
printCompilerError(func(args ...interface{}) {
fmt.Fprintln(stderr, args...)
}, err)
}
if !passed {
select {
case fail <- struct{}{}:
default:
}
}
}()
}
// Wait for all tests to finish.
wg.Wait()
close(fail)
if _, fail := <-fail; fail {
if !allTestsPassed {
fmt.Println("FAIL")
os.Exit(1)
}
@@ -1542,37 +1424,14 @@ func main() {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
if flagJSON {
json, _ := json.MarshalIndent(struct {
GOROOT string `json:"goroot"`
GOOS string `json:"goos"`
GOARCH string `json:"goarch"`
GOARM string `json:"goarm"`
BuildTags []string `json:"build_tags"`
GC string `json:"garbage_collector"`
Scheduler string `json:"scheduler"`
LLVMTriple string `json:"llvm_triple"`
}{
GOROOT: cachedGOROOT,
GOOS: config.GOOS(),
GOARCH: config.GOARCH(),
GOARM: config.GOARM(),
BuildTags: config.BuildTags(),
GC: config.GC(),
Scheduler: config.Scheduler(),
LLVMTriple: config.Triple(),
}, "", " ")
fmt.Println(string(json))
} else {
fmt.Printf("LLVM triple: %s\n", config.Triple())
fmt.Printf("GOOS: %s\n", config.GOOS())
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("garbage collector: %s\n", config.GC())
fmt.Printf("scheduler: %s\n", config.Scheduler())
fmt.Printf("cached GOROOT: %s\n", cachedGOROOT)
}
fmt.Printf("LLVM triple: %s\n", config.Triple())
fmt.Printf("GOOS: %s\n", config.GOOS())
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("garbage collector: %s\n", config.GC())
fmt.Printf("scheduler: %s\n", config.Scheduler())
fmt.Printf("cached GOROOT: %s\n", cachedGOROOT)
case "list":
config, err := builder.NewConfig(options)
if err != nil {
@@ -1581,13 +1440,13 @@ func main() {
os.Exit(1)
}
var extraArgs []string
if flagJSON {
if *flagJSON {
extraArgs = append(extraArgs, "-json")
}
if flagDeps {
if *flagDeps {
extraArgs = append(extraArgs, "-deps")
}
if flagTest {
if *flagTest {
extraArgs = append(extraArgs, "-test")
}
cmd, err := loader.List(config, extraArgs, flag.Args())
@@ -1624,8 +1483,8 @@ func main() {
goversion = s
}
version := goenv.Version
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
version += "-" + goenv.GitSha1
if strings.HasSuffix(goenv.Version, "-dev") && gitSha1 != "" {
version += "-" + gitSha1
}
fmt.Printf("tinygo version %s %s/%s (using go version %s and LLVM version %s)\n", version, runtime.GOOS, runtime.GOARCH, goversion, llvm.Version)
case "env":
@@ -1646,117 +1505,3 @@ func main() {
os.Exit(1)
}
}
// testOutputBuf is used to buffer the output of concurrent tests.
type testOutputBuf struct {
mu sync.Mutex
output []outputEntry
stdout, stderr io.Writer
outerr, errerr error
done chan struct{}
}
// flush the output to stdout and stderr.
// This waits until done is closed.
func (b *testOutputBuf) flush(stdout, stderr io.Writer) error {
b.mu.Lock()
var err error
b.stdout = stdout
b.stderr = stderr
for _, e := range b.output {
var w io.Writer
var errDst *error
if e.stderr {
w = stderr
errDst = &b.errerr
} else {
w = stdout
errDst = &b.outerr
}
if *errDst != nil {
continue
}
_, werr := w.Write(e.data)
if werr != nil {
if err == nil {
err = werr
}
*errDst = err
}
}
b.mu.Unlock()
<-b.done
return err
}
// testStdout writes stdout from a test to the output buffer.
type testStdout testOutputBuf
func (out *testStdout) Write(data []byte) (int, error) {
buf := (*testOutputBuf)(out)
buf.mu.Lock()
if buf.stdout != nil {
// Write the output directly.
err := out.outerr
buf.mu.Unlock()
if err != nil {
return 0, err
}
return buf.stdout.Write(data)
}
defer buf.mu.Unlock()
// Append the output.
if len(buf.output) == 0 || buf.output[len(buf.output)-1].stderr {
buf.output = append(buf.output, outputEntry{
stderr: false,
})
}
last := &buf.output[len(buf.output)-1]
last.data = append(last.data, data...)
return len(data), nil
}
// testStderr writes stderr from a test to the output buffer.
type testStderr testOutputBuf
func (out *testStderr) Write(data []byte) (int, error) {
buf := (*testOutputBuf)(out)
buf.mu.Lock()
if buf.stderr != nil {
// Write the output directly.
err := out.errerr
buf.mu.Unlock()
if err != nil {
return 0, err
}
return buf.stderr.Write(data)
}
defer buf.mu.Unlock()
// Append the output.
if len(buf.output) == 0 || !buf.output[len(buf.output)-1].stderr {
buf.output = append(buf.output, outputEntry{
stderr: true,
})
}
last := &buf.output[len(buf.output)-1]
last.data = append(last.data, data...)
return len(data), nil
}
type outputEntry struct {
stderr bool
data []byte
}
+100 -328
View File
@@ -6,16 +6,12 @@ package main
import (
"bufio"
"bytes"
"context"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strings"
"sync"
@@ -31,18 +27,7 @@ const TESTDATA = "testdata"
var testTarget = flag.String("target", "", "override test target")
var supportedLinuxArches = map[string]string{
"AMD64Linux": "linux/amd64",
"X86Linux": "linux/386",
"ARMLinux": "linux/arm/6",
"ARM64Linux": "linux/arm64",
}
var sema = make(chan struct{}, runtime.NumCPU())
func TestBuild(t *testing.T) {
t.Parallel()
func TestCompiler(t *testing.T) {
tests := []string{
"alias.go",
"atomic.go",
@@ -69,6 +54,7 @@ func TestBuild(t *testing.T) {
"testing.go",
"zeroalloc.go",
}
_, minor, err := goenv.GetGorootVersion(goenv.Get("GOROOT"))
if err != nil {
t.Fatal("could not read version from GOROOT:", err)
@@ -81,13 +67,12 @@ func TestBuild(t *testing.T) {
// This makes it possible to run one specific test (instead of all),
// which is especially useful to quickly check whether some changes
// affect a particular target architecture.
runPlatTests(optionsFromTarget(*testTarget, sema), tests, t)
runPlatTests(optionsFromTarget(*testTarget), tests, t)
return
}
t.Run("Host", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("", sema), tests, t)
runPlatTests(optionsFromTarget(""), tests, t)
})
// Test a few build options.
@@ -97,29 +82,38 @@ func TestBuild(t *testing.T) {
// Test with few optimizations enabled (no inlining, etc).
t.Run("opt=1", func(t *testing.T) {
t.Parallel()
opts := optionsFromTarget("", sema)
opts.Opt = "1"
runTestWithConfig("stdlib.go", t, opts, nil, nil)
runTestWithConfig("stdlib.go", t, compileopts.Options{
GOOS: goenv.Get("GOOS"),
GOARCH: goenv.Get("GOARCH"),
GOARM: goenv.Get("GOARM"),
Opt: "1",
}, nil, nil)
})
// Test with only the bare minimum of optimizations enabled.
// TODO: fix this for stdlib.go, which currently fails.
t.Run("opt=0", func(t *testing.T) {
t.Parallel()
opts := optionsFromTarget("", sema)
opts.Opt = "0"
runTestWithConfig("print.go", t, opts, nil, nil)
runTestWithConfig("print.go", t, compileopts.Options{
GOOS: goenv.Get("GOOS"),
GOARCH: goenv.Get("GOARCH"),
GOARM: goenv.Get("GOARM"),
Opt: "0",
}, nil, nil)
})
t.Run("ldflags", func(t *testing.T) {
t.Parallel()
opts := optionsFromTarget("", sema)
opts.GlobalValues = map[string]map[string]string{
"main": {
"someGlobal": "foobar",
runTestWithConfig("ldflags.go", t, compileopts.Options{
GOOS: goenv.Get("GOOS"),
GOARCH: goenv.Get("GOARCH"),
GOARM: goenv.Get("GOARM"),
GlobalValues: map[string]map[string]string{
"main": {
"someGlobal": "foobar",
},
},
}
runTestWithConfig("ldflags.go", t, opts, nil, nil)
}, nil, nil)
})
})
@@ -130,89 +124,34 @@ func TestBuild(t *testing.T) {
}
t.Run("EmulatedCortexM3", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("cortex-m-qemu", sema), tests, t)
runPlatTests(optionsFromTarget("cortex-m-qemu"), tests, t)
})
t.Run("EmulatedRISCV", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("riscv-qemu", sema), tests, t)
})
t.Run("AVR", func(t *testing.T) {
// LLVM backend crash:
// LIBCLANG FATAL ERROR: Cannot select: t3: i16 = JumpTable<0>
// This bug is non-deterministic.
t.Skip("skipped due to non-deterministic backend bugs")
var avrTests []string
for _, t := range tests {
switch t {
case "atomic.go":
// Requires GCC 11.2.0 or above for interface comparison.
// https://github.com/gcc-mirror/gcc/commit/f30dd607669212de135dec1f1d8a93b8954c327c
case "reflect.go":
// Reflect tests do not work due to type code issues.
case "gc.go":
// Does not pass due to high mark false positive rate.
case "json.go", "stdlib.go", "testing.go":
// Breaks interp.
case "map.go":
// Reflect size calculation crashes.
case "binop.go":
// Interface comparison results are inverted.
case "channel.go":
// Freezes after recv from closed channel.
case "float.go", "math.go", "print.go":
// Stuck in runtime.printfloat64.
case "interface.go":
// Several comparison tests fail.
case "cgo/":
// CGo does not work on AVR.
default:
avrTests = append(avrTests, t)
}
}
runPlatTests(optionsFromTarget("simavr", sema), avrTests, t)
runPlatTests(optionsFromTarget("riscv-qemu"), tests, t)
})
if runtime.GOOS == "linux" {
for name, osArch := range supportedLinuxArches {
options := optionsFromOSARCH(osArch, sema)
if options.GOARCH != runtime.GOARCH { // Native architecture already run above.
t.Run(name, func(t *testing.T) {
runPlatTests(options, tests, t)
})
}
}
t.Run("X86Linux", func(t *testing.T) {
runPlatTests(optionsFromOSARCH("linux/386"), tests, t)
})
t.Run("ARMLinux", func(t *testing.T) {
runPlatTests(optionsFromOSARCH("linux/arm/6"), tests, t)
})
t.Run("ARM64Linux", func(t *testing.T) {
runPlatTests(optionsFromOSARCH("linux/arm64"), tests, t)
})
t.Run("WebAssembly", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("wasm", sema), tests, t)
runPlatTests(optionsFromTarget("wasm"), tests, t)
})
t.Run("WASI", func(t *testing.T) {
t.Parallel()
runPlatTests(optionsFromTarget("wasi", sema), tests, t)
runPlatTests(optionsFromTarget("wasi"), tests, t)
})
}
}
func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
emuCheck(t, options)
spec, err := compileopts.LoadTarget(&options)
if err != nil {
t.Fatal("failed to load target spec:", err)
}
t.Parallel()
for _, name := range tests {
name := name // redefine to avoid race condition
@@ -221,12 +160,10 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
runTest(name, options, t, nil, nil)
})
}
if len(spec.Emulator) == 0 || spec.Emulator[0] != "simavr" {
t.Run("env.go", func(t *testing.T) {
t.Parallel()
runTest("env.go", options, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"})
})
}
t.Run("env.go", func(t *testing.T) {
t.Parallel()
runTest("env.go", options, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"})
})
if options.Target == "wasi" || options.Target == "wasm" {
t.Run("alias.go-scheduler-none", func(t *testing.T) {
t.Parallel()
@@ -249,51 +186,36 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
}
}
func emuCheck(t *testing.T, options compileopts.Options) {
// Check if the emulator is installed.
spec, err := compileopts.LoadTarget(&options)
if err != nil {
t.Fatal("failed to load target spec:", err)
}
if len(spec.Emulator) != 0 {
_, err := exec.LookPath(spec.Emulator[0])
if err != nil {
if errors.Is(err, exec.ErrNotFound) {
t.Skipf("emulator not installed: %q", spec.Emulator[0])
}
// Due to some problems with LLD, we cannot run links in parallel, or in parallel with compiles.
// Therefore, we put a lock around builds and run everything else in parallel.
var buildLock sync.Mutex
t.Errorf("searching for emulator: %v", err)
return
}
}
// runBuild is a thread-safe wrapper around Build.
func runBuild(src, out string, opts *compileopts.Options) error {
buildLock.Lock()
defer buildLock.Unlock()
return Build(src, out, opts)
}
func optionsFromTarget(target string, sema chan struct{}) compileopts.Options {
func optionsFromTarget(target string) compileopts.Options {
return compileopts.Options{
// GOOS/GOARCH are only used if target == ""
GOOS: goenv.Get("GOOS"),
GOARCH: goenv.Get("GOARCH"),
GOARM: goenv.Get("GOARM"),
Target: target,
Semaphore: sema,
Debug: true,
VerifyIR: true,
Opt: "z",
GOOS: goenv.Get("GOOS"),
GOARCH: goenv.Get("GOARCH"),
GOARM: goenv.Get("GOARM"),
Target: target,
}
}
// optionsFromOSARCH returns a set of options based on the "osarch" string. This
// string is in the form of "os/arch/subarch", with the subarch only sometimes
// being necessary. Examples are "darwin/amd64" or "linux/arm/7".
func optionsFromOSARCH(osarch string, sema chan struct{}) compileopts.Options {
func optionsFromOSARCH(osarch string) compileopts.Options {
parts := strings.Split(osarch, "/")
options := compileopts.Options{
GOOS: parts[0],
GOARCH: parts[1],
Semaphore: sema,
Debug: true,
VerifyIR: true,
Opt: "z",
GOOS: parts[0],
GOARCH: parts[1],
}
if options.GOARCH == "arm" {
options.GOARM = parts[2]
@@ -306,6 +228,13 @@ func runTest(name string, options compileopts.Options, t *testing.T, cmdArgs, en
}
func runTestWithConfig(name string, t *testing.T, options compileopts.Options, cmdArgs, environmentVars []string) {
// Set default config.
options.Debug = true
options.VerifyIR = true
if options.Opt == "" {
options.Opt = "z"
}
// Get the expected output for this test.
// Note: not using filepath.Join as it strips the path separator at the end
// of the path.
@@ -364,35 +293,22 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
if spec.GOOS == "windows" {
binary += ".exe"
}
err = Build("./"+path, binary, &options)
err = runBuild("./"+path, binary, &options)
if err != nil {
printCompilerError(t.Log, err)
t.Fail()
return
}
// Reserve CPU time for the test to run.
// This attempts to ensure that the test is not CPU-starved.
options.Semaphore <- struct{}{}
defer func() { <-options.Semaphore }()
// Create the test command, taking care of emulators etc.
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
var cmd *exec.Cmd
// make sure any special vars in the emulator definition are rewritten
config := compileopts.Config{Target: spec}
emulator := config.Emulator()
if len(emulator) == 0 {
cmd = exec.CommandContext(ctx, binary)
if len(spec.Emulator) == 0 {
cmd = exec.Command(binary)
} else {
args := append(emulator[1:], binary)
cmd = exec.CommandContext(ctx, emulator[0], args...)
args := append(spec.Emulator[1:], binary)
cmd = exec.Command(spec.Emulator[0], args...)
}
if len(emulator) != 0 && emulator[0] == "wasmtime" {
if len(spec.Emulator) != 0 && spec.Emulator[0] == "wasmtime" {
// Allow reading from the current directory.
cmd.Args = append(cmd.Args, "--dir=.")
for _, v := range environmentVars {
@@ -407,41 +323,47 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
}
// Run the test.
runComplete := make(chan struct{})
ranTooLong := false
stdout := &bytes.Buffer{}
if len(emulator) != 0 && emulator[0] == "simavr" {
cmd.Stdout = os.Stderr
cmd.Stderr = stdout
} else {
cmd.Stdout = stdout
cmd.Stderr = os.Stderr
}
cmd.Stdout = stdout
cmd.Stderr = os.Stderr
err = cmd.Start()
if err != nil {
t.Fatal("failed to start:", err)
}
go func() {
// Terminate the process if it runs too long.
maxDuration := 10 * time.Second
if runtime.GOOS == "windows" {
// For some reason, tests on Windows can take around
// 30s to complete. TODO: investigate why and fix this.
maxDuration = 40 * time.Second
}
timer := time.NewTimer(maxDuration)
select {
case <-runComplete:
timer.Stop()
case <-timer.C:
ranTooLong = true
if runtime.GOOS == "windows" {
cmd.Process.Signal(os.Kill) // Windows doesn't support SIGINT.
} else {
cmd.Process.Signal(os.Interrupt)
}
}
}()
err = cmd.Wait()
close(runComplete)
if cerr := ctx.Err(); cerr == context.DeadlineExceeded {
if ranTooLong {
stdout.WriteString("--- test ran too long, terminating...\n")
err = cerr
}
// putchar() prints CRLF, convert it to LF.
actual := bytes.Replace(stdout.Bytes(), []byte{'\r', '\n'}, []byte{'\n'}, -1)
expected = bytes.Replace(expected, []byte{'\r', '\n'}, []byte{'\n'}, -1) // for Windows
if len(emulator) != 0 && emulator[0] == "simavr" {
// Strip simavr log formatting.
actual = bytes.Replace(actual, []byte{0x1b, '[', '3', '2', 'm'}, nil, -1)
actual = bytes.Replace(actual, []byte{0x1b, '[', '0', 'm'}, nil, -1)
actual = bytes.Replace(actual, []byte{'.', '.', '\n'}, []byte{'\n'}, -1)
}
if name == "testing.go" {
// Strip actual time.
re := regexp.MustCompile(`\([0-9]\.[0-9][0-9]s\)`)
actual = re.ReplaceAllLiteral(actual, []byte{'(', '0', '.', '0', '0', 's', ')'})
}
// Check whether the command ran successfully.
fail := false
if err != nil {
@@ -465,156 +387,6 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
}
}
func TestTest(t *testing.T) {
t.Parallel()
type targ struct {
name string
opts compileopts.Options
}
targs := []targ{
// Host
{"Host", optionsFromTarget("", sema)},
}
if !testing.Short() {
if runtime.GOOS == "linux" {
for name, osArch := range supportedLinuxArches {
options := optionsFromOSARCH(osArch, sema)
if options.GOARCH != runtime.GOARCH { // Native architecture already run above.
targs = append(targs, targ{name, options})
}
}
}
targs = append(targs,
// QEMU microcontrollers
targ{"EmulatedCortexM3", optionsFromTarget("cortex-m-qemu", sema)},
targ{"EmulatedRISCV", optionsFromTarget("riscv-qemu", sema)},
// Node/Wasmtime
targ{"WASM", optionsFromTarget("wasm", sema)},
targ{"WASI", optionsFromTarget("wasi", sema)},
)
}
for _, targ := range targs {
targ := targ
t.Run(targ.name, func(t *testing.T) {
t.Parallel()
emuCheck(t, targ.opts)
t.Run("Pass", func(t *testing.T) {
t.Parallel()
// Test a package which builds and passes normally.
var wg sync.WaitGroup
defer wg.Wait()
out := ioLogger(t, &wg)
defer out.Close()
opts := targ.opts
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/pass", out, out, &opts, false, false, false, "", "", "", "")
if err != nil {
t.Errorf("test error: %v", err)
}
if !passed {
t.Error("test failed")
}
})
t.Run("Fail", func(t *testing.T) {
t.Parallel()
// Test a package which builds fine but fails.
var wg sync.WaitGroup
defer wg.Wait()
out := ioLogger(t, &wg)
defer out.Close()
opts := targ.opts
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/fail", out, out, &opts, false, false, false, "", "", "", "")
if err != nil {
t.Errorf("test error: %v", err)
}
if passed {
t.Error("test passed")
}
})
if targ.name != "Host" {
// Emulated tests are somewhat slow, and these do not need to be run across every platform.
return
}
t.Run("Nothing", func(t *testing.T) {
t.Parallel()
// Test a package with no test files.
var wg sync.WaitGroup
defer wg.Wait()
out := ioLogger(t, &wg)
defer out.Close()
var output bytes.Buffer
opts := targ.opts
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/nothing", io.MultiWriter(&output, out), out, &opts, false, false, false, "", "", "", "")
if err != nil {
t.Errorf("test error: %v", err)
}
if !passed {
t.Error("test failed")
}
if !strings.Contains(output.String(), "[no test files]") {
t.Error("missing [no test files] in output")
}
})
t.Run("BuildErr", func(t *testing.T) {
t.Parallel()
// Test a package which fails to build.
var wg sync.WaitGroup
defer wg.Wait()
out := ioLogger(t, &wg)
defer out.Close()
opts := targ.opts
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/builderr", out, out, &opts, false, false, false, "", "", "", "")
if err == nil {
t.Error("test did not error")
}
if passed {
t.Error("test passed")
}
})
})
}
}
func ioLogger(t *testing.T, wg *sync.WaitGroup) io.WriteCloser {
r, w := io.Pipe()
wg.Add(1)
go func() {
defer wg.Done()
defer r.Close()
scanner := bufio.NewScanner(r)
for scanner.Scan() {
t.Log(scanner.Text())
}
}()
return w
}
// This TestMain is necessary because TinyGo may also be invoked to run certain
// LLVM tools in a separate process. Not capturing these invocations would lead
// to recursive tests.
+218
View File
@@ -0,0 +1,218 @@
package main
import (
"bufio"
"bytes"
"crypto/md5"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"golang.org/x/sync/errgroup"
)
func main() {
threads := runtime.NumCPU()
if j, ok := os.LookupEnv(`RUN_SMOKETEST_JOBS`); ok {
n, err := strconv.ParseInt(j, 0, 0)
if err == nil {
threads = int(n)
}
}
flag.IntVar(&threads, "threads", threads, "threads of make smoketest")
flag.Parse()
if len(os.Args) < 2 {
fmt.Printf("usage: %s make smoketest\n", filepath.Base(os.Args[0]))
os.Exit(1)
}
commands, err := getMakeCommands(flag.Args())
if err != nil {
log.Fatalf(err.Error())
}
err = run(commands, threads)
if err != nil {
log.Fatalf(err.Error())
}
}
func getMakeCommands(args []string) ([]string, error) {
var buf bytes.Buffer
cmd := exec.Command(args[0], args[1:]...)
cmd.Args = append(cmd.Args, "-n")
cmd.Stdout = &buf
cmd.Stderr = &buf
err := cmd.Run()
if err != nil {
return nil, err
}
commands := []string{}
scanner := bufio.NewScanner(&buf)
for scanner.Scan() {
line := scanner.Text()
fields := strings.Fields(line)
if filepath.Base(fields[0]) == "tinygo" && (fields[1] == "build" || fields[1] == "version") {
commands = append(commands, line)
} else if strings.HasPrefix(line, "#") {
commands = append(commands, line)
}
}
return commands, nil
}
func run(commands []string, threads int) error {
ch := make(chan string, 1000)
o := NewOchan(ch, 100)
go func() {
limit := make(chan struct{}, threads)
var eg errgroup.Group
for _, command := range commands {
command := command
select {
case limit <- struct{}{}:
och := o.GetCh()
eg.Go(func() error {
var err error
if runtime.GOOS == `windows` {
command = convertToWindowsPath(command)
}
fields := strings.Fields(command)
if filepath.Base(fields[0]) == "tinygo" && fields[1] == "build" {
err = buildAndmd5sum(command, och)
} else if strings.HasPrefix(command, "#") {
och <- fmt.Sprintf("%s\n", command)
} else {
err = runCommand(command, och)
}
close(och)
<-limit
return err
})
}
}
if err := eg.Wait(); err != nil {
log.Fatal(err)
}
o.Wait()
close(ch)
}()
for s := range ch {
fmt.Print(s)
}
return nil
}
func runCommand(command string, ch chan string) error {
var buf bytes.Buffer
fmt.Fprintf(&buf, "%s\n", command)
args := strings.Fields(command)
cmd := exec.Command(args[0], args[1:]...)
cmd.Stdout = &buf
cmd.Stderr = &buf
err := cmd.Run()
if err != nil {
ch <- buf.String()
return err
}
ch <- buf.String()
return nil
}
func buildAndmd5sum(command string, ch chan string) error {
var buf bytes.Buffer
fmt.Fprintf(&buf, "%s\n", command)
args := strings.Fields(command)
output := ""
tmpOutput := ""
tmpdir, err := ioutil.TempDir("", "")
if err != nil {
return err
}
for i := range args {
if args[i] == "-o" {
output = args[i+1]
ext := filepath.Ext(output)
tmpOutput = filepath.Join(tmpdir, fmt.Sprintf("%s.%s", filepath.Base(output), ext))
args[i+1] = tmpOutput
} else if strings.HasPrefix(args[i], "-o=") {
output = args[i][3:]
ext := filepath.Ext(output)
tmpOutput = filepath.Join(tmpdir, fmt.Sprintf("%s.%s", filepath.Base(output), ext))
args[i] = fmt.Sprintf("-o=%s", tmpOutput)
}
}
cmd := exec.Command(args[0], args[1:]...)
cmd.Stdout = &buf
cmd.Stderr = &buf
err = cmd.Run()
if err != nil {
ch <- buf.String()
return err
}
md5str, err := calcMD5(tmpOutput)
if err != nil {
ch <- buf.String()
return err
}
fmt.Fprintf(&buf, "%s %s\n", md5str, output)
ch <- buf.String()
return nil
}
func calcMD5(f string) (string, error) {
r, err := os.Open(f)
if err != nil {
return "", err
}
defer r.Close()
h := md5.New()
if _, err := io.Copy(h, r); err != nil {
return "", err
}
return fmt.Sprintf("%x", h.Sum(nil)), nil
}
func convertToWindowsPath(command string) string {
if !strings.HasPrefix(command, `/`) {
return command
}
command = fmt.Sprintf("%c:%s", command[1], command[2:])
return command
}
+71
View File
@@ -0,0 +1,71 @@
package main
import (
"sync"
)
// An Ochan is a structure for controlling the output order of channels.
type Ochan struct {
out chan string
in chan chan string
done chan struct{}
wg sync.WaitGroup
size int
}
// NewOchan returns a new Ochan struct with specified buffer capacity.
func NewOchan(out chan string, size int) *Ochan {
o := &Ochan{
out: out,
in: make(chan chan string, size),
done: make(chan struct{}, 1),
wg: sync.WaitGroup{},
size: size,
}
go func(o *Ochan) {
for {
select {
case ch, ok := <-o.in:
if !ok {
return
}
for s := range ch {
o.out <- s
}
o.wg.Done()
case <-o.done:
return
}
}
}(o)
return o
}
// GetCh returns a next input channel. The input channel must be explicitly
// closed after use.
func (o *Ochan) GetCh() chan string {
ch := make(chan string, o.size)
o.in <- ch
o.wg.Add(1)
return ch
}
// SetSize sets the capacity of the channel returned by GetCh.
func (o *Ochan) SetSize(size int) {
o.size = size
}
// Wait blocks until it retrieves data from all input channel. All input
// channels must be closed before calling this function.
func (o *Ochan) Wait() error {
o.wg.Wait()
return nil
}
// Close closed ochan's goroutine.
func (o *Ochan) Close() {
close(o.done)
}
-4
View File
@@ -15,9 +15,5 @@ var Reader io.Reader
// Read is a helper function that calls Reader.Read using io.ReadFull.
// On return, n == len(b) if and only if err == nil.
func Read(b []byte) (n int, err error) {
if Reader == nil {
panic("no rng")
}
return io.ReadFull(Reader, b)
}
-36
View File
@@ -1,36 +0,0 @@
//go:build stm32 || (sam && atsamd51) || (sam && atsame5x)
// +build stm32 sam,atsamd51 sam,atsame5x
package rand
import (
"machine"
)
func init() {
Reader = &reader{}
}
type reader struct {
}
func (r *reader) Read(b []byte) (n int, err error) {
if len(b) == 0 {
return
}
var randomByte uint32
for i := range b {
if i%4 == 0 {
randomByte, err = machine.GetRNG()
if err != nil {
return n, err
}
} else {
randomByte >>= 8
}
b[i] = byte(randomByte)
}
return len(b), nil
}
-1
View File
@@ -1,7 +1,6 @@
// Hand created file. DO NOT DELETE.
// Cortex-M System Control Block-related definitions.
//go:build cortexm
// +build cortexm
package arm
-16
View File
@@ -1,16 +0,0 @@
//go:build avr && attiny85
// +build avr,attiny85
package avr
// The attiny85 have only TIMSK when other AVR boards have TIMSK0 and TIMSK1, etc.
// Create an alias of TIMSK, TIMSK_OCIE0A, TIMSK_OCIE0B and TIMSK_TOIE0 so we can use
// common code to mask interrupts.
var TIMSK0 = TIMSK
const (
TIMSK0_OCIE0A = TIMSK_OCIE0A
TIMSK0_OCIE0B = TIMSK_OCIE0B
TIMSK0_TOIE0 = TIMSK_TOIE0
)
-1
View File
@@ -1,4 +1,3 @@
//go:build feather_m4_can
// +build feather_m4_can
package main
@@ -1,4 +1,3 @@
//go:build feather_m4_can
// +build feather_m4_can
package main
-1
View File
@@ -1,4 +1,3 @@
//go:build circuitplay_express
// +build circuitplay_express
package main
-1
View File
@@ -1,4 +1,3 @@
//go:build pyportal
// +build pyportal
package main

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