mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-03 02:27:48 +00:00
Compare commits
232 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3e5f602655 | |||
| ecb7eebcff | |||
| a680bfbb7a | |||
| bf23839931 | |||
| 6b15a72895 | |||
| 08fd49fe60 | |||
| d65e3deccf | |||
| cbfa85be6a | |||
| 6c23f27f73 | |||
| 31a3a7c84b | |||
| a9a225ba26 | |||
| 58d0499e55 | |||
| b24af78327 | |||
| b406422277 | |||
| cfed3f0213 | |||
| d75e14245b | |||
| af8244e868 | |||
| f962e2fd15 | |||
| 5746154cc0 | |||
| e9d9ae8781 | |||
| 52ffd6aa98 | |||
| 644356c220 | |||
| 47a622a903 | |||
| 4417374b53 | |||
| 262291a80a | |||
| cdd267fa10 | |||
| 850a5fdbfb | |||
| 4b2edc9a26 | |||
| f2fef290c9 | |||
| 010cc13e9e | |||
| ac7e370c72 | |||
| 77ec9b6369 | |||
| aa8e0bb509 | |||
| 372d9e0f5e | |||
| d139fa5e0f | |||
| 367fb9d40e | |||
| 98a6ed8059 | |||
| 641a7e5cb9 | |||
| 3fa7d6cc40 | |||
| e497b5c5ba | |||
| 23dc861ddb | |||
| b2ccf12e98 | |||
| 23479c92d3 | |||
| 3458726234 | |||
| a7a69d38a4 | |||
| 4210200070 | |||
| 3883550c44 | |||
| 5ce072b827 | |||
| 4029b838ce | |||
| 3fbab2ede3 | |||
| a29e1d43f1 | |||
| ee663ccb96 | |||
| cd867b72b9 | |||
| 8aa223aed9 | |||
| 3a4e0c94e1 | |||
| 0a0981a475 | |||
| 2f57e4ff6d | |||
| 5e33dccf1f | |||
| f4fdf8dce9 | |||
| 9c3f9537be | |||
| f5b7925047 | |||
| 50401c05e8 | |||
| 7914a729a5 | |||
| 8eedd2b04b | |||
| 60b483bd3b | |||
| 322abf6d22 | |||
| b85cb55aab | |||
| 03d83181ca | |||
| 31ee1637df | |||
| b7bcb256d7 | |||
| 7516c5d69e | |||
| c6ae1c58fc | |||
| 0c2fefa09b | |||
| ea2a6b70b2 | |||
| d054d4d512 | |||
| e7e1b755c9 | |||
| 38cd5b80ec | |||
| 57ff3a5ca0 | |||
| ecf7014f7e | |||
| 7c3a22d289 | |||
| 2c7ea98ccf | |||
| 57b8f7e667 | |||
| db0efc52c7 | |||
| 94b075e423 | |||
| ce5d52870f | |||
| dd6adcacb6 | |||
| 610a20c4d5 | |||
| daf5d0b63a | |||
| 233f5c6af2 | |||
| ca2f25ed48 | |||
| cc1a95a489 | |||
| 431e223803 | |||
| 1b46324456 | |||
| 751ac85488 | |||
| 512fb1dae6 | |||
| 0d20afa85f | |||
| c87bb0e9cc | |||
| 6afceb5621 | |||
| aa053b5fb0 | |||
| 0ed34e3cb0 | |||
| 78a36f7724 | |||
| a743580734 | |||
| e2178ce682 | |||
| b2ef7299b7 | |||
| 14ce531498 | |||
| 21c76c0cb0 | |||
| fbd72a4b2c | |||
| 93e0636c03 | |||
| ef77b645b9 | |||
| 0b939f93bc | |||
| 798085e866 | |||
| 69bf6e3c89 | |||
| 8f8d83bffe | |||
| 998f01608c | |||
| 84279ab2ec | |||
| a888d6245d | |||
| f80efa5b8b | |||
| 29f7ebc63e | |||
| 72e15af1fa | |||
| 6cb604c752 | |||
| cb01d4d63e | |||
| fe21650010 | |||
| ebd4969cde | |||
| 32a7b8cc4e | |||
| b4fa658705 | |||
| ee4e42ba1f | |||
| c6678525a9 | |||
| 8d75b58bdf | |||
| ec97313239 | |||
| e046b23773 | |||
| 0099d47002 | |||
| 5c3ad004ab | |||
| 61be9189f1 | |||
| 1e2791b216 | |||
| d86dd642b3 | |||
| 21b89ef327 | |||
| 39c8711332 | |||
| edc9319e0d | |||
| fcd88356db | |||
| e536676a67 | |||
| 342c438586 | |||
| 6b7ecf1f52 | |||
| bd7ab8ddd5 | |||
| 302e72e84f | |||
| 55ca5287fe | |||
| 11ee0969b6 | |||
| 81dbbc89d3 | |||
| a4f9e5e552 | |||
| f9f2349850 | |||
| f1b15db258 | |||
| 12e314ccc9 | |||
| e594dbc133 | |||
| bb08a25edc | |||
| b7b7713526 | |||
| 92150bd1c5 | |||
| d0633f6228 | |||
| d46933abf2 | |||
| 26625f5a22 | |||
| 3e109fca5f | |||
| 763a86cd8e | |||
| 13a3c4b155 | |||
| 9fa667ce63 | |||
| 8bd39d2fc2 | |||
| c685e0696a | |||
| 9db8826b3b | |||
| 0aed62efe4 | |||
| 2b1a72d112 | |||
| a6837f05a4 | |||
| c35ce761aa | |||
| d2963b153e | |||
| f9293645af | |||
| 38305399a3 | |||
| 8f2082df69 | |||
| da8eb521e1 | |||
| dc53a59c49 | |||
| f21fdd1f76 | |||
| 5e719b0d3d | |||
| 9eb13884de | |||
| 85031d6df7 | |||
| 58b44f9f17 | |||
| c0ea21ece7 | |||
| 81edf577a3 | |||
| 484bb8f13d | |||
| ae1e7731a4 | |||
| 518745ea79 | |||
| 38b14706e2 | |||
| 747336f0a9 | |||
| e4de7b4957 | |||
| d5c0083085 | |||
| e6fbad13c6 | |||
| 62bda8e129 | |||
| 51d6ffb3be | |||
| 964aa7058a | |||
| 0f9d2ac0e4 | |||
| 5264469cbd | |||
| c096f35224 | |||
| 929cd767c1 | |||
| e1df2510d4 | |||
| 2ebaa9f520 | |||
| 5159eab694 | |||
| 75dfb26452 | |||
| 971da0bc09 | |||
| 0420842f4d | |||
| d30f8b6ed6 | |||
| 1f6b4a5e7b | |||
| 51fc78c100 | |||
| e4f2b9c003 | |||
| cff4493ca0 | |||
| 93ac7cec0d | |||
| b4503c1e37 | |||
| 3e6410f323 | |||
| 0f69d016a0 | |||
| ef8c1a187d | |||
| 08d0dc0d25 | |||
| 039186a2a3 | |||
| d6c892fe7b | |||
| cfe6b9765f | |||
| 539495ef45 | |||
| b13c993565 | |||
| 449bfe04f3 | |||
| 1903cf23c9 | |||
| 9734f349a3 | |||
| d87ff838eb | |||
| a360c82b40 | |||
| 4a2faeb2c5 | |||
| 99f00d396d | |||
| 049c5ed3b1 | |||
| cce02cd046 | |||
| be7bbba4ca | |||
| e668c8c1a7 | |||
| d62c9696fb | |||
| 343146f35c |
+4
-110
@@ -22,12 +22,12 @@ commands:
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- llvm-source-12-v1
|
||||
- llvm-source-13-v1
|
||||
- run:
|
||||
name: "Fetch LLVM source"
|
||||
command: make llvm-source
|
||||
- save_cache:
|
||||
key: llvm-source-12-v1
|
||||
key: llvm-source-13-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-v3
|
||||
- wasi-libc-sysroot-systemclang-v4
|
||||
- run: make wasi-libc
|
||||
- save_cache:
|
||||
key: wasi-libc-sysroot-systemclang-v3
|
||||
key: wasi-libc-sysroot-systemclang-v4
|
||||
paths:
|
||||
- lib/wasi-libc/sysroot
|
||||
- run: make gen-device -j4
|
||||
@@ -99,104 +99,6 @@ 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:
|
||||
@@ -211,17 +113,9 @@ 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
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
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
|
||||
@@ -1,11 +1,15 @@
|
||||
name: CI for tinygo-dev docker container
|
||||
# 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: Push Docker image to GHCR/Docker Hub
|
||||
name: build-push-dev
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
@@ -15,6 +19,8 @@ jobs:
|
||||
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
|
||||
@@ -43,3 +49,11 @@ jobs:
|
||||
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 }}"
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-12-linux-v1
|
||||
key: llvm-source-13-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-12-linux-v1
|
||||
key: llvm-build-13-linux-v2
|
||||
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-v2
|
||||
key: wasi-libc-sysroot-linux-asserts-v3
|
||||
path: lib/wasi-libc/sysroot
|
||||
- name: Build wasi-libc
|
||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||
@@ -108,6 +108,10 @@ 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:
|
||||
@@ -128,6 +132,7 @@ 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
|
||||
@@ -140,12 +145,16 @@ 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
|
||||
@@ -170,7 +179,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-12-linux-asserts-v1
|
||||
key: llvm-source-13-linux-asserts-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -183,7 +192,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-12-linux-asserts-v1
|
||||
key: llvm-build-13-linux-asserts-v2
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -208,11 +217,12 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-linux-asserts-v2
|
||||
key: wasi-libc-sysroot-linux-asserts-v3
|
||||
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
|
||||
@@ -227,6 +237,5 @@ 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
|
||||
|
||||
@@ -15,10 +15,11 @@ jobs:
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17'
|
||||
- name: Install Ninja
|
||||
- uses: MinoruSekine/setup-scoop@v1
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
choco install ninja
|
||||
scoop install ninja binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
@@ -34,7 +35,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-12-windows-v1
|
||||
key: llvm-source-13-windows-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -47,7 +48,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-12-windows-v1
|
||||
key: llvm-build-13-windows-v2
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -64,20 +65,11 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-v1
|
||||
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: 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"
|
||||
@@ -100,6 +92,6 @@ jobs:
|
||||
path: build/release/release.zip
|
||||
- name: Smoke tests
|
||||
shell: bash
|
||||
run: make smoketest TINYGO=build/tinygo AVR=0 XTENSA=0
|
||||
run: make smoketest TINYGO=$(PWD)/build/tinygo AVR=0 XTENSA=0
|
||||
- name: Test stdlib packages
|
||||
run: make tinygo-test
|
||||
|
||||
@@ -32,3 +32,6 @@
|
||||
[submodule "lib/mingw-w64"]
|
||||
path = lib/mingw-w64
|
||||
url = https://github.com/mingw-w64/mingw-w64.git
|
||||
[submodule "lib/macos-minimal-sdk"]
|
||||
path = lib/macos-minimal-sdk
|
||||
url = https://github.com/aykevl/macos-minimal-sdk.git
|
||||
|
||||
+1
-6
@@ -11,12 +11,7 @@ lld so that the binary can be easily moved between systems. It also shows how to
|
||||
build a release tarball that includes this binary and all necessary extra files.
|
||||
|
||||
**Note**: this documentation describes how to build a statically linked release
|
||||
tarball. If you want to develop TinyGo, you will probably want to follow a
|
||||
different guide:
|
||||
|
||||
* [Linux](https://tinygo.org/getting-started/linux/#source-install)
|
||||
* [macOS](https://tinygo.org/getting-started/macos/#source-install)
|
||||
* [Windows](https://tinygo.org/getting-started/windows/#source-install)
|
||||
tarball. If you want to help with development of TinyGo itself, you should follow the guide located at https://tinygo.org/docs/guides/build/
|
||||
|
||||
## Dependencies
|
||||
|
||||
|
||||
+105
@@ -1,3 +1,108 @@
|
||||
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
|
||||
---
|
||||
|
||||
|
||||
+38
-68
@@ -1,80 +1,50 @@
|
||||
# TinyGo base stage installs the most recent Go 1.17.x, LLVM 11 and the TinyGo compiler itself.
|
||||
FROM golang:1.17 AS tinygo-base
|
||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||
FROM golang:1.17 AS tinygo-llvm
|
||||
|
||||
RUN wget -O- https://apt.llvm.org/llvm-snapshot.gpg.key| apt-key add - && \
|
||||
echo "deb http://apt.llvm.org/bullseye/ llvm-toolchain-bullseye-11 main" >> /etc/apt/sources.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y llvm-11-dev libclang-11-dev lld-11 git
|
||||
RUN apt-get update && \
|
||||
apt-get install -y apt-utils make cmake clang-11 binutils-avr gcc-avr avr-libc ninja-build
|
||||
|
||||
COPY ./Makefile /tinygo/Makefile
|
||||
|
||||
RUN cd /tinygo/ && \
|
||||
make llvm-source
|
||||
|
||||
# tinygo-llvm-build stage build the custom llvm with xtensa support
|
||||
FROM tinygo-llvm AS tinygo-llvm-build
|
||||
|
||||
RUN cd /tinygo/ && \
|
||||
make llvm-build
|
||||
|
||||
# tinygo-xtensa stage installs tools needed for ESP32
|
||||
FROM tinygo-llvm-build AS tinygo-xtensa
|
||||
|
||||
ARG xtensa_version="1.22.0-80-g6c4433a-5.2.0"
|
||||
RUN cd /tmp/ && \
|
||||
wget -q https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-${xtensa_version}.tar.gz && \
|
||||
tar xzf xtensa-esp32-elf-linux64-${xtensa_version}.tar.gz && \
|
||||
cp ./xtensa-esp32-elf/bin/xtensa-esp32-elf-ld /usr/local/bin/ && \
|
||||
rm -rf /tmp/xtensa*
|
||||
|
||||
# tinygo-compiler stage builds the compiler itself
|
||||
FROM tinygo-xtensa AS tinygo-compiler
|
||||
|
||||
COPY . /tinygo
|
||||
|
||||
# remove submodules directories and re-init them to fix any hard-coded paths
|
||||
# after copying the tinygo directory in the previous step.
|
||||
# update submodules
|
||||
RUN cd /tinygo/ && \
|
||||
rm -rf ./lib/* && \
|
||||
rm -rf ./lib/*/ && \
|
||||
git submodule sync && \
|
||||
git submodule update --init --recursive --force
|
||||
|
||||
COPY ./lib/picolibc-stdio.c /tinygo/lib/picolibc-stdio.c
|
||||
RUN cd /tinygo/ && \
|
||||
make
|
||||
|
||||
# tinygo-tools stage installs the needed dependencies to compile TinyGo programs for all platforms.
|
||||
FROM tinygo-compiler AS tinygo-tools
|
||||
|
||||
RUN cd /tinygo/ && \
|
||||
go install /tinygo/
|
||||
|
||||
# tinygo-wasm stage installs the needed dependencies to compile TinyGo programs for WASM.
|
||||
FROM tinygo-base AS tinygo-wasm
|
||||
|
||||
COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
|
||||
COPY --from=tinygo-base /tinygo/src /tinygo/src
|
||||
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
|
||||
|
||||
RUN cd /tinygo/ && \
|
||||
apt-get update && \
|
||||
apt-get install -y make clang-11 libllvm11 lld-11 cmake ninja-build && \
|
||||
mkdir build && \
|
||||
make wasi-libc binaryen
|
||||
|
||||
# tinygo-avr stage installs the needed dependencies to compile TinyGo programs for AVR microcontrollers.
|
||||
FROM tinygo-base AS tinygo-avr
|
||||
|
||||
COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
|
||||
COPY --from=tinygo-base /tinygo/src /tinygo/src
|
||||
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
|
||||
COPY --from=tinygo-base /tinygo/Makefile /tinygo/
|
||||
COPY --from=tinygo-base /tinygo/tools /tinygo/tools
|
||||
COPY --from=tinygo-base /tinygo/lib /tinygo/lib
|
||||
|
||||
RUN cd /tinygo/ && \
|
||||
apt-get update && \
|
||||
apt-get install -y apt-utils make binutils-avr gcc-avr avr-libc && \
|
||||
make gen-device-avr && \
|
||||
apt-get autoremove -y && \
|
||||
apt-get clean
|
||||
|
||||
# tinygo-arm stage installs the needed dependencies to compile TinyGo programs for ARM microcontrollers.
|
||||
FROM tinygo-base AS tinygo-arm
|
||||
|
||||
COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
|
||||
COPY --from=tinygo-base /tinygo/src /tinygo/src
|
||||
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
|
||||
COPY --from=tinygo-base /tinygo/Makefile /tinygo/
|
||||
COPY --from=tinygo-base /tinygo/tools /tinygo/tools
|
||||
COPY --from=tinygo-base /tinygo/lib /tinygo/lib
|
||||
|
||||
RUN cd /tinygo/ && \
|
||||
apt-get update && \
|
||||
apt-get install -y apt-utils make clang-11 && \
|
||||
make gen-device-nrf && make gen-device-stm32
|
||||
|
||||
# tinygo-all stage installs the needed dependencies to compile TinyGo programs for all platforms.
|
||||
FROM tinygo-wasm AS tinygo-all
|
||||
|
||||
COPY --from=tinygo-base /tinygo/Makefile /tinygo/
|
||||
COPY --from=tinygo-base /tinygo/tools /tinygo/tools
|
||||
COPY --from=tinygo-base /tinygo/lib /tinygo/lib
|
||||
|
||||
RUN cd /tinygo/ && \
|
||||
apt-get update && \
|
||||
apt-get install -y apt-utils make clang-11 binutils-avr gcc-avr avr-libc && \
|
||||
make gen-device
|
||||
make wasi-libc binaryen && \
|
||||
make gen-device -j4 && \
|
||||
cp build/* $GOPATH/bin/
|
||||
|
||||
CMD ["tinygo"]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Copyright (c) 2018-2021 TinyGo Authors. All rights reserved.
|
||||
Copyright (c) 2018-2022 The TinyGo Authors. All rights reserved.
|
||||
|
||||
TinyGo includes portions of the Go standard library.
|
||||
Copyright (c) 2009-2021 The Go Authors. All rights reserved.
|
||||
Copyright (c) 2009-2022 The Go Authors. All rights reserved.
|
||||
|
||||
TinyGo includes portions of LLVM, which is under the Apache License v2.0 with
|
||||
LLVM Exceptions. See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
@@ -9,10 +9,21 @@ CLANG_SRC ?= $(LLVM_PROJECTDIR)/clang
|
||||
LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
|
||||
|
||||
# Try to autodetect LLVM build tools.
|
||||
detect = $(shell command -v $(1) 2> /dev/null && echo $(1))
|
||||
CLANG ?= $(word 1,$(abspath $(call detect,llvm-build/bin/clang))$(call detect,clang-11)$(call detect,clang))
|
||||
LLVM_AR ?= $(word 1,$(abspath $(call detect,llvm-build/bin/llvm-ar))$(call detect,llvm-ar-11)$(call detect,llvm-ar))
|
||||
LLVM_NM ?= $(word 1,$(abspath $(call detect,llvm-build/bin/llvm-nm))$(call detect,llvm-nm-11)$(call detect,llvm-nm))
|
||||
# Versions are listed here in descending priority order.
|
||||
LLVM_VERSIONS = 13 12 11
|
||||
errifempty = $(if $(1),$(1),$(error $(2)))
|
||||
detect = $(shell which $(call errifempty,$(firstword $(foreach p,$(2),$(shell command -v $(p) 2> /dev/null && echo $(p)))),failed to locate $(1) at any of: $(2)))
|
||||
toolSearchPathsVersion = $(1)-$(2)
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
# Also explicitly search Brew's copy, which is not in PATH by default.
|
||||
BREW_PREFIX := $(shell brew --prefix)
|
||||
toolSearchPathsVersion += $(BREW_PREFIX)/opt/llvm@$(2)/bin/$(1)-$(2) $(BREW_PREFIX)/opt/llvm@$(2)/bin/$(1)
|
||||
endif
|
||||
# First search for a custom built copy, then move on to explicitly version-tagged binaries, then just see if the tool is in path with its normal name.
|
||||
findLLVMTool = $(call detect,$(1),$(abspath llvm-build/bin/$(1)) $(foreach ver,$(LLVM_VERSIONS),$(call toolSearchPathsVersion,$(1),$(ver))) $(1))
|
||||
CLANG ?= $(call findLLVMTool,clang)
|
||||
LLVM_AR ?= $(call findLLVMTool,llvm-ar)
|
||||
LLVM_NM ?= $(call findLLVMTool,llvm-nm)
|
||||
|
||||
# Go binary and GOROOT to select
|
||||
GO ?= go
|
||||
@@ -25,7 +36,7 @@ GOTESTFLAGS ?= -v
|
||||
MD5SUM = md5sum
|
||||
|
||||
# tinygo binary for tests
|
||||
TINYGO ?= $(word 1,$(call detect,tinygo)$(call detect,build/tinygo))
|
||||
TINYGO ?= $(call detect,tinygo,tinygo $(CURDIR)/build/tinygo)
|
||||
|
||||
# Use CCACHE for LLVM if possible
|
||||
ifneq (, $(shell command -v ccache 2> /dev/null))
|
||||
@@ -57,10 +68,15 @@ ifeq ($(OS),Windows_NT)
|
||||
CGO_LDFLAGS += -static -static-libgcc -static-libstdc++
|
||||
CGO_LDFLAGS_EXTRA += -lversion
|
||||
|
||||
BINARYEN_OPTION += -DCMAKE_EXE_LINKER_FLAGS='-static-libgcc -static-libstdc++'
|
||||
USE_SYSTEM_BINARYEN ?= 1
|
||||
|
||||
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
|
||||
@@ -75,7 +91,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 lldMachO lldMinGW lldReaderWriter lldWasm lldYAML
|
||||
LLD_LIB_NAMES = lldCOFF lldCommon lldCore lldDriver lldELF lldMachO2 lldMinGW lldReaderWriter lldWasm lldYAML
|
||||
LLD_LIBS = $(START_GROUP) $(addprefix -l,$(LLD_LIB_NAMES)) $(END_GROUP)
|
||||
|
||||
# Other libraries that are needed to link TinyGo.
|
||||
@@ -99,7 +115,6 @@ 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
|
||||
|
||||
@@ -160,7 +175,7 @@ gen-device-rp: build/gen-device-svd
|
||||
|
||||
# Get LLVM sources.
|
||||
$(LLVM_PROJECTDIR)/llvm:
|
||||
git clone -b xtensa_release_12.0.1 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
|
||||
git clone -b xtensa_release_13.0.0 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
|
||||
llvm-source: $(LLVM_PROJECTDIR)/llvm
|
||||
|
||||
# Configure LLVM.
|
||||
@@ -172,6 +187,7 @@ $(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)
|
||||
@@ -179,13 +195,14 @@ build/wasm-opt$(EXE):
|
||||
mkdir -p build
|
||||
cd lib/binaryen && cmake -G Ninja . -DBUILD_STATIC_LIB=ON $(BINARYEN_OPTION) && ninja bin/wasm-opt$(EXE)
|
||||
cp lib/binaryen/bin/wasm-opt$(EXE) build/wasm-opt$(EXE)
|
||||
endif
|
||||
|
||||
# Build wasi-libc sysroot
|
||||
.PHONY: wasi-libc
|
||||
wasi-libc: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a
|
||||
lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
|
||||
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
|
||||
cd lib/wasi-libc && make -j4 WASM_CFLAGS="-O2 -g -DNDEBUG" WASM_CC=$(CLANG) WASM_AR=$(LLVM_AR) WASM_NM=$(LLVM_NM)
|
||||
cd lib/wasi-libc && make -j4 WASM_CFLAGS="-O2 -g -DNDEBUG" MALLOC_IMPL=none WASM_CC=$(CLANG) WASM_AR=$(LLVM_AR) WASM_NM=$(LLVM_NM)
|
||||
|
||||
|
||||
# Build the Go compiler.
|
||||
@@ -196,15 +213,20 @@ tinygo:
|
||||
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 .
|
||||
|
||||
TEST_PACKAGES = \
|
||||
# Tests that take over a minute in wasi
|
||||
TEST_PACKAGES_SLOW = \
|
||||
compress/bzip2 \
|
||||
compress/flate \
|
||||
crypto/dsa \
|
||||
index/suffixarray \
|
||||
|
||||
TEST_PACKAGES_BASE = \
|
||||
compress/lzw \
|
||||
compress/zlib \
|
||||
container/heap \
|
||||
container/list \
|
||||
container/ring \
|
||||
crypto/des \
|
||||
crypto/dsa \
|
||||
crypto/elliptic/internal/fiat \
|
||||
crypto/internal/subtle \
|
||||
crypto/md5 \
|
||||
@@ -224,16 +246,17 @@ TEST_PACKAGES = \
|
||||
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 \
|
||||
@@ -241,15 +264,64 @@ TEST_PACKAGES = \
|
||||
unicode/utf16 \
|
||||
unicode/utf8 \
|
||||
|
||||
# Standard library packages that pass tests natively
|
||||
TEST_PACKAGES := \
|
||||
$(TEST_PACKAGES_BASE)
|
||||
|
||||
# archive/zip requires 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
|
||||
ifneq ($(OS),Windows_NT)
|
||||
TEST_PACKAGES := \
|
||||
$(TEST_PACKAGES) \
|
||||
archive/zip \
|
||||
debug/dwarf \
|
||||
debug/plan9obj \
|
||||
io/fs \
|
||||
testing/fstest
|
||||
endif
|
||||
|
||||
# Standard library packages that pass tests on wasi
|
||||
TEST_PACKAGES_WASI = \
|
||||
$(TEST_PACKAGES_BASE)
|
||||
|
||||
# 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) $(TEST_PACKAGES_SLOW)
|
||||
tinygo-test-fast:
|
||||
$(TINYGO) test $(TEST_PACKAGES)
|
||||
tinygo-bench:
|
||||
$(TINYGO) test -bench . $(TEST_PACKAGES) $(TEST_PACKAGES_SLOW)
|
||||
tinygo-bench-fast:
|
||||
$(TINYGO) test -bench . $(TEST_PACKAGES)
|
||||
tinygo-test-wasi:
|
||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_WASI) $(TEST_PACKAGES_SLOW)
|
||||
tinygo-test-wasi-fast:
|
||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_WASI)
|
||||
tinygo-bench-wasi:
|
||||
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_WASI) $(TEST_PACKAGES_SLOW)
|
||||
tinygo-bench-wasi-fast:
|
||||
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_WASI)
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
.PHONY: smoketest
|
||||
smoketest:
|
||||
$(TINYGO) version
|
||||
# compile-only platform-independent examples
|
||||
cd tests/text/template/smoke && $(TINYGO) test -c && rm -f smoke.test
|
||||
# regression test for #2563
|
||||
cd tests/os/smoke && $(TINYGO) test -c -target=pybadge && rm smoke.test
|
||||
# test all examples (except pwm)
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -383,6 +455,8 @@ 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
|
||||
@@ -409,6 +483,8 @@ 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
|
||||
@@ -443,8 +519,12 @@ ifneq ($(STM32), 0)
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=stm32f4disco-1 examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=stm32f469disco examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=lorae5 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=swan examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
endif
|
||||
ifneq ($(AVR), 0)
|
||||
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
|
||||
@@ -478,6 +558,8 @@ 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
|
||||
@@ -501,6 +583,7 @@ 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.
|
||||
@@ -511,11 +594,12 @@ endif
|
||||
wasmtest:
|
||||
$(GO) test ./tests/wasm
|
||||
|
||||
build/release: tinygo gen-device wasi-libc binaryen
|
||||
build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binaryen)
|
||||
@mkdir -p build/release/tinygo/bin
|
||||
@mkdir -p build/release/tinygo/lib/clang/include
|
||||
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
|
||||
@mkdir -p build/release/tinygo/lib/compiler-rt/lib
|
||||
@mkdir -p build/release/tinygo/lib/macos-minimal-sdk
|
||||
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
|
||||
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
|
||||
@mkdir -p build/release/tinygo/lib/musl/arch
|
||||
@@ -525,18 +609,21 @@ build/release: tinygo gen-device wasi-libc binaryen
|
||||
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libc
|
||||
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libm
|
||||
@mkdir -p build/release/tinygo/lib/wasi-libc
|
||||
@mkdir -p build/release/tinygo/pkg/armv6m-unknown-unknown-eabi
|
||||
@mkdir -p build/release/tinygo/pkg/armv7m-unknown-unknown-eabi
|
||||
@mkdir -p build/release/tinygo/pkg/armv7em-unknown-unknown-eabi
|
||||
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0
|
||||
@mkdir -p build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus
|
||||
@mkdir -p build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4
|
||||
@echo copying source files
|
||||
@cp -p build/tinygo$(EXE) build/release/tinygo/bin
|
||||
ifneq ($(USE_SYSTEM_BINARYEN),1)
|
||||
@cp -p build/wasm-opt$(EXE) build/release/tinygo/bin
|
||||
endif
|
||||
@cp -p $(abspath $(CLANG_SRC))/lib/Headers/*.h build/release/tinygo/lib/clang/include
|
||||
@cp -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/CMSIS
|
||||
@cp -rp lib/CMSIS/README.md build/release/tinygo/lib/CMSIS
|
||||
@cp -rp lib/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt/lib
|
||||
@cp -rp lib/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt
|
||||
@cp -rp lib/compiler-rt/README.txt build/release/tinygo/lib/compiler-rt
|
||||
@cp -rp lib/macos-minimal-sdk/* build/release/tinygo/lib/macos-minimal-sdk
|
||||
@cp -rp lib/musl/arch/aarch64 build/release/tinygo/lib/musl/arch
|
||||
@cp -rp lib/musl/arch/arm build/release/tinygo/lib/musl/arch
|
||||
@cp -rp lib/musl/arch/generic build/release/tinygo/lib/musl/arch
|
||||
@@ -574,12 +661,12 @@ build/release: tinygo gen-device wasi-libc binaryen
|
||||
@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=armv6m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv6m-unknown-unknown-eabi/compiler-rt compiler-rt
|
||||
./build/tinygo build-library -target=armv7m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7m-unknown-unknown-eabi/compiler-rt compiler-rt
|
||||
./build/tinygo build-library -target=armv7em-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7em-unknown-unknown-eabi/compiler-rt compiler-rt
|
||||
./build/tinygo build-library -target=armv6m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv6m-unknown-unknown-eabi/picolibc picolibc
|
||||
./build/tinygo build-library -target=armv7m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7m-unknown-unknown-eabi/picolibc picolibc
|
||||
./build/tinygo build-library -target=armv7em-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7em-unknown-unknown-eabi/picolibc picolibc
|
||||
./build/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/compiler-rt compiler-rt
|
||||
./build/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/compiler-rt compiler-rt
|
||||
./build/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/compiler-rt compiler-rt
|
||||
./build/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/picolibc picolibc
|
||||
./build/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/picolibc picolibc
|
||||
./build/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/picolibc picolibc
|
||||
|
||||
release: build/release
|
||||
tar -czf build/release.tar.gz -C build/release tinygo
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# TinyGo - Go compiler for small places
|
||||
|
||||
[](https://circleci.com/gh/tinygo-org/tinygo/tree/dev) [](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml)
|
||||
[](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml) [](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml) [](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml) [](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml) [](https://circleci.com/gh/tinygo-org/tinygo/tree/dev)
|
||||
|
||||
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (Wasm), and command-line tools.
|
||||
|
||||
@@ -43,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
|
||||
|
||||
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
||||
|
||||
The following 74 microcontroller boards are currently supported:
|
||||
The following 82 microcontroller boards are currently supported:
|
||||
|
||||
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
||||
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
||||
@@ -59,6 +59,7 @@ The following 74 microcontroller boards are currently supported:
|
||||
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
|
||||
* [Adafruit ItsyBitsy M4](https://www.adafruit.com/product/3800)
|
||||
* [Adafruit ItsyBitsy nRF52840](https://www.adafruit.com/product/4481)
|
||||
* [Adafruit MacroPad RP2040](https://www.adafruit.com/product/5100)
|
||||
* [Adafruit Matrix Portal M4](https://www.adafruit.com/product/4745)
|
||||
* [Adafruit Metro M4 Express Airlift](https://www.adafruit.com/product/4000)
|
||||
* [Adafruit PyBadge](https://www.adafruit.com/product/4200)
|
||||
@@ -79,13 +80,17 @@ The following 74 microcontroller boards are currently supported:
|
||||
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
|
||||
* [BBC micro:bit](https://microbit.org/)
|
||||
* [BBC micro:bit v2](https://microbit.org/new-microbit/)
|
||||
* [blues wireless Swan](https://blues.io/products/swan/)
|
||||
* [Digispark](http://digistump.com/products/1)
|
||||
* [Dragino LoRaWAN GPS Tracker LGT-92](http://www.dragino.com/products/lora-lorawan-end-node/item/142-lgt-92.html)
|
||||
* [ESP32](https://www.espressif.com/en/products/socs/esp32)
|
||||
* [ESP8266](https://www.espressif.com/en/products/socs/esp8266)
|
||||
* [ESP32 - Core board](https://www.espressif.com/en/products/socs/esp32)
|
||||
* [ESP32 - mini32](https://www.espressif.com/en/products/socs/esp32)
|
||||
* [ESP8266 - d1mini](https://www.espressif.com/en/products/socs/esp8266)
|
||||
* [ESP8266 - NodeMCU](https://www.espressif.com/en/products/socs/esp8266)
|
||||
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
|
||||
* [M5Stack](https://docs.m5stack.com/en/core/basic)
|
||||
* [M5Stack Core2](https://shop.m5stack.com/products/m5stack-core2-esp32-iot-development-kit)
|
||||
* [M5Stamp C3](https://docs.m5stack.com/en/core/stamp_c3)
|
||||
* [Makerdiary nRF52840-MDK](https://wiki.makerdiary.com/nrf52840-mdk/)
|
||||
* [Makerdiary nRF52840-MDK USB Dongle](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/)
|
||||
* [Microchip SAM E54 Xplained Pro](https://www.microchip.com/developmenttools/productdetails/atsame54-xpro)
|
||||
@@ -102,14 +107,15 @@ The following 74 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)
|
||||
* [SiFIve HiFive1](https://www.sifive.com/boards/hifive1)
|
||||
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
|
||||
* [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1)
|
||||
* [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)
|
||||
@@ -118,7 +124,9 @@ The following 74 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!
|
||||
|
||||
@@ -159,7 +167,6 @@ Goals:
|
||||
|
||||
Non-goals:
|
||||
|
||||
* Using more than one core.
|
||||
* Be efficient while using zillions of goroutines. However, good goroutine support is certainly a goal.
|
||||
* Be as fast as `gc`. However, LLVM will probably be better at optimizing certain things so TinyGo might actually turn out to be faster for number crunching.
|
||||
* Be able to compile every Go program out there.
|
||||
|
||||
+67
-24
@@ -23,7 +23,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/tinygo-org/tinygo/cgo"
|
||||
"github.com/gofrs/flock"
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"github.com/tinygo-org/tinygo/compiler"
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
@@ -45,6 +45,11 @@ 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.
|
||||
@@ -63,9 +68,8 @@ type BuildResult struct {
|
||||
// implementation of an imported package changes.
|
||||
type packageAction struct {
|
||||
ImportPath string
|
||||
CGoVersion int // cgo.Version
|
||||
CompilerVersion int // compiler.Version
|
||||
InterpVersion int // interp.Version
|
||||
CompilerBuildID string
|
||||
TinyGoVersion string
|
||||
LLVMVersion string
|
||||
Config *compiler.Config
|
||||
CFlags []string
|
||||
@@ -83,12 +87,23 @@ type packageAction struct {
|
||||
// The error value may be of type *MultiError. Callers will likely want to check
|
||||
// for this case and print such errors individually.
|
||||
func Build(pkgName, outpath string, config *compileopts.Config, action func(BuildResult) error) error {
|
||||
// Read the build ID of the tinygo binary.
|
||||
// Used as a cache key for package builds.
|
||||
compilerBuildID, err := ReadBuildID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a temporary directory for intermediary files.
|
||||
dir, err := ioutil.TempDir("", "tinygo")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
if config.Options.Work {
|
||||
fmt.Printf("WORK=%s\n", dir)
|
||||
} else {
|
||||
defer os.RemoveAll(dir)
|
||||
}
|
||||
|
||||
// Check for a libc dependency.
|
||||
// As a side effect, this also creates the headers for the given libc, if
|
||||
@@ -96,18 +111,23 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
root := goenv.Get("TINYGOROOT")
|
||||
var libcDependencies []*compileJob
|
||||
switch config.Target.Libc {
|
||||
case "darwin-libSystem":
|
||||
job := makeDarwinLibSystemJob(config, dir)
|
||||
libcDependencies = append(libcDependencies, job)
|
||||
case "musl":
|
||||
job, err := Musl.load(config, dir)
|
||||
job, unlock, err := Musl.load(config, dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer unlock()
|
||||
libcDependencies = append(libcDependencies, dummyCompileJob(filepath.Join(filepath.Dir(job.result), "crt1.o")))
|
||||
libcDependencies = append(libcDependencies, job)
|
||||
case "picolibc":
|
||||
libcJob, err := Picolibc.load(config, dir)
|
||||
libcJob, unlock, err := Picolibc.load(config, dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer unlock()
|
||||
libcDependencies = append(libcDependencies, libcJob)
|
||||
case "wasi-libc":
|
||||
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
|
||||
@@ -116,10 +136,11 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
}
|
||||
libcDependencies = append(libcDependencies, dummyCompileJob(path))
|
||||
case "mingw-w64":
|
||||
_, err := MinGW.load(config, dir)
|
||||
_, unlock, err := MinGW.load(config, dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
unlock()
|
||||
libcDependencies = append(libcDependencies, makeMinGWExtraLibs(dir)...)
|
||||
case "":
|
||||
// no library specified, so nothing to do
|
||||
@@ -139,7 +160,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
SizeLevel: sizeLevel,
|
||||
|
||||
Scheduler: config.Scheduler(),
|
||||
FuncImplementation: config.FuncImplementation(),
|
||||
AutomaticStackSize: config.AutomaticStackSize(),
|
||||
DefaultStackSize: config.Target.DefaultStackSize,
|
||||
NeedsStackObjects: config.NeedsStackObjects(),
|
||||
@@ -188,9 +208,8 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
// the parameters for the build.
|
||||
actionID := packageAction{
|
||||
ImportPath: pkg.ImportPath,
|
||||
CGoVersion: cgo.Version,
|
||||
CompilerVersion: compiler.Version,
|
||||
InterpVersion: interp.Version,
|
||||
CompilerBuildID: string(compilerBuildID),
|
||||
TinyGoVersion: goenv.Version,
|
||||
LLVMVersion: llvm.Version,
|
||||
Config: compilerConfig,
|
||||
CFlags: pkg.CFlags,
|
||||
@@ -228,17 +247,19 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
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())
|
||||
@@ -414,7 +435,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
llvmInitFn.SetUnnamedAddr(true)
|
||||
transform.AddStandardAttributes(llvmInitFn, config)
|
||||
llvmInitFn.Param(0).SetName("context")
|
||||
llvmInitFn.Param(1).SetName("parentHandle")
|
||||
block := mod.Context().AddBasicBlock(llvmInitFn, "entry")
|
||||
irbuilder := mod.Context().NewBuilder()
|
||||
defer irbuilder.Dispose()
|
||||
@@ -425,7 +445,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
if pkgInit.IsNil() {
|
||||
panic("init not found for " + pkg.Pkg.Path())
|
||||
}
|
||||
irbuilder.CreateCall(pkgInit, []llvm.Value{llvm.Undef(i8ptrType), llvm.Undef(i8ptrType)}, "")
|
||||
irbuilder.CreateCall(pkgInit, []llvm.Value{llvm.Undef(i8ptrType)}, "")
|
||||
}
|
||||
irbuilder.CreateRetVoid()
|
||||
|
||||
@@ -479,7 +499,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
outext := filepath.Ext(outpath)
|
||||
if outext == ".o" || outext == ".bc" || outext == ".ll" {
|
||||
// Run jobs to produce the LLVM module.
|
||||
err := runJobs(programJob, config.Options.Parallelism)
|
||||
err := runJobs(programJob, config.Options.Semaphore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -533,10 +553,11 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
// Add compiler-rt dependency if needed. Usually this is a simple load from
|
||||
// a cache.
|
||||
if config.Target.RTLib == "compiler-rt" {
|
||||
job, err := CompilerRT.load(config, dir)
|
||||
job, unlock, err := CompilerRT.load(config, dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer unlock()
|
||||
linkerDependencies = append(linkerDependencies, job)
|
||||
}
|
||||
|
||||
@@ -740,7 +761,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
// Run all jobs to compile and link the program.
|
||||
// Do this now (instead of after elf-to-hex and similar conversions) as it
|
||||
// is simpler and cannot be parallelized.
|
||||
err = runJobs(linkJob, config.Options.Parallelism)
|
||||
err = runJobs(linkJob, config.Options.Semaphore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -788,9 +809,18 @@ 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,
|
||||
})
|
||||
}
|
||||
@@ -1181,3 +1211,16 @@ func patchRP2040BootCRC(executable string) error {
|
||||
// Update the .boot2 section to included the CRC
|
||||
return replaceElfSection(executable, ".boot2", bytes)
|
||||
}
|
||||
|
||||
// lock may acquire a lock at the specified path.
|
||||
// It returns a function to release the lock.
|
||||
// If flock is not supported, it does nothing.
|
||||
func lock(path string) func() {
|
||||
flock := flock.New(path)
|
||||
err := flock.Lock()
|
||||
if err != nil {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
return func() { flock.Close() }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// ReadBuildID reads the build ID from the currently running executable.
|
||||
func ReadBuildID() ([]byte, error) {
|
||||
executable, err := os.Executable()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := os.Open(executable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "linux", "freebsd":
|
||||
// Read the GNU build id section. (Not sure about FreeBSD though...)
|
||||
file, err := elf.NewFile(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var gnuID, goID []byte
|
||||
for _, section := range file.Sections {
|
||||
if section.Type != elf.SHT_NOTE ||
|
||||
(section.Name != ".note.gnu.build-id" && section.Name != ".note.go.buildid") {
|
||||
continue
|
||||
}
|
||||
buf := make([]byte, section.Size)
|
||||
n, err := section.ReadAt(buf, 0)
|
||||
if uint64(n) != section.Size || err != nil {
|
||||
return nil, fmt.Errorf("could not read build id: %w", err)
|
||||
}
|
||||
if section.Name == ".note.gnu.build-id" {
|
||||
gnuID = buf
|
||||
} else {
|
||||
goID = buf
|
||||
}
|
||||
}
|
||||
if gnuID != nil {
|
||||
return gnuID, nil
|
||||
} else if goID != nil {
|
||||
return goID, nil
|
||||
}
|
||||
case "darwin":
|
||||
// Read the LC_UUID load command, which contains the equivalent of a
|
||||
// build ID.
|
||||
file, err := macho.NewFile(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, load := range file.Loads {
|
||||
// Unfortunately, the debug/macho package doesn't support the
|
||||
// LC_UUID command directly. So we have to read it from
|
||||
// macho.LoadBytes.
|
||||
load, ok := load.(macho.LoadBytes)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
raw := load.Raw()
|
||||
command := binary.LittleEndian.Uint32(raw)
|
||||
if command != 0x1b {
|
||||
// Looking for the LC_UUID load command.
|
||||
// LC_UUID is defined here as 0x1b:
|
||||
// https://opensource.apple.com/source/xnu/xnu-4570.71.2/EXTERNAL_HEADERS/mach-o/loader.h.auto.html
|
||||
continue
|
||||
}
|
||||
return raw[4:], nil
|
||||
}
|
||||
default:
|
||||
// On other platforms (such as Windows) there isn't such a convenient
|
||||
// build ID. Luckily, Go does have an equivalent of the build ID, which
|
||||
// is stored as a special symbol named go.buildid. You can read it
|
||||
// using `go tool buildid`, but the code below extracts it directly
|
||||
// from the binary.
|
||||
// Unfortunately, because of stripping with the -w flag, no symbol
|
||||
// table might be available. Therefore, we have to scan the binary
|
||||
// directly. Luckily the build ID is always at the start of the file.
|
||||
// For details, see:
|
||||
// https://github.com/golang/go/blob/master/src/cmd/internal/buildid/buildid.go
|
||||
fileStart := make([]byte, 4096)
|
||||
_, err := io.ReadFull(f, fileStart)
|
||||
index := bytes.Index(fileStart, []byte("\xff Go build ID: \""))
|
||||
if index < 0 || index > len(fileStart)-103 {
|
||||
return nil, fmt.Errorf("could not find build id in %s", err)
|
||||
}
|
||||
buf := fileStart[index : index+103]
|
||||
if bytes.HasPrefix(buf, []byte("\xff Go build ID: \"")) && bytes.HasSuffix(buf, []byte("\"\n \xff")) {
|
||||
return buf[len("\xff Go build ID: \"") : len(buf)-1], nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("could not find build ID in %s", executable)
|
||||
}
|
||||
@@ -63,6 +63,10 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Acquire a lock (if supported).
|
||||
unlock := lock(filepath.Join(goenv.Get("GOCACHE"), fileHash+".c.lock"))
|
||||
defer unlock()
|
||||
|
||||
// Create cache key for the dependencies file.
|
||||
buf, err := json.Marshal(struct {
|
||||
Path string
|
||||
|
||||
+42
-37
@@ -115,29 +115,26 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
||||
// Any DebugInfoKind implies GenDwarfForAssembly.
|
||||
Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
|
||||
|
||||
if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
|
||||
OPT_compress_debug_sections_EQ)) {
|
||||
if (A->getOption().getID() == OPT_compress_debug_sections) {
|
||||
// TODO: be more clever about the compression type auto-detection
|
||||
Opts.CompressDebugSections = llvm::DebugCompressionType::GNU;
|
||||
} else {
|
||||
Opts.CompressDebugSections =
|
||||
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
|
||||
.Case("none", llvm::DebugCompressionType::None)
|
||||
.Case("zlib", llvm::DebugCompressionType::Z)
|
||||
.Case("zlib-gnu", llvm::DebugCompressionType::GNU)
|
||||
.Default(llvm::DebugCompressionType::None);
|
||||
}
|
||||
if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections_EQ)) {
|
||||
Opts.CompressDebugSections =
|
||||
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
|
||||
.Case("none", llvm::DebugCompressionType::None)
|
||||
.Case("zlib", llvm::DebugCompressionType::Z)
|
||||
.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));
|
||||
Opts.DebugCompilationDir =
|
||||
std::string(Args.getLastArgValue(OPT_fdebug_compilation_dir));
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ,
|
||||
options::OPT_fdebug_compilation_dir_EQ))
|
||||
Opts.DebugCompilationDir = A->getValue();
|
||||
Opts.MainFileName = std::string(Args.getLastArgValue(OPT_main_file_name));
|
||||
|
||||
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
|
||||
@@ -219,7 +216,7 @@ getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
|
||||
|
||||
std::error_code EC;
|
||||
auto Out = std::make_unique<raw_fd_ostream>(
|
||||
Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_Text));
|
||||
Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_TextWithCRLF));
|
||||
if (EC) {
|
||||
Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
|
||||
return nullptr;
|
||||
@@ -228,7 +225,8 @@ getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
|
||||
return Out;
|
||||
}
|
||||
|
||||
bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
|
||||
static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
||||
DiagnosticsEngine &Diags) {
|
||||
// Get the target specific parser.
|
||||
std::string Error;
|
||||
const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error);
|
||||
@@ -236,7 +234,7 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
|
||||
return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
|
||||
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
|
||||
MemoryBuffer::getFileOrSTDIN(Opts.InputFile);
|
||||
MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
|
||||
|
||||
if (std::error_code EC = Buffer.getError()) {
|
||||
Error = EC.message();
|
||||
@@ -277,11 +275,15 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
|
||||
if (!Opts.SplitDwarfOutput.empty())
|
||||
DwoOS = getOutputStream(Opts.SplitDwarfOutput, Diags, IsBinary);
|
||||
|
||||
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
|
||||
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
|
||||
std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
|
||||
// Build up the feature string from the target feature list.
|
||||
std::string FS = llvm::join(Opts.Features, ",");
|
||||
|
||||
MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr, &MCOptions);
|
||||
std::unique_ptr<MCSubtargetInfo> STI(
|
||||
TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
|
||||
assert(STI && "Unable to create subtarget info!");
|
||||
|
||||
MCContext Ctx(Triple(Opts.Triple), MAI.get(), MRI.get(), STI.get(), &SrcMgr,
|
||||
&MCOptions);
|
||||
|
||||
bool PIC = false;
|
||||
if (Opts.RelocationModel == "static") {
|
||||
@@ -294,7 +296,12 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
|
||||
PIC = false;
|
||||
}
|
||||
|
||||
MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, Ctx);
|
||||
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
|
||||
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
|
||||
std::unique_ptr<MCObjectFileInfo> MOFI(
|
||||
TheTarget->createMCObjectFileInfo(Ctx, PIC));
|
||||
Ctx.setObjectFileInfo(MOFI.get());
|
||||
|
||||
if (Opts.SaveTemporaryLabels)
|
||||
Ctx.setAllowTemporaryLabels(false);
|
||||
if (Opts.GenDwarfForAssembly)
|
||||
@@ -316,19 +323,16 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
|
||||
Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
|
||||
if (!Opts.MainFileName.empty())
|
||||
Ctx.setMainFileName(StringRef(Opts.MainFileName));
|
||||
Ctx.setDwarfFormat(Opts.Dwarf64 ? dwarf::DWARF64 : dwarf::DWARF32);
|
||||
Ctx.setDwarfVersion(Opts.DwarfVersion);
|
||||
if (Opts.GenDwarfForAssembly)
|
||||
Ctx.setGenDwarfRootFile(Opts.InputFile,
|
||||
SrcMgr.getMemoryBuffer(BufferIndex)->getBuffer());
|
||||
|
||||
// Build up the feature string from the target feature list.
|
||||
std::string FS = llvm::join(Opts.Features, ",");
|
||||
|
||||
std::unique_ptr<MCStreamer> Str;
|
||||
|
||||
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
|
||||
std::unique_ptr<MCSubtargetInfo> STI(
|
||||
TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
|
||||
assert(MCII && "Unable to create instruction info!");
|
||||
|
||||
raw_pwrite_stream *Out = FDOS.get();
|
||||
std::unique_ptr<buffer_ostream> BOS;
|
||||
@@ -367,6 +371,8 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
|
||||
TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
|
||||
std::unique_ptr<MCAsmBackend> MAB(
|
||||
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
|
||||
assert(MAB && "Unable to create asm backend!");
|
||||
|
||||
std::unique_ptr<MCObjectWriter> OW =
|
||||
DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS)
|
||||
: MAB->createObjectWriter(*Out);
|
||||
@@ -381,8 +387,7 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
|
||||
|
||||
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
|
||||
// is emitted in __LLVM,__asm section if the object file is MachO format.
|
||||
if (Opts.EmbedBitcode && Ctx.getObjectFileInfo()->getObjectFileType() ==
|
||||
MCObjectFileInfo::IsMachO) {
|
||||
if (Opts.EmbedBitcode && Ctx.getObjectFileType() == MCContext::IsMachO) {
|
||||
MCSection *AsmLabel = Ctx.getMachOSection(
|
||||
"__LLVM", "__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly());
|
||||
Str.get()->SwitchSection(AsmLabel);
|
||||
@@ -419,12 +424,12 @@ bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
|
||||
Failed = Parser->Run(Opts.NoInitialTextSection);
|
||||
}
|
||||
|
||||
// Close Streamer first.
|
||||
// It might have a reference to the output stream.
|
||||
Str.reset();
|
||||
// Close the output stream early.
|
||||
BOS.reset();
|
||||
FDOS.reset();
|
||||
return Failed;
|
||||
}
|
||||
|
||||
bool ExecuteAssembler(AssemblerInvocation &Opts,
|
||||
DiagnosticsEngine &Diags) {
|
||||
bool Failed = ExecuteAssemblerImpl(Opts, Diags);
|
||||
|
||||
// Delete output file if there were errors.
|
||||
if (Failed) {
|
||||
@@ -472,7 +477,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,
|
||||
|
||||
@@ -39,6 +39,7 @@ struct AssemblerInvocation {
|
||||
unsigned SaveTemporaryLabels : 1;
|
||||
unsigned GenDwarfForAssembly : 1;
|
||||
unsigned RelaxELFRelocations : 1;
|
||||
unsigned Dwarf64 : 1;
|
||||
unsigned DwarfVersion;
|
||||
std::string DwarfDebugFlags;
|
||||
std::string DwarfDebugProducer;
|
||||
@@ -108,6 +109,7 @@ public:
|
||||
FatalWarnings = 0;
|
||||
NoWarn = 0;
|
||||
IncrementalLinkerCompatible = 0;
|
||||
Dwarf64 = 0;
|
||||
DwarfVersion = 0;
|
||||
EmbedBitcode = 0;
|
||||
}
|
||||
|
||||
+11
-1
@@ -2,6 +2,7 @@ package builder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
@@ -25,7 +26,16 @@ func init() {
|
||||
// Add the path to a Homebrew-installed LLVM for ease of use (no need to
|
||||
// manually set $PATH).
|
||||
if runtime.GOOS == "darwin" {
|
||||
prefix := "/usr/local/opt/llvm@" + llvmMajor + "/bin/"
|
||||
var prefix string
|
||||
switch runtime.GOARCH {
|
||||
case "amd64":
|
||||
prefix = "/usr/local/opt/llvm@" + llvmMajor + "/bin/"
|
||||
case "arm64":
|
||||
prefix = "/opt/homebrew/opt/llvm@" + llvmMajor + "/bin/"
|
||||
default:
|
||||
// unknown GOARCH
|
||||
panic(fmt.Sprintf("unknown GOARCH: %s on darwin", runtime.GOARCH))
|
||||
}
|
||||
commands["clang"] = append(commands["clang"], prefix+"clang-"+llvmMajor)
|
||||
commands["ld.lld"] = append(commands["ld.lld"], prefix+"ld.lld")
|
||||
commands["wasm-ld"] = append(commands["wasm-ld"], prefix+"wasm-ld")
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
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...)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,20 @@ func getClangHeaderPath(TINYGOROOT string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// On Arch Linux, the clang executable is stored in /usr/bin rather than being symlinked from there.
|
||||
// Search directly in /usr/lib for clang.
|
||||
if matches, err := filepath.Glob("/usr/lib/clang/" + llvmMajor + ".*.*"); err == nil {
|
||||
// Check for the highest version first.
|
||||
sort.Strings(matches)
|
||||
for i := len(matches) - 1; i >= 0; i-- {
|
||||
path := filepath.Join(matches[i], "include")
|
||||
_, err := os.Stat(filepath.Join(path, "stdint.h"))
|
||||
if err == nil {
|
||||
return path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Could not find it.
|
||||
return ""
|
||||
}
|
||||
|
||||
+114
-84
@@ -4,8 +4,12 @@ package builder
|
||||
// parallel while taking care of dependencies.
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -29,7 +33,6 @@ type compileJob struct {
|
||||
dependencies []*compileJob
|
||||
result string // result (path)
|
||||
run func(*compileJob) (err error)
|
||||
state jobState
|
||||
err error // error if finished
|
||||
duration time.Duration // how long it took to run this job (only set after finishing)
|
||||
}
|
||||
@@ -44,41 +47,20 @@ func dummyCompileJob(result string) *compileJob {
|
||||
}
|
||||
}
|
||||
|
||||
// readyToRun returns whether this job is ready to run: it is itself not yet
|
||||
// started and all dependencies are finished.
|
||||
func (job *compileJob) readyToRun() bool {
|
||||
if job.state != jobStateQueued {
|
||||
// Already running or finished, so shouldn't be run again.
|
||||
return false
|
||||
}
|
||||
|
||||
// Check dependencies.
|
||||
for _, dep := range job.dependencies {
|
||||
if dep.state != jobStateFinished {
|
||||
// A dependency is not finished, so this job has to wait until it
|
||||
// is.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// All conditions are satisfied.
|
||||
return true
|
||||
}
|
||||
|
||||
// runJobs runs the indicated job and all its dependencies. For every job, all
|
||||
// the dependencies are run first. It returns the error of the first job that
|
||||
// fails.
|
||||
// It runs all jobs in the order of the dependencies slice, depth-first.
|
||||
// Therefore, if some jobs are preferred to run before others, they should be
|
||||
// ordered as such in the job dependencies.
|
||||
func runJobs(job *compileJob, parallelism int) error {
|
||||
if parallelism == 0 {
|
||||
// Have a default, if the parallelism isn't set. This is useful for
|
||||
func runJobs(job *compileJob, sema chan struct{}) error {
|
||||
if sema == nil {
|
||||
// Have a default, if the semaphore isn't set. This is useful for
|
||||
// tests.
|
||||
parallelism = runtime.NumCPU()
|
||||
sema = make(chan struct{}, runtime.NumCPU())
|
||||
}
|
||||
if parallelism < 1 {
|
||||
return fmt.Errorf("-p flag must be at least 1, provided -p=%d", parallelism)
|
||||
if cap(sema) == 0 {
|
||||
return errors.New("cannot 0 jobs at a time")
|
||||
}
|
||||
|
||||
// Create a slice of jobs to run, where all dependencies are run in order.
|
||||
@@ -97,64 +79,91 @@ func runJobs(job *compileJob, parallelism int) error {
|
||||
}
|
||||
addJobs(job)
|
||||
|
||||
// Create channels to communicate with the workers.
|
||||
doneChan := make(chan *compileJob)
|
||||
workerChan := make(chan *compileJob)
|
||||
defer close(workerChan)
|
||||
|
||||
// Start a number of workers.
|
||||
for i := 0; i < parallelism; i++ {
|
||||
if jobRunnerDebug {
|
||||
fmt.Println("## starting worker", i)
|
||||
waiting := make(map[*compileJob]map[*compileJob]struct{}, len(jobs))
|
||||
dependents := make(map[*compileJob][]*compileJob, len(jobs))
|
||||
jidx := make(map[*compileJob]int)
|
||||
var ready intHeap
|
||||
for i, job := range jobs {
|
||||
jidx[job] = i
|
||||
if len(job.dependencies) == 0 {
|
||||
// This job is ready to run.
|
||||
ready.Push(i)
|
||||
continue
|
||||
}
|
||||
|
||||
// Construct a map for dependencies which the job is currently waiting on.
|
||||
waitDeps := make(map[*compileJob]struct{})
|
||||
waiting[job] = waitDeps
|
||||
|
||||
// Add the job to the dependents list of each dependency.
|
||||
for _, dep := range job.dependencies {
|
||||
dependents[dep] = append(dependents[dep], job)
|
||||
waitDeps[dep] = struct{}{}
|
||||
}
|
||||
go jobWorker(workerChan, doneChan)
|
||||
}
|
||||
|
||||
// Create a channel to accept notifications of completion.
|
||||
doneChan := make(chan *compileJob)
|
||||
|
||||
// Send each job in the jobs slice to a worker, taking care of job
|
||||
// dependencies.
|
||||
numRunningJobs := 0
|
||||
var totalTime time.Duration
|
||||
start := time.Now()
|
||||
for {
|
||||
// If there are free workers, try starting a new job (if one is
|
||||
// available). If it succeeds, try again to fill the entire worker pool.
|
||||
if numRunningJobs < parallelism {
|
||||
jobToRun := nextJob(jobs)
|
||||
if jobToRun != nil {
|
||||
// Start job.
|
||||
for len(ready.IntSlice) > 0 || numRunningJobs != 0 {
|
||||
var completed *compileJob
|
||||
if len(ready.IntSlice) > 0 {
|
||||
select {
|
||||
case sema <- struct{}{}:
|
||||
// Start a job.
|
||||
job := jobs[heap.Pop(&ready).(int)]
|
||||
if jobRunnerDebug {
|
||||
fmt.Println("## start: ", jobToRun.description)
|
||||
fmt.Println("## start: ", job.description)
|
||||
}
|
||||
jobToRun.state = jobStateRunning
|
||||
workerChan <- jobToRun
|
||||
go runJob(job, doneChan)
|
||||
numRunningJobs++
|
||||
continue
|
||||
|
||||
case completed = <-doneChan:
|
||||
// A job completed.
|
||||
}
|
||||
} else {
|
||||
// Wait for a job to complete.
|
||||
completed = <-doneChan
|
||||
}
|
||||
|
||||
// When there are no jobs running, all jobs in the jobs slice must have
|
||||
// been finished. Therefore, the work is done.
|
||||
if numRunningJobs == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Wait until a job is finished.
|
||||
job := <-doneChan
|
||||
job.state = jobStateFinished
|
||||
numRunningJobs--
|
||||
totalTime += job.duration
|
||||
<-sema
|
||||
if jobRunnerDebug {
|
||||
fmt.Println("## finished:", job.description, "(time "+job.duration.String()+")")
|
||||
}
|
||||
if job.err != nil {
|
||||
// Wait for running jobs to finish.
|
||||
if completed.err != nil {
|
||||
// Wait for any current jobs to finish.
|
||||
for numRunningJobs != 0 {
|
||||
<-doneChan
|
||||
numRunningJobs--
|
||||
}
|
||||
// Return error of first failing job.
|
||||
return job.err
|
||||
|
||||
// The build failed.
|
||||
return completed.err
|
||||
}
|
||||
|
||||
// Update total run time.
|
||||
totalTime += completed.duration
|
||||
|
||||
// Update dependent jobs.
|
||||
for _, j := range dependents[completed] {
|
||||
wait := waiting[j]
|
||||
delete(wait, completed)
|
||||
if len(wait) == 0 {
|
||||
// This job is now ready to run.
|
||||
ready.Push(jidx[j])
|
||||
delete(waiting, j)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(waiting) != 0 {
|
||||
// There is a dependency cycle preventing some jobs from running.
|
||||
return errDependencyCycle{waiting}
|
||||
}
|
||||
|
||||
// Some statistics, if debugging.
|
||||
@@ -171,29 +180,50 @@ func runJobs(job *compileJob, parallelism int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// nextJob returns the first ready-to-run job.
|
||||
// This is an implementation detail of runJobs.
|
||||
func nextJob(jobs []*compileJob) *compileJob {
|
||||
for _, job := range jobs {
|
||||
if job.readyToRun() {
|
||||
return job
|
||||
}
|
||||
}
|
||||
return nil
|
||||
type errDependencyCycle struct {
|
||||
waiting map[*compileJob]map[*compileJob]struct{}
|
||||
}
|
||||
|
||||
// jobWorker is the goroutine that runs received jobs.
|
||||
// This is an implementation detail of runJobs.
|
||||
func jobWorker(workerChan, doneChan chan *compileJob) {
|
||||
for job := range workerChan {
|
||||
start := time.Now()
|
||||
if job.run != nil {
|
||||
err := job.run(job)
|
||||
if err != nil {
|
||||
job.err = err
|
||||
}
|
||||
func (err errDependencyCycle) Error() string {
|
||||
waits := make([]string, 0, len(err.waiting))
|
||||
for j, wait := range err.waiting {
|
||||
deps := make([]string, 0, len(wait))
|
||||
for dep := range wait {
|
||||
deps = append(deps, dep.description)
|
||||
}
|
||||
job.duration = time.Since(start)
|
||||
doneChan <- job
|
||||
sort.Strings(deps)
|
||||
|
||||
waits = append(waits, fmt.Sprintf("\t%s is waiting for [%s]",
|
||||
j.description, strings.Join(deps, ", "),
|
||||
))
|
||||
}
|
||||
sort.Strings(waits)
|
||||
return "deadlock:\n" + strings.Join(waits, "\n")
|
||||
}
|
||||
|
||||
type intHeap struct {
|
||||
sort.IntSlice
|
||||
}
|
||||
|
||||
func (h *intHeap) Push(x interface{}) {
|
||||
h.IntSlice = append(h.IntSlice, x.(int))
|
||||
}
|
||||
|
||||
func (h *intHeap) Pop() interface{} {
|
||||
x := h.IntSlice[len(h.IntSlice)-1]
|
||||
h.IntSlice = h.IntSlice[:len(h.IntSlice)-1]
|
||||
return x
|
||||
}
|
||||
|
||||
// runJob runs a compile job and notifies doneChan of completion.
|
||||
func runJob(job *compileJob, doneChan chan *compileJob) {
|
||||
start := time.Now()
|
||||
if job.run != nil {
|
||||
err := job.run(job)
|
||||
if err != nil {
|
||||
job.err = err
|
||||
}
|
||||
}
|
||||
job.duration = time.Since(start)
|
||||
doneChan <- job
|
||||
}
|
||||
|
||||
+49
-13
@@ -4,7 +4,9 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
@@ -36,11 +38,12 @@ type Library struct {
|
||||
// The resulting directory may be stored in the provided tmpdir, which is
|
||||
// expected to be removed after the Load call.
|
||||
func (l *Library) Load(config *compileopts.Config, tmpdir string) (dir string, err error) {
|
||||
job, err := l.load(config, tmpdir)
|
||||
job, unlock, err := l.load(config, tmpdir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = runJobs(job, config.Options.Parallelism)
|
||||
defer unlock()
|
||||
err = runJobs(job, config.Options.Semaphore)
|
||||
return filepath.Dir(job.result), err
|
||||
}
|
||||
|
||||
@@ -52,28 +55,38 @@ func (l *Library) Load(config *compileopts.Config, tmpdir string) (dir string, e
|
||||
// output archive file, it is expected to be removed after use.
|
||||
// As a side effect, this call creates the library header files if they didn't
|
||||
// exist yet.
|
||||
func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJob, err error) {
|
||||
func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJob, abortLock func(), err error) {
|
||||
outdir, precompiled := config.LibcPath(l.name)
|
||||
archiveFilePath := filepath.Join(outdir, "lib.a")
|
||||
if precompiled {
|
||||
// Found a precompiled library for this OS/architecture. Return the path
|
||||
// directly.
|
||||
return dummyCompileJob(archiveFilePath), nil
|
||||
return dummyCompileJob(archiveFilePath), func() {}, nil
|
||||
}
|
||||
|
||||
// Create a lock on the output (if supported).
|
||||
// This is a bit messy, but avoids a deadlock because it is ordered consistently with other library loads within a build.
|
||||
outname := filepath.Base(outdir)
|
||||
unlock := lock(filepath.Join(goenv.Get("GOCACHE"), outname+".lock"))
|
||||
var ok bool
|
||||
defer func() {
|
||||
if !ok {
|
||||
unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
// Try to fetch this library from the cache.
|
||||
if _, err := os.Stat(archiveFilePath); err == nil {
|
||||
return dummyCompileJob(archiveFilePath), nil
|
||||
return dummyCompileJob(archiveFilePath), func() {}, nil
|
||||
}
|
||||
// Cache miss, build it now.
|
||||
|
||||
// Create the destination directory where the components of this library
|
||||
// (lib.a file, include directory) are placed.
|
||||
outname := filepath.Base(outdir)
|
||||
err = os.MkdirAll(filepath.Join(goenv.Get("GOCACHE"), outname), 0o777)
|
||||
if err != nil {
|
||||
// Could not create directory (and not because it already exists).
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Make headers if needed.
|
||||
@@ -83,16 +96,32 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
if _, err = os.Stat(headerPath); err != nil {
|
||||
temporaryHeaderPath, err := ioutil.TempDir(outdir, "include.tmp*")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
defer os.RemoveAll(temporaryHeaderPath)
|
||||
err = l.makeHeaders(target, temporaryHeaderPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
err = os.Rename(temporaryHeaderPath, headerPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
switch {
|
||||
case os.IsExist(err):
|
||||
// Another invocation of TinyGo also seems to have already created the headers.
|
||||
|
||||
case runtime.GOOS == "windows" && os.IsPermission(err):
|
||||
// On Windows, a rename with a destination directory that already
|
||||
// exists does not result in an IsExist error, but rather in an
|
||||
// access denied error. To be sure, check for this case by checking
|
||||
// whether the target directory exists.
|
||||
if _, err := os.Stat(headerPath); err == nil {
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
|
||||
default:
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,7 +130,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
dir := filepath.Join(tmpdir, "build-lib-"+l.name)
|
||||
err = os.Mkdir(dir, 0777)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Precalculate the flags to the compiler invocation.
|
||||
@@ -120,7 +149,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
|
||||
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft")
|
||||
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft", "-fno-unwind-tables")
|
||||
}
|
||||
if strings.HasPrefix(target, "riscv32-") {
|
||||
args = append(args, "-march=rv32imac", "-mabi=ilp32", "-fforce-enable-int128")
|
||||
@@ -129,6 +158,8 @@ 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
|
||||
@@ -136,6 +167,8 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
description: "ar " + l.name + "/lib.a",
|
||||
result: filepath.Join(goenv.Get("GOCACHE"), outname, "lib.a"),
|
||||
run: func(*compileJob) error {
|
||||
defer once.Do(unlock)
|
||||
|
||||
// Create an archive of all object files.
|
||||
f, err := ioutil.TempFile(outdir, "libc.a.tmp*")
|
||||
if err != nil {
|
||||
@@ -207,5 +240,8 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
})
|
||||
}
|
||||
|
||||
return job, nil
|
||||
ok = true
|
||||
return job, func() {
|
||||
once.Do(unlock)
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -11,6 +11,11 @@ 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());
|
||||
|
||||
@@ -101,6 +101,7 @@ var Musl = Library{
|
||||
"-I" + muslDir + "/src/internal",
|
||||
"-I" + headerPath,
|
||||
"-I" + muslDir + "/include",
|
||||
"-fno-stack-protector",
|
||||
}
|
||||
},
|
||||
sourceDir: "lib/musl/src",
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ var Picolibc = Library{
|
||||
"-DHAVE_ALIAS_ATTRIBUTE",
|
||||
"-DTINY_STDIO",
|
||||
"-nostdlibinc",
|
||||
"-Xclang", "-internal-isystem", "-Xclang", picolibcDir + "/include",
|
||||
"-isystem", picolibcDir + "/include",
|
||||
"-I" + picolibcDir + "/tinystdio",
|
||||
"-I" + headerPath,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build byollvm
|
||||
// +build byollvm
|
||||
|
||||
package builder
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
#include <stdlib.h>
|
||||
bool tinygo_clang_driver(int argc, char **argv);
|
||||
bool tinygo_link_elf(int argc, char **argv);
|
||||
bool tinygo_link_macho(int argc, char **argv);
|
||||
bool tinygo_link_mingw(int argc, char **argv);
|
||||
bool tinygo_link_wasm(int argc, char **argv);
|
||||
*/
|
||||
@@ -26,8 +28,13 @@ const hasBuiltinTools = true
|
||||
// linking statically with LLVM (with the byollvm build tag).
|
||||
func RunTool(tool string, args ...string) error {
|
||||
linker := "elf"
|
||||
if tool == "ld.lld" && len(args) >= 2 && args[0] == "-m" && args[1] == "i386pep" {
|
||||
linker = "mingw"
|
||||
if tool == "ld.lld" && len(args) >= 2 {
|
||||
if args[0] == "-m" && args[1] == "i386pep" {
|
||||
linker = "mingw"
|
||||
} else if args[0] == "-flavor" {
|
||||
linker = args[1]
|
||||
args = args[2:]
|
||||
}
|
||||
}
|
||||
args = append([]string{"tinygo:" + tool}, args...)
|
||||
|
||||
@@ -47,6 +54,8 @@ func RunTool(tool string, args ...string) error {
|
||||
ok = C.tinygo_clang_driver(C.int(len(args)), (**C.char)(buf))
|
||||
case "ld.lld":
|
||||
switch linker {
|
||||
case "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,3 +1,4 @@
|
||||
//go:build !byollvm
|
||||
// +build !byollvm
|
||||
|
||||
package builder
|
||||
|
||||
+4
-7
@@ -26,12 +26,6 @@ import (
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
)
|
||||
|
||||
// Version of the cgo package. It must be incremented whenever the cgo package
|
||||
// is changed in a way that affects the output so that cached package builds
|
||||
// will be invalidated.
|
||||
// This version is independent of the TinyGo version number.
|
||||
const Version = 1 // last change: run libclang once per Go file
|
||||
|
||||
// cgoPackage holds all CGo-related information of a package.
|
||||
type cgoPackage struct {
|
||||
generated *ast.File
|
||||
@@ -203,7 +197,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) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
|
||||
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string, clangHeaders string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
|
||||
p := &cgoPackage{
|
||||
currentDir: dir,
|
||||
fset: fset,
|
||||
@@ -339,6 +333,9 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||
// have better alternatives anyway.
|
||||
cflagsForCGo := append([]string{"-D_FORTIFY_SOURCE=0"}, cflags...)
|
||||
cflagsForCGo = append(cflagsForCGo, p.cflags...)
|
||||
if clangHeaders != "" {
|
||||
cflagsForCGo = append(cflagsForCGo, "-isystem", clangHeaders)
|
||||
}
|
||||
|
||||
// Process CGo imports for each file.
|
||||
for i, f := range files {
|
||||
|
||||
+1
-1
@@ -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,14 +0,0 @@
|
||||
// +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"
|
||||
@@ -0,0 +1,16 @@
|
||||
//go:build !byollvm && llvm11
|
||||
// +build !byollvm,llvm11
|
||||
|
||||
package cgo
|
||||
|
||||
/*
|
||||
#cgo linux CFLAGS: -I/usr/lib/llvm-11/include
|
||||
#cgo darwin amd64 CFLAGS: -I/usr/local/opt/llvm@11/include
|
||||
#cgo darwin arm64 CFLAGS: -I/opt/homebrew/opt/llvm@11/include
|
||||
#cgo freebsd CFLAGS: -I/usr/local/llvm11/include
|
||||
#cgo linux LDFLAGS: -L/usr/lib/llvm-11/lib -lclang
|
||||
#cgo darwin amd64 LDFLAGS: -L/usr/local/opt/llvm@11/lib -lclang -lffi
|
||||
#cgo darwin arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@11/lib -lclang -lffi
|
||||
#cgo freebsd LDFLAGS: -L/usr/local/llvm11/lib -lclang
|
||||
*/
|
||||
import "C"
|
||||
@@ -1,14 +1,16 @@
|
||||
// +build !byollvm
|
||||
// +build llvm12
|
||||
//go:build !byollvm && llvm12
|
||||
// +build !byollvm,llvm12
|
||||
|
||||
package cgo
|
||||
|
||||
/*
|
||||
#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
|
||||
#cgo linux CFLAGS: -I/usr/lib/llvm-12/include
|
||||
#cgo darwin amd64 CFLAGS: -I/usr/local/opt/llvm@12/include
|
||||
#cgo darwin arm64 CFLAGS: -I/opt/homebrew/opt/llvm@12/include
|
||||
#cgo freebsd CFLAGS: -I/usr/local/llvm12/include
|
||||
#cgo linux LDFLAGS: -L/usr/lib/llvm-12/lib -lclang
|
||||
#cgo darwin amd64 LDFLAGS: -L/usr/local/opt/llvm@12/lib -lclang -lffi
|
||||
#cgo darwin arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@12/lib -lclang -lffi
|
||||
#cgo freebsd LDFLAGS: -L/usr/local/llvm12/lib -lclang
|
||||
*/
|
||||
import "C"
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
//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"
|
||||
+34
-45
@@ -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", "extalloc", and "conservative".
|
||||
// values are "none", "leaking", 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", "extalloc":
|
||||
case "conservative":
|
||||
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",
|
||||
//"coroutines" and "tasks".
|
||||
// "asyncify" 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 coroutines, which are supported everywhere.
|
||||
return "coroutines"
|
||||
// Fall back to none.
|
||||
return "none"
|
||||
}
|
||||
|
||||
// Serial returns the serial implementation for this build configuration: uart,
|
||||
@@ -159,31 +159,6 @@ func (c *Config) OptLevels() (optLevel, sizeLevel int, inlinerThreshold uint) {
|
||||
}
|
||||
}
|
||||
|
||||
// FuncImplementation picks an appropriate func value implementation for the
|
||||
// target.
|
||||
func (c *Config) FuncImplementation() string {
|
||||
switch c.Scheduler() {
|
||||
case "tasks", "asyncify":
|
||||
// A func value is implemented as a pair of pointers:
|
||||
// {context, function pointer}
|
||||
// where the context may be a pointer to a heap-allocated struct
|
||||
// containing the free variables, or it may be undef if the function
|
||||
// being pointed to doesn't need a context. The function pointer is a
|
||||
// regular function pointer.
|
||||
return "doubleword"
|
||||
case "none", "coroutines":
|
||||
// As "doubleword", but with the function pointer replaced by a unique
|
||||
// ID per function signature. Function values are called by using a
|
||||
// switch statement and choosing which function to call.
|
||||
// Pick the switch implementation with the coroutines scheduler, as it
|
||||
// allows the use of blocking inside a function that is used as a func
|
||||
// value.
|
||||
return "switch"
|
||||
default:
|
||||
panic("unknown scheduler type")
|
||||
}
|
||||
}
|
||||
|
||||
// PanicStrategy returns the panic strategy selected for this target. Valid
|
||||
// values are "print" (print the panic value, then exit) or "trap" (issue a trap
|
||||
// instruction).
|
||||
@@ -224,8 +199,13 @@ func MuslArchitecture(triple string) string {
|
||||
// a precompiled libc shipped with a TinyGo build, or a libc path in the cache
|
||||
// directory (which might not yet be built).
|
||||
func (c *Config) LibcPath(name string) (path string, precompiled bool) {
|
||||
archname := c.Triple()
|
||||
if c.CPU() != "" {
|
||||
archname += "-" + c.CPU()
|
||||
}
|
||||
|
||||
// Try to load a precompiled library.
|
||||
precompiledDir := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", c.Triple(), name)
|
||||
precompiledDir := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", archname, name)
|
||||
if _, err := os.Stat(precompiledDir); err == nil {
|
||||
// Found a precompiled library for this OS/architecture. Return the path
|
||||
// directly.
|
||||
@@ -234,13 +214,7 @@ func (c *Config) LibcPath(name string) (path string, precompiled bool) {
|
||||
|
||||
// No precompiled library found. Determine the path name that will be used
|
||||
// in the build cache.
|
||||
var outname string
|
||||
if c.CPU() != "" {
|
||||
outname = name + "-" + c.Triple() + "-" + c.CPU()
|
||||
} else {
|
||||
outname = name + "-" + c.Triple()
|
||||
}
|
||||
return filepath.Join(goenv.Get("GOCACHE"), outname), false
|
||||
return filepath.Join(goenv.Get("GOCACHE"), name+"-"+archname), false
|
||||
}
|
||||
|
||||
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo
|
||||
@@ -251,23 +225,29 @@ func (c *Config) CFlags() []string {
|
||||
cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT")))
|
||||
}
|
||||
switch c.Target.Libc {
|
||||
case "darwin-libSystem":
|
||||
root := goenv.Get("TINYGOROOT")
|
||||
cflags = append(cflags,
|
||||
"--sysroot="+filepath.Join(root, "lib/macos-minimal-sdk/src"),
|
||||
)
|
||||
case "picolibc":
|
||||
root := goenv.Get("TINYGOROOT")
|
||||
picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc")
|
||||
path, _ := c.LibcPath("picolibc")
|
||||
cflags = append(cflags,
|
||||
"--sysroot="+path,
|
||||
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "include"),
|
||||
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "tinystdio"),
|
||||
"-isystem", filepath.Join(picolibcDir, "include"),
|
||||
"-isystem", filepath.Join(picolibcDir, "tinystdio"),
|
||||
)
|
||||
case "musl":
|
||||
root := goenv.Get("TINYGOROOT")
|
||||
path, _ := c.LibcPath("musl")
|
||||
arch := MuslArchitecture(c.Triple())
|
||||
cflags = append(cflags,
|
||||
"--sysroot="+path,
|
||||
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "musl", "arch", arch),
|
||||
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "musl", "include"),
|
||||
"-nostdlibinc",
|
||||
"-isystem", filepath.Join(path, "include"),
|
||||
"-isystem", filepath.Join(root, "lib", "musl", "arch", arch),
|
||||
"-isystem", filepath.Join(root, "lib", "musl", "include"),
|
||||
)
|
||||
case "wasi-libc":
|
||||
root := goenv.Get("TINYGOROOT")
|
||||
@@ -277,8 +257,8 @@ func (c *Config) CFlags() []string {
|
||||
path, _ := c.LibcPath("mingw-w64")
|
||||
cflags = append(cflags,
|
||||
"--sysroot="+path,
|
||||
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "crt"),
|
||||
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "defaults", "include"),
|
||||
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "crt"),
|
||||
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "defaults", "include"),
|
||||
"-D_UCRT",
|
||||
)
|
||||
case "":
|
||||
@@ -462,6 +442,15 @@ 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
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
validGCOptions = []string{"none", "leaking", "extalloc", "conservative"}
|
||||
validSchedulerOptions = []string{"none", "tasks", "coroutines", "asyncify"}
|
||||
validGCOptions = []string{"none", "leaking", "conservative"}
|
||||
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
|
||||
validSerialOptions = []string{"none", "uart", "usb"}
|
||||
validPrintSizeOptions = []string{"none", "short", "full"}
|
||||
validPanicStrategyOptions = []string{"print", "trap"}
|
||||
@@ -28,11 +28,12 @@ type Options struct {
|
||||
PanicStrategy string
|
||||
Scheduler string
|
||||
Serial string
|
||||
Work bool // -work flag to print temporary build directory
|
||||
PrintIR bool
|
||||
DumpSSA bool
|
||||
VerifyIR bool
|
||||
PrintCommands func(cmd string, args ...string)
|
||||
Parallelism int // -p flag
|
||||
Semaphore chan struct{} // -p flag controls cap
|
||||
Debug bool
|
||||
PrintSizes string
|
||||
PrintAllocs *regexp.Regexp // regexp string
|
||||
@@ -44,6 +45,7 @@ type Options struct {
|
||||
Programmer string
|
||||
OpenOCDCommands []string
|
||||
LLVMFeatures string
|
||||
Directory string
|
||||
}
|
||||
|
||||
// Verify performs a validation on the given options, raising an error if options are not valid.
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
|
||||
func TestVerifyOptions(t *testing.T) {
|
||||
|
||||
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, extalloc, conservative`)
|
||||
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, coroutines, asyncify`)
|
||||
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, conservative`)
|
||||
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, asyncify`)
|
||||
expectedPrintSizeError := errors.New(`invalid size option 'incorrect': valid values are none, short, full`)
|
||||
expectedPanicStrategyError := errors.New(`invalid panic option 'incorrect': valid values are print, trap`)
|
||||
|
||||
@@ -42,12 +42,6 @@ func TestVerifyOptions(t *testing.T) {
|
||||
GC: "leaking",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GCOptionExtalloc",
|
||||
opts: compileopts.Options{
|
||||
GC: "extalloc",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GCOptionConservative",
|
||||
opts: compileopts.Options{
|
||||
@@ -73,12 +67,6 @@ func TestVerifyOptions(t *testing.T) {
|
||||
Scheduler: "tasks",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SchedulerOptionCoroutines",
|
||||
opts: compileopts.Options{
|
||||
Scheduler: "coroutines",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "InvalidPrintSizeOption",
|
||||
opts: compileopts.Options{
|
||||
|
||||
+28
-10
@@ -258,21 +258,30 @@ 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,-thumb-mode"
|
||||
spec.Features = "+armv5t,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
case "armv6":
|
||||
spec.Features = "+armv6,+dsp,+fp64,+strict-align,+vfp2,+vfp2sp,-thumb-mode"
|
||||
spec.Features = "+armv6,+dsp,+fp64,+strict-align,+vfp2,+vfp2sp,-aes,-d32,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-neon,-sha2,-thumb-mode,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
case "armv7":
|
||||
spec.Features = "+armv7-a,+d32,+dsp,+fp64,+neon,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-thumb-mode"
|
||||
spec.Features = "+armv7-a,+d32,+dsp,+fp64,+neon,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-aes,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-sha2,-thumb-mode,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
}
|
||||
case "arm64":
|
||||
spec.CPU = "generic"
|
||||
spec.Features = "+neon"
|
||||
}
|
||||
if goos == "darwin" {
|
||||
spec.CFlags = append(spec.CFlags, "-isysroot", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk")
|
||||
spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip")
|
||||
spec.Linker = "ld.lld"
|
||||
spec.Libc = "darwin-libSystem"
|
||||
arch := strings.Split(triple, "-")[0]
|
||||
platformVersion := strings.TrimPrefix(strings.Split(triple, "-")[2], "macosx")
|
||||
spec.LDFlags = append(spec.LDFlags,
|
||||
"-flavor", "darwinnew",
|
||||
"-dead_strip",
|
||||
"-arch", arch,
|
||||
"-platform_version", "macos", platformVersion, platformVersion,
|
||||
)
|
||||
} else if goos == "linux" {
|
||||
spec.Linker = "ld.lld"
|
||||
spec.RTLib = "compiler-rt"
|
||||
@@ -316,11 +325,20 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
if goarch != runtime.GOARCH {
|
||||
// Some educated guesses as to how to invoke helper programs.
|
||||
spec.GDB = []string{"gdb-multiarch"}
|
||||
if goarch == "arm" && goos == "linux" {
|
||||
spec.Emulator = []string{"qemu-arm"}
|
||||
}
|
||||
if goarch == "arm64" && goos == "linux" {
|
||||
spec.Emulator = []string{"qemu-aarch64"}
|
||||
if goos == "linux" {
|
||||
switch goarch {
|
||||
case "386":
|
||||
// amd64 can _usually_ run 32-bit programs, so skip the emulator in that case.
|
||||
if runtime.GOARCH != "amd64" {
|
||||
spec.Emulator = []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 goos != runtime.GOOS {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/ssa"
|
||||
@@ -16,6 +17,20 @@ func (b *builder) createAtomicOp(call *ssa.CallCommon) (llvm.Value, bool) {
|
||||
case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
|
||||
ptr := b.getValue(call.Args[0])
|
||||
val := b.getValue(call.Args[1])
|
||||
if strings.HasPrefix(b.Triple, "avr") {
|
||||
// AtomicRMW does not work on AVR as intended:
|
||||
// - There are some register allocation issues (fixed by https://reviews.llvm.org/D97127 which is not yet in a usable LLVM release)
|
||||
// - The result is the new value instead of the old value
|
||||
vType := val.Type()
|
||||
name := fmt.Sprintf("__sync_fetch_and_add_%d", vType.IntTypeWidth()/8)
|
||||
fn := b.mod.NamedFunction(name)
|
||||
if fn.IsNil() {
|
||||
fn = llvm.AddFunction(b.mod, name, llvm.FunctionType(vType, []llvm.Type{ptr.Type(), vType}, false))
|
||||
}
|
||||
oldVal := b.createCall(fn, []llvm.Value{ptr, val}, "")
|
||||
// Return the new value, not the original value returned.
|
||||
return b.CreateAdd(oldVal, val, ""), true
|
||||
}
|
||||
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAdd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
|
||||
// Return the new value, not the original value returned by atomicrmw.
|
||||
return b.CreateAdd(oldVal, val, ""), true
|
||||
@@ -73,6 +88,23 @@ func (b *builder) createAtomicOp(call *ssa.CallCommon) (llvm.Value, bool) {
|
||||
case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer":
|
||||
ptr := b.getValue(call.Args[0])
|
||||
val := b.getValue(call.Args[1])
|
||||
if strings.HasPrefix(b.Triple, "avr") {
|
||||
// SelectionDAGBuilder is currently missing the "are unaligned atomics allowed" check for stores.
|
||||
vType := val.Type()
|
||||
isPointer := vType.TypeKind() == llvm.PointerTypeKind
|
||||
if isPointer {
|
||||
// libcalls only supports integers, so cast to an integer.
|
||||
vType = b.uintptrType
|
||||
val = b.CreatePtrToInt(val, vType, "")
|
||||
ptr = b.CreateBitCast(ptr, llvm.PointerType(vType, 0), "")
|
||||
}
|
||||
name := fmt.Sprintf("__atomic_store_%d", vType.IntTypeWidth()/8)
|
||||
fn := b.mod.NamedFunction(name)
|
||||
if fn.IsNil() {
|
||||
fn = llvm.AddFunction(b.mod, name, llvm.FunctionType(vType, []llvm.Type{ptr.Type(), vType, b.uintptrType}, false))
|
||||
}
|
||||
return b.createCall(fn, []llvm.Value{ptr, val, llvm.ConstInt(b.uintptrType, 5, false)}, ""), true
|
||||
}
|
||||
store := b.CreateStore(val, ptr)
|
||||
store.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
|
||||
store.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
|
||||
|
||||
+1
-2
@@ -40,8 +40,7 @@ func (b *builder) createRuntimeCall(fnName string, args []llvm.Value, name strin
|
||||
if llvmFn.IsNil() {
|
||||
panic("trying to call non-existent function: " + fn.RelString(nil))
|
||||
}
|
||||
args = append(args, llvm.Undef(b.i8ptrType)) // unused context parameter
|
||||
args = append(args, llvm.ConstPointerNull(b.i8ptrType)) // coroutine handle
|
||||
args = append(args, llvm.Undef(b.i8ptrType)) // unused context parameter
|
||||
return b.createCall(llvmFn, args, name)
|
||||
}
|
||||
|
||||
|
||||
+73
-36
@@ -20,11 +20,6 @@ import (
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// Version of the compiler pacakge. Must be incremented each time the compiler
|
||||
// package changes in a way that affects the generated LLVM module.
|
||||
// This version is independent of the TinyGo version number.
|
||||
const Version = 25 // last change: add "target-cpu" and "target-features" attributes
|
||||
|
||||
func init() {
|
||||
llvm.InitializeAllTargets()
|
||||
llvm.InitializeAllTargetMCs()
|
||||
@@ -52,7 +47,6 @@ type Config struct {
|
||||
|
||||
// Various compiler options that determine how code is generated.
|
||||
Scheduler string
|
||||
FuncImplementation string
|
||||
AutomaticStackSize bool
|
||||
DefaultStackSize uint64
|
||||
NeedsStackObjects bool
|
||||
@@ -83,6 +77,7 @@ type compilerContext struct {
|
||||
diagnostics []error
|
||||
astComments map[string]*ast.CommentGroup
|
||||
pkg *types.Package
|
||||
packageDir string // directory for this package
|
||||
runtimePkg *types.Package
|
||||
}
|
||||
|
||||
@@ -144,6 +139,8 @@ type builder struct {
|
||||
deferPtr llvm.Value
|
||||
difunc llvm.Metadata
|
||||
dilocals map[*types.Var]llvm.Metadata
|
||||
initInlinedAt llvm.Metadata // fake inlinedAt position
|
||||
initPseudoFuncs map[string]llvm.Metadata // fake "inlined" functions for proper init debug locations
|
||||
allDeferFuncs []interface{}
|
||||
deferFuncs map[*ssa.Function]int
|
||||
deferInvokeFuncs map[string]int
|
||||
@@ -247,6 +244,7 @@ func Sizes(machine llvm.TargetMachine) types.Sizes {
|
||||
// CompilePackage compiles a single package to a LLVM module.
|
||||
func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package, machine llvm.TargetMachine, config *Config, dumpSSA bool) (llvm.Module, []error) {
|
||||
c := newCompilerContext(moduleName, machine, config, dumpSSA)
|
||||
c.packageDir = pkg.OriginalDir()
|
||||
c.pkg = pkg.Pkg
|
||||
c.runtimePkg = ssaPkg.Prog.ImportedPackage("runtime").Pkg
|
||||
c.program = ssaPkg.Prog
|
||||
@@ -271,6 +269,10 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
|
||||
// Predeclare the runtime.alloc function, which is used by the wordpack
|
||||
// functionality.
|
||||
c.getFunction(c.program.ImportedPackage("runtime").Members["alloc"].(*ssa.Function))
|
||||
if c.NeedsStackObjects {
|
||||
// Predeclare trackPointer, which is used everywhere we use runtime.alloc.
|
||||
c.getFunction(c.program.ImportedPackage("runtime").Members["trackPointer"].(*ssa.Function))
|
||||
}
|
||||
|
||||
// Compile all functions, methods, and global variables in this package.
|
||||
irbuilder := c.ctx.NewBuilder()
|
||||
@@ -601,6 +603,51 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
|
||||
}
|
||||
}
|
||||
|
||||
// setDebugLocation sets the current debug location for the builder.
|
||||
func (b *builder) setDebugLocation(pos token.Pos) {
|
||||
if pos == token.NoPos {
|
||||
// No debug information available for this instruction.
|
||||
b.SetCurrentDebugLocation(0, 0, b.difunc, llvm.Metadata{})
|
||||
return
|
||||
}
|
||||
|
||||
position := b.program.Fset.Position(pos)
|
||||
if b.fn.Synthetic == "package initializer" {
|
||||
// Package initializers are treated specially, because while individual
|
||||
// Go SSA instructions have file/line/col information, the parent
|
||||
// function does not. LLVM doesn't store filename information per
|
||||
// instruction, only per function. We work around this difference by
|
||||
// creating a fake DIFunction for each Go file and say that the
|
||||
// instruction really came from that (fake) function but was inlined in
|
||||
// the package initializer function.
|
||||
position := b.program.Fset.Position(pos)
|
||||
name := filepath.Base(position.Filename)
|
||||
difunc, ok := b.initPseudoFuncs[name]
|
||||
if !ok {
|
||||
diFuncType := b.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
|
||||
File: b.getDIFile(position.Filename),
|
||||
})
|
||||
difunc = b.dibuilder.CreateFunction(b.getDIFile(position.Filename), llvm.DIFunction{
|
||||
Name: b.fn.RelString(nil) + "#" + name,
|
||||
File: b.getDIFile(position.Filename),
|
||||
Line: 0,
|
||||
Type: diFuncType,
|
||||
LocalToUnit: true,
|
||||
IsDefinition: true,
|
||||
ScopeLine: 0,
|
||||
Flags: llvm.FlagPrototyped,
|
||||
Optimized: true,
|
||||
})
|
||||
b.initPseudoFuncs[name] = difunc
|
||||
}
|
||||
b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), difunc, b.initInlinedAt)
|
||||
return
|
||||
}
|
||||
|
||||
// Regular debug information.
|
||||
b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), b.difunc, llvm.Metadata{})
|
||||
}
|
||||
|
||||
// getLocalVariable returns a debug info entry for a local variable, which may
|
||||
// either be a parameter or a regular variable. It will create a new metadata
|
||||
// entry if there isn't one for the variable yet.
|
||||
@@ -853,16 +900,14 @@ func (b *builder) createFunction() {
|
||||
// Add debug info, if needed.
|
||||
if b.Debug {
|
||||
if b.fn.Synthetic == "package initializer" {
|
||||
// Package initializers have no debug info. Create some fake debug
|
||||
// info to at least have *something*.
|
||||
filename := b.fn.Package().Pkg.Path() + "/<init>"
|
||||
b.difunc = b.attachDebugInfoRaw(b.fn, b.llvmFn, "", filename, 0)
|
||||
// Package initializer functions have no debug info. Create some
|
||||
// fake debug info to at least have *something*.
|
||||
b.difunc = b.attachDebugInfoRaw(b.fn, b.llvmFn, "", b.packageDir, 0)
|
||||
} else if b.fn.Syntax() != nil {
|
||||
// Create debug info file if needed.
|
||||
b.difunc = b.attachDebugInfo(b.fn)
|
||||
}
|
||||
pos := b.program.Fset.Position(b.fn.Pos())
|
||||
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
|
||||
b.setDebugLocation(b.fn.Pos())
|
||||
}
|
||||
|
||||
// Pre-create all basic blocks in the function.
|
||||
@@ -874,6 +919,16 @@ func (b *builder) createFunction() {
|
||||
entryBlock := b.blockEntries[b.fn.Blocks[0]]
|
||||
b.SetInsertPointAtEnd(entryBlock)
|
||||
|
||||
if b.fn.Synthetic == "package initializer" {
|
||||
b.initPseudoFuncs = make(map[string]llvm.Metadata)
|
||||
|
||||
// Create a fake 'inlined at' metadata node.
|
||||
// See setDebugLocation for details.
|
||||
alloca := b.CreateAlloca(b.uintptrType, "")
|
||||
b.initInlinedAt = alloca.InstructionDebugLoc()
|
||||
alloca.EraseFromParentAsInstruction()
|
||||
}
|
||||
|
||||
// Load function parameters
|
||||
llvmParamIndex := 0
|
||||
for _, param := range b.fn.Params {
|
||||
@@ -912,9 +967,7 @@ func (b *builder) createFunction() {
|
||||
// method).
|
||||
var context llvm.Value
|
||||
if !b.info.exported {
|
||||
parentHandle := b.llvmFn.LastParam()
|
||||
parentHandle.SetName("parentHandle")
|
||||
context = llvm.PrevParam(parentHandle)
|
||||
context = b.llvmFn.LastParam()
|
||||
context.SetName("context")
|
||||
}
|
||||
if len(b.fn.FreeVars) != 0 {
|
||||
@@ -1068,8 +1121,7 @@ func getPos(val posser) token.Pos {
|
||||
// particular Go SSA instruction.
|
||||
func (b *builder) createInstruction(instr ssa.Instruction) {
|
||||
if b.Debug {
|
||||
pos := b.program.Fset.Position(getPos(instr))
|
||||
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
|
||||
b.setDebugLocation(getPos(instr))
|
||||
}
|
||||
|
||||
switch instr := instr.(type) {
|
||||
@@ -1451,9 +1503,6 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
// This function takes a context parameter.
|
||||
// Add it to the end of the parameter list.
|
||||
params = append(params, context)
|
||||
|
||||
// Parent coroutine handle.
|
||||
params = append(params, llvm.Undef(b.i8ptrType))
|
||||
}
|
||||
|
||||
return b.createCall(callee, params, ""), nil
|
||||
@@ -1522,8 +1571,9 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
switch expr := expr.(type) {
|
||||
case *ssa.Alloc:
|
||||
typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
||||
if expr.Heap {
|
||||
size := b.targetData.TypeAllocSize(typ)
|
||||
size := b.targetData.TypeAllocSize(typ)
|
||||
// Move all "large" allocations to the heap. This value is also transform.maxStackAlloc.
|
||||
if expr.Heap || size > 256 {
|
||||
// Calculate ^uintptr(0)
|
||||
maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue()
|
||||
if size > maxSize {
|
||||
@@ -1792,20 +1842,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
if expr.IsString {
|
||||
return b.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil
|
||||
} else { // map
|
||||
llvmKeyType := b.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
|
||||
llvmValueType := b.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
|
||||
|
||||
mapKeyAlloca, mapKeyPtr, mapKeySize := b.createTemporaryAlloca(llvmKeyType, "range.key")
|
||||
mapValueAlloca, mapValuePtr, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
|
||||
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyPtr, mapValuePtr}, "range.next")
|
||||
|
||||
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
|
||||
tuple = b.CreateInsertValue(tuple, ok, 0, "")
|
||||
tuple = b.CreateInsertValue(tuple, b.CreateLoad(mapKeyAlloca, ""), 1, "")
|
||||
tuple = b.CreateInsertValue(tuple, b.CreateLoad(mapValueAlloca, ""), 2, "")
|
||||
b.emitLifetimeEnd(mapKeyPtr, mapKeySize)
|
||||
b.emitLifetimeEnd(mapValuePtr, mapValueSize)
|
||||
return tuple, nil
|
||||
return b.createMapIteratorNext(rangeVal, llvmRangeVal, it), nil
|
||||
}
|
||||
case *ssa.Phi:
|
||||
phi := b.CreatePHI(b.getLLVMType(expr.Type()), "")
|
||||
|
||||
@@ -55,10 +55,9 @@ func TestCompiler(t *testing.T) {
|
||||
{"string.go", "", ""},
|
||||
{"float.go", "", ""},
|
||||
{"interface.go", "", ""},
|
||||
{"func.go", "", "coroutines"},
|
||||
{"func.go", "", ""},
|
||||
{"pragma.go", "", ""},
|
||||
{"goroutine.go", "wasm", "asyncify"},
|
||||
{"goroutine.go", "wasm", "coroutines"},
|
||||
{"goroutine.go", "cortex-m-qemu", "tasks"},
|
||||
{"channel.go", "", ""},
|
||||
{"intrinsics.go", "cortex-m-qemu", ""},
|
||||
@@ -106,9 +105,9 @@ func TestCompiler(t *testing.T) {
|
||||
CodeModel: config.CodeModel(),
|
||||
RelocationModel: config.RelocationModel(),
|
||||
Scheduler: config.Scheduler(),
|
||||
FuncImplementation: config.FuncImplementation(),
|
||||
AutomaticStackSize: config.AutomaticStackSize(),
|
||||
DefaultStackSize: config.Target.DefaultStackSize,
|
||||
NeedsStackObjects: config.NeedsStackObjects(),
|
||||
}
|
||||
machine, err := NewTargetMachine(compilerConfig)
|
||||
if err != nil {
|
||||
@@ -224,7 +223,12 @@ 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.
|
||||
// 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.
|
||||
continue
|
||||
}
|
||||
out = append(out, line)
|
||||
|
||||
@@ -343,9 +343,6 @@ func (b *builder) createRunDefers() {
|
||||
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||
}
|
||||
|
||||
// Parent coroutine handle.
|
||||
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||
|
||||
b.createCall(fnPtr, forwardParams, "")
|
||||
|
||||
case *ssa.Function:
|
||||
@@ -374,9 +371,6 @@ func (b *builder) createRunDefers() {
|
||||
// Add the context parameter. We know it is ignored by the receiving
|
||||
// function, but we have to pass one anyway.
|
||||
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||
|
||||
// Parent coroutine handle.
|
||||
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||
}
|
||||
|
||||
// Call real function.
|
||||
@@ -403,9 +397,6 @@ func (b *builder) createRunDefers() {
|
||||
forwardParams = append(forwardParams, forwardParam)
|
||||
}
|
||||
|
||||
// Parent coroutine handle.
|
||||
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||
|
||||
// Call deferred function.
|
||||
b.createCall(b.getFunction(fn), forwardParams, "")
|
||||
case *ssa.Builtin:
|
||||
|
||||
+9
-55
@@ -19,29 +19,8 @@ func (b *builder) createFuncValue(funcPtr, context llvm.Value, sig *types.Signat
|
||||
// createFuncValue creates a function value from a raw function pointer with no
|
||||
// context.
|
||||
func (c *compilerContext) createFuncValue(builder llvm.Builder, funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
|
||||
var funcValueScalar llvm.Value
|
||||
switch c.FuncImplementation {
|
||||
case "doubleword":
|
||||
// Closure is: {context, function pointer}
|
||||
funcValueScalar = llvm.ConstBitCast(funcPtr, c.rawVoidFuncType)
|
||||
case "switch":
|
||||
funcValueWithSignatureGlobalName := funcPtr.Name() + "$withSignature"
|
||||
funcValueWithSignatureGlobal := c.mod.NamedGlobal(funcValueWithSignatureGlobalName)
|
||||
if funcValueWithSignatureGlobal.IsNil() {
|
||||
funcValueWithSignatureType := c.getLLVMRuntimeType("funcValueWithSignature")
|
||||
funcValueWithSignature := llvm.ConstNamedStruct(funcValueWithSignatureType, []llvm.Value{
|
||||
llvm.ConstPtrToInt(funcPtr, c.uintptrType),
|
||||
c.getFuncSignatureID(sig),
|
||||
})
|
||||
funcValueWithSignatureGlobal = llvm.AddGlobal(c.mod, funcValueWithSignatureType, funcValueWithSignatureGlobalName)
|
||||
funcValueWithSignatureGlobal.SetInitializer(funcValueWithSignature)
|
||||
funcValueWithSignatureGlobal.SetGlobalConstant(true)
|
||||
funcValueWithSignatureGlobal.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
}
|
||||
funcValueScalar = llvm.ConstPtrToInt(funcValueWithSignatureGlobal, c.uintptrType)
|
||||
default:
|
||||
panic("unimplemented func value variant")
|
||||
}
|
||||
// Closure is: {context, function pointer}
|
||||
funcValueScalar := llvm.ConstBitCast(funcPtr, c.rawVoidFuncType)
|
||||
funcValueType := c.getFuncType(sig)
|
||||
funcValue := llvm.Undef(funcValueType)
|
||||
funcValue = builder.CreateInsertValue(funcValue, context, 0, "")
|
||||
@@ -78,43 +57,19 @@ func (b *builder) extractFuncContext(funcValue llvm.Value) llvm.Value {
|
||||
// value. This may be an expensive operation.
|
||||
func (b *builder) decodeFuncValue(funcValue llvm.Value, sig *types.Signature) (funcPtr, context llvm.Value) {
|
||||
context = b.CreateExtractValue(funcValue, 0, "")
|
||||
switch b.FuncImplementation {
|
||||
case "doubleword":
|
||||
bitcast := b.CreateExtractValue(funcValue, 1, "")
|
||||
if !bitcast.IsAConstantExpr().IsNil() && bitcast.Opcode() == llvm.BitCast {
|
||||
funcPtr = bitcast.Operand(0)
|
||||
return
|
||||
}
|
||||
llvmSig := b.getRawFuncType(sig)
|
||||
funcPtr = b.CreateBitCast(bitcast, llvmSig, "")
|
||||
case "switch":
|
||||
if !funcValue.IsAConstant().IsNil() {
|
||||
// If this is a constant func value, the underlying function is
|
||||
// known and can be returned directly.
|
||||
funcValueWithSignatureGlobal := llvm.ConstExtractValue(funcValue, []uint32{1}).Operand(0)
|
||||
funcPtr = llvm.ConstExtractValue(funcValueWithSignatureGlobal.Initializer(), []uint32{0}).Operand(0)
|
||||
return
|
||||
}
|
||||
llvmSig := b.getRawFuncType(sig)
|
||||
sigGlobal := b.getFuncSignatureID(sig)
|
||||
funcPtr = b.createRuntimeCall("getFuncPtr", []llvm.Value{funcValue, sigGlobal}, "")
|
||||
funcPtr = b.CreateIntToPtr(funcPtr, llvmSig, "")
|
||||
default:
|
||||
panic("unimplemented func value variant")
|
||||
bitcast := b.CreateExtractValue(funcValue, 1, "")
|
||||
if !bitcast.IsAConstantExpr().IsNil() && bitcast.Opcode() == llvm.BitCast {
|
||||
funcPtr = bitcast.Operand(0)
|
||||
return
|
||||
}
|
||||
llvmSig := b.getRawFuncType(sig)
|
||||
funcPtr = b.CreateBitCast(bitcast, llvmSig, "")
|
||||
return
|
||||
}
|
||||
|
||||
// getFuncType returns the type of a func value given a signature.
|
||||
func (c *compilerContext) getFuncType(typ *types.Signature) llvm.Type {
|
||||
switch c.FuncImplementation {
|
||||
case "doubleword":
|
||||
return c.ctx.StructType([]llvm.Type{c.i8ptrType, c.rawVoidFuncType}, false)
|
||||
case "switch":
|
||||
return c.getLLVMRuntimeType("funcValue")
|
||||
default:
|
||||
panic("unimplemented func value variant")
|
||||
}
|
||||
return c.ctx.StructType([]llvm.Type{c.i8ptrType, c.rawVoidFuncType}, false)
|
||||
}
|
||||
|
||||
// getRawFuncType returns a LLVM function pointer type for a given signature.
|
||||
@@ -160,7 +115,6 @@ func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
|
||||
}
|
||||
// All functions take these parameters at the end.
|
||||
paramTypes = append(paramTypes, c.i8ptrType) // context
|
||||
paramTypes = append(paramTypes, c.i8ptrType) // parent coroutine
|
||||
|
||||
// Make a func type out of the signature.
|
||||
return llvm.PointerType(llvm.FunctionType(returnType, paramTypes, false), c.funcPtrAddrSpace)
|
||||
|
||||
+21
-53
@@ -30,11 +30,6 @@ func (b *builder) createGo(instr *ssa.Go) {
|
||||
switch value := instr.Call.Value.(type) {
|
||||
case *ssa.Function:
|
||||
// Goroutine call is regular function call. No context is necessary.
|
||||
if b.Scheduler == "coroutines" {
|
||||
// The context parameter is assumed to be always present in the
|
||||
// coroutines scheduler.
|
||||
context = llvm.Undef(b.i8ptrType)
|
||||
}
|
||||
case *ssa.MakeClosure:
|
||||
// A goroutine call on a func value, but the callee is trivial to find. For
|
||||
// example: immediately applied functions.
|
||||
@@ -95,50 +90,31 @@ func (b *builder) createGo(instr *ssa.Go) {
|
||||
// * The function pointer (for tasks).
|
||||
var context llvm.Value
|
||||
funcPtr, context = b.decodeFuncValue(b.getValue(instr.Call.Value), instr.Call.Value.Type().Underlying().(*types.Signature))
|
||||
params = append(params, context) // context parameter
|
||||
params = append(params, context, funcPtr)
|
||||
hasContext = true
|
||||
switch b.Scheduler {
|
||||
case "none", "coroutines":
|
||||
// There are no additional parameters needed for the goroutine start operation.
|
||||
case "tasks", "asyncify":
|
||||
// Add the function pointer as a parameter to start the goroutine.
|
||||
params = append(params, funcPtr)
|
||||
default:
|
||||
panic("unknown scheduler type")
|
||||
}
|
||||
prefix = b.fn.RelString(nil)
|
||||
}
|
||||
|
||||
paramBundle := b.emitPointerPack(params)
|
||||
var callee, stackSize llvm.Value
|
||||
switch b.Scheduler {
|
||||
case "none", "tasks", "asyncify":
|
||||
callee = b.createGoroutineStartWrapper(funcPtr, prefix, hasContext, instr.Pos())
|
||||
if b.AutomaticStackSize {
|
||||
// The stack size is not known until after linking. Call a dummy
|
||||
// function that will be replaced with a load from a special ELF
|
||||
// section that contains the stack size (and is modified after
|
||||
// linking).
|
||||
stackSizeFn := b.getFunction(b.program.ImportedPackage("internal/task").Members["getGoroutineStackSize"].(*ssa.Function))
|
||||
stackSize = b.createCall(stackSizeFn, []llvm.Value{callee, llvm.Undef(b.i8ptrType), llvm.Undef(b.i8ptrType)}, "stacksize")
|
||||
} else {
|
||||
// The stack size is fixed at compile time. By emitting it here as a
|
||||
// constant, it can be optimized.
|
||||
if (b.Scheduler == "tasks" || b.Scheduler == "asyncify") && b.DefaultStackSize == 0 {
|
||||
b.addError(instr.Pos(), "default stack size for goroutines is not set")
|
||||
}
|
||||
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
|
||||
var stackSize llvm.Value
|
||||
callee := b.createGoroutineStartWrapper(funcPtr, prefix, hasContext, instr.Pos())
|
||||
if b.AutomaticStackSize {
|
||||
// The stack size is not known until after linking. Call a dummy
|
||||
// function that will be replaced with a load from a special ELF
|
||||
// section that contains the stack size (and is modified after
|
||||
// linking).
|
||||
stackSizeFn := b.getFunction(b.program.ImportedPackage("internal/task").Members["getGoroutineStackSize"].(*ssa.Function))
|
||||
stackSize = b.createCall(stackSizeFn, []llvm.Value{callee, llvm.Undef(b.i8ptrType)}, "stacksize")
|
||||
} else {
|
||||
// The stack size is fixed at compile time. By emitting it here as a
|
||||
// constant, it can be optimized.
|
||||
if (b.Scheduler == "tasks" || b.Scheduler == "asyncify") && b.DefaultStackSize == 0 {
|
||||
b.addError(instr.Pos(), "default stack size for goroutines is not set")
|
||||
}
|
||||
case "coroutines":
|
||||
callee = b.CreatePtrToInt(funcPtr, b.uintptrType, "")
|
||||
// There is no goroutine stack size: coroutines are used instead of
|
||||
// stacks.
|
||||
stackSize = llvm.Undef(b.uintptrType)
|
||||
default:
|
||||
panic("unreachable")
|
||||
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
|
||||
}
|
||||
start := b.getFunction(b.program.ImportedPackage("internal/task").Members["start"].(*ssa.Function))
|
||||
b.createCall(start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.i8ptrType), llvm.ConstPointerNull(b.i8ptrType)}, "")
|
||||
b.createCall(start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.i8ptrType)}, "")
|
||||
}
|
||||
|
||||
// createGoroutineStartWrapper creates a wrapper for the task-based
|
||||
@@ -217,7 +193,6 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
|
||||
|
||||
// Create the list of params for the call.
|
||||
paramTypes := fn.Type().ElementType().ParamTypes()
|
||||
paramTypes = paramTypes[:len(paramTypes)-1] // strip parentHandle parameter
|
||||
if !hasContext {
|
||||
paramTypes = paramTypes[:len(paramTypes)-1] // strip context parameter
|
||||
}
|
||||
@@ -225,14 +200,13 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
|
||||
if !hasContext {
|
||||
params = append(params, llvm.Undef(c.i8ptrType)) // add dummy context parameter
|
||||
}
|
||||
params = append(params, llvm.Undef(c.i8ptrType)) // add dummy parentHandle parameter
|
||||
|
||||
// Create the call.
|
||||
builder.CreateCall(fn, params, "")
|
||||
|
||||
if c.Scheduler == "asyncify" {
|
||||
builder.CreateCall(deadlock, []llvm.Value{
|
||||
llvm.Undef(c.i8ptrType), llvm.Undef(c.i8ptrType),
|
||||
llvm.Undef(c.i8ptrType),
|
||||
}, "")
|
||||
}
|
||||
|
||||
@@ -288,25 +262,19 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
|
||||
|
||||
// Get the list of parameters, with the extra parameters at the end.
|
||||
paramTypes := fn.Type().ElementType().ParamTypes()
|
||||
paramTypes[len(paramTypes)-1] = fn.Type() // the last element is the function pointer
|
||||
paramTypes = append(paramTypes, fn.Type()) // the last element is the function pointer
|
||||
params := llvmutil.EmitPointerUnpack(builder, c.mod, wrapper.Param(0), paramTypes)
|
||||
|
||||
// Get the function pointer.
|
||||
fnPtr := params[len(params)-1]
|
||||
|
||||
// The last parameter in the packed object has somewhat of a dual role.
|
||||
// Inside the parameter bundle it's the function pointer, stored right
|
||||
// after the context pointer. But in the IR call instruction, it's the
|
||||
// parentHandle function that's always undef outside of the coroutines
|
||||
// scheduler. Thus, make the parameter undef here.
|
||||
params[len(params)-1] = llvm.Undef(c.i8ptrType)
|
||||
params = params[:len(params)-1]
|
||||
|
||||
// Create the call.
|
||||
builder.CreateCall(fnPtr, params, "")
|
||||
|
||||
if c.Scheduler == "asyncify" {
|
||||
builder.CreateCall(deadlock, []llvm.Value{
|
||||
llvm.Undef(c.i8ptrType), llvm.Undef(c.i8ptrType),
|
||||
llvm.Undef(c.i8ptrType),
|
||||
}, "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
|
||||
// Magic function: insert inline assembly instead of calling it.
|
||||
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{}, false)
|
||||
asm := constant.StringVal(args[0].(*ssa.Const).Value)
|
||||
target := llvm.InlineAsm(fnType, asm, "", true, false, 0)
|
||||
target := llvm.InlineAsm(fnType, asm, "", true, false, 0, false)
|
||||
return b.CreateCall(target, nil, ""), nil
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
target := llvm.InlineAsm(fnType, asmString, strings.Join(constraints, ","), true, false, 0, false)
|
||||
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)
|
||||
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0, false)
|
||||
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)
|
||||
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0, false)
|
||||
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)
|
||||
target := llvm.InlineAsm(fnType, asm, "=r", true, false, 0, false)
|
||||
return b.CreateCall(target, nil, ""), nil
|
||||
case "Set":
|
||||
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.uintptrType}, false)
|
||||
asm := fmt.Sprintf("csrw %d, $0", csr)
|
||||
target := llvm.InlineAsm(fnType, asm, "r", true, false, 0)
|
||||
target := llvm.InlineAsm(fnType, asm, "r", true, false, 0, false)
|
||||
return b.CreateCall(target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
|
||||
case "SetBits":
|
||||
// Note: it may be possible to optimize this to csrrsi in many cases.
|
||||
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType}, false)
|
||||
asm := fmt.Sprintf("csrrs $0, %d, $1", csr)
|
||||
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0)
|
||||
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0, false)
|
||||
return b.CreateCall(target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
|
||||
case "ClearBits":
|
||||
// Note: it may be possible to optimize this to csrrci in many cases.
|
||||
fnType := llvm.FunctionType(b.uintptrType, []llvm.Type{b.uintptrType}, false)
|
||||
asm := fmt.Sprintf("csrrc $0, %d, $1", csr)
|
||||
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0)
|
||||
target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0, false)
|
||||
return b.CreateCall(target, []llvm.Value{b.getValue(call.Args[1])}, ""), nil
|
||||
default:
|
||||
return llvm.Value{}, b.makeError(call.Pos(), "unknown CSR operation: "+name)
|
||||
|
||||
+10
-3
@@ -31,6 +31,15 @@ func (b *builder) createMakeInterface(val llvm.Value, typ types.Type, pos token.
|
||||
return itf
|
||||
}
|
||||
|
||||
// extractValueFromInterface extract the value from an interface value
|
||||
// (runtime._interface) under the assumption that it is of the type given in
|
||||
// llvmType. The behavior is undefied if the interface is nil or llvmType
|
||||
// doesn't match the underlying type of the interface.
|
||||
func (b *builder) extractValueFromInterface(itf llvm.Value, llvmType llvm.Type) llvm.Value {
|
||||
valuePtr := b.CreateExtractValue(itf, 1, "typeassert.value.ptr")
|
||||
return b.emitPointerUnpack(valuePtr, []llvm.Type{llvmType})[0]
|
||||
}
|
||||
|
||||
// getTypeCode returns a reference to a type code.
|
||||
// It returns a pointer to an external global which should be replaced with the
|
||||
// real type in the interface lowering pass.
|
||||
@@ -416,8 +425,7 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
||||
} else {
|
||||
// Type assert on concrete type. Extract the underlying type from
|
||||
// the interface (but only after checking it matches).
|
||||
valuePtr := b.CreateExtractValue(itf, 1, "typeassert.value.ptr")
|
||||
valueOk = b.emitPointerUnpack(valuePtr, []llvm.Type{assertedType})[0]
|
||||
valueOk = b.extractValueFromInterface(itf, assertedType)
|
||||
}
|
||||
b.CreateBr(nextBlock)
|
||||
|
||||
@@ -522,7 +530,6 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFn llv
|
||||
wrapFnType := llvm.FunctionType(fnType.ReturnType(), paramTypes, false)
|
||||
wrapper = llvm.AddFunction(c.mod, wrapperName, wrapFnType)
|
||||
c.addStandardAttributes(wrapper)
|
||||
wrapper.LastParam().SetName("parentHandle")
|
||||
|
||||
wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
wrapper.SetUnnamedAddr(true)
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
||||
|
||||
// Create the global initializer.
|
||||
bitmapBytes := make([]byte, int(objectSizeWords+7)/8)
|
||||
copy(bitmapBytes, bitmap.Bytes())
|
||||
bitmap.FillBytes(bitmapBytes)
|
||||
var bitmapByteValues []llvm.Value
|
||||
for _, b := range bitmapBytes {
|
||||
bitmapByteValues = append(bitmapByteValues, llvm.ConstInt(c.ctx.Int8Type(), uint64(b), false))
|
||||
|
||||
@@ -97,15 +97,13 @@ func EmitPointerPack(builder llvm.Builder, mod llvm.Module, prefix string, needs
|
||||
packedHeapAlloc := builder.CreateCall(alloc, []llvm.Value{
|
||||
sizeValue,
|
||||
llvm.ConstNull(i8ptrType),
|
||||
llvm.Undef(i8ptrType), // unused context parameter
|
||||
llvm.ConstPointerNull(i8ptrType), // coroutine handle
|
||||
llvm.Undef(i8ptrType), // unused context parameter
|
||||
}, "")
|
||||
if needsStackObjects {
|
||||
trackPointer := mod.NamedFunction("runtime.trackPointer")
|
||||
builder.CreateCall(trackPointer, []llvm.Value{
|
||||
packedHeapAlloc,
|
||||
llvm.Undef(i8ptrType), // unused context parameter
|
||||
llvm.ConstPointerNull(i8ptrType), // coroutine handle
|
||||
llvm.Undef(i8ptrType), // unused context parameter
|
||||
}, "")
|
||||
}
|
||||
packedAlloc := builder.CreateBitCast(packedHeapAlloc, llvm.PointerType(packedType, 0), "")
|
||||
|
||||
@@ -167,6 +167,66 @@ func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos tok
|
||||
}
|
||||
}
|
||||
|
||||
// createMapIteratorNext lowers the *ssa.Next instruction for iterating over a
|
||||
// map. It returns a tuple of {bool, key, value} with the result of the
|
||||
// iteration.
|
||||
func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llvm.Value) llvm.Value {
|
||||
// Determine the type of the values to return from the *ssa.Next
|
||||
// instruction. It is returned as {bool, keyType, valueType}.
|
||||
keyType := rangeVal.Type().Underlying().(*types.Map).Key()
|
||||
valueType := rangeVal.Type().Underlying().(*types.Map).Elem()
|
||||
llvmKeyType := b.getLLVMType(keyType)
|
||||
llvmValueType := b.getLLVMType(valueType)
|
||||
|
||||
// There is a special case in which keys are stored as an interface value
|
||||
// instead of the value they normally are. This happens for non-trivially
|
||||
// comparable types such as float32 or some structs.
|
||||
isKeyStoredAsInterface := false
|
||||
if t, ok := keyType.Underlying().(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
// key is a string
|
||||
} else if hashmapIsBinaryKey(keyType) {
|
||||
// key can be compared with runtime.memequal
|
||||
} else {
|
||||
// The key is stored as an interface value, and may or may not be an
|
||||
// interface type (for example, float32 keys are stored as an interface
|
||||
// value).
|
||||
if _, ok := keyType.Underlying().(*types.Interface); !ok {
|
||||
isKeyStoredAsInterface = true
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the type of the key as stored in the map.
|
||||
llvmStoredKeyType := llvmKeyType
|
||||
if isKeyStoredAsInterface {
|
||||
llvmStoredKeyType = b.getLLVMRuntimeType("_interface")
|
||||
}
|
||||
|
||||
// Extract the key and value from the map.
|
||||
mapKeyAlloca, mapKeyPtr, mapKeySize := b.createTemporaryAlloca(llvmStoredKeyType, "range.key")
|
||||
mapValueAlloca, mapValuePtr, mapValueSize := b.createTemporaryAlloca(llvmValueType, "range.value")
|
||||
ok := b.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyPtr, mapValuePtr}, "range.next")
|
||||
mapKey := b.CreateLoad(mapKeyAlloca, "")
|
||||
mapValue := b.CreateLoad(mapValueAlloca, "")
|
||||
|
||||
if isKeyStoredAsInterface {
|
||||
// The key is stored as an interface but it isn't of interface type.
|
||||
// Extract the underlying value.
|
||||
mapKey = b.extractValueFromInterface(mapKey, llvmKeyType)
|
||||
}
|
||||
|
||||
// End the lifetimes of the allocas, because we're done with them.
|
||||
b.emitLifetimeEnd(mapKeyPtr, mapKeySize)
|
||||
b.emitLifetimeEnd(mapValuePtr, mapValueSize)
|
||||
|
||||
// Construct the *ssa.Next return value: {ok, mapKey, mapValue}
|
||||
tuple := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
|
||||
tuple = b.CreateInsertValue(tuple, ok, 0, "")
|
||||
tuple = b.CreateInsertValue(tuple, mapKey, 1, "")
|
||||
tuple = b.CreateInsertValue(tuple, mapValue, 2, "")
|
||||
|
||||
return tuple
|
||||
}
|
||||
|
||||
// Returns true if this key type does not contain strings, interfaces etc., so
|
||||
// can be compared with runtime.memequal.
|
||||
func hashmapIsBinaryKey(keyType types.Type) bool {
|
||||
|
||||
@@ -84,7 +84,6 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
|
||||
// closures and bound methods, but should be optimized away when not used.
|
||||
if !info.exported {
|
||||
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "context", flags: 0})
|
||||
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "parentHandle", flags: 0})
|
||||
}
|
||||
|
||||
var paramTypes []llvm.Type
|
||||
|
||||
+4
-4
@@ -56,7 +56,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
}
|
||||
constraints += ",~{rcx},~{r11}"
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel)
|
||||
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel, false)
|
||||
return b.CreateCall(target, args, ""), nil
|
||||
case b.GOARCH == "386" && b.GOOS == "linux":
|
||||
// Sources:
|
||||
@@ -82,7 +82,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel)
|
||||
target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel, false)
|
||||
return b.CreateCall(target, args, ""), nil
|
||||
case b.GOARCH == "arm" && b.GOOS == "linux":
|
||||
// Implement the EABI system call convention for Linux.
|
||||
@@ -114,7 +114,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
constraints += ",~{r" + strconv.Itoa(i) + "}"
|
||||
}
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
|
||||
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0, false)
|
||||
return b.CreateCall(target, args, ""), nil
|
||||
case b.GOARCH == "arm64" && b.GOOS == "linux":
|
||||
// Source: syscall(2) man page.
|
||||
@@ -146,7 +146,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
}
|
||||
constraints += ",~{x16},~{x17}" // scratch registers
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
|
||||
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0, false)
|
||||
return b.CreateCall(target, args, ""), nil
|
||||
default:
|
||||
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
|
||||
|
||||
Vendored
+30
-28
@@ -1,41 +1,43 @@
|
||||
; ModuleID = 'basic.go'
|
||||
source_filename = "basic.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%main.kv = type { float }
|
||||
%main.kv.0 = type { i8 }
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.addInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.addInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = add i32 %x, %y
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.equalInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.equalInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.divInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.divInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
|
||||
divbyzero.throw: ; preds = %entry
|
||||
call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0
|
||||
call void @runtime.divideByZeroPanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
divbyzero.next: ; preds = %entry
|
||||
@@ -47,16 +49,16 @@ divbyzero.next: ; preds = %entry
|
||||
ret i32 %5
|
||||
}
|
||||
|
||||
declare void @runtime.divideByZeroPanic(i8*, i8*)
|
||||
declare void @runtime.divideByZeroPanic(i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.divUint(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.divUint(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
|
||||
divbyzero.throw: ; preds = %entry
|
||||
call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0
|
||||
call void @runtime.divideByZeroPanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
divbyzero.next: ; preds = %entry
|
||||
@@ -65,13 +67,13 @@ divbyzero.next: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.remInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.remInt(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
|
||||
divbyzero.throw: ; preds = %entry
|
||||
call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0
|
||||
call void @runtime.divideByZeroPanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
divbyzero.next: ; preds = %entry
|
||||
@@ -84,13 +86,13 @@ divbyzero.next: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.remUint(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.remUint(i32 %x, i32 %y, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = icmp eq i32 %y, 0
|
||||
br i1 %0, label %divbyzero.throw, label %divbyzero.next
|
||||
|
||||
divbyzero.throw: ; preds = %entry
|
||||
call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0
|
||||
call void @runtime.divideByZeroPanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
divbyzero.next: ; preds = %entry
|
||||
@@ -99,61 +101,61 @@ divbyzero.next: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatEQ(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.floatEQ(float %x, float %y, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = fcmp oeq float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatNE(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.floatNE(float %x, float %y, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = fcmp une float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatLower(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.floatLower(float %x, float %y, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = fcmp olt float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatLowerEqual(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.floatLowerEqual(float %x, float %y, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = fcmp ole float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatGreater(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.floatGreater(float %x, float %y, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = fcmp ogt float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.floatGreaterEqual(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.floatGreaterEqual(float %x, float %y, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = fcmp oge float %x, %y
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.complexReal(float %x.r, float %x.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden float @main.complexReal(float %x.r, float %x.i, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret float %x.r
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.complexImag(float %x.r, float %x.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden float @main.complexImag(float %x.r, float %x.i, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret float %x.i
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = fadd float %x.r, %y.r
|
||||
%1 = fadd float %x.i, %y.i
|
||||
@@ -163,7 +165,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = fsub float %x.r, %y.r
|
||||
%1 = fsub float %x.i, %y.i
|
||||
@@ -173,7 +175,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = fmul float %x.r, %y.r
|
||||
%1 = fmul float %x.i, %y.i
|
||||
@@ -187,14 +189,14 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.foo(%main.kv* dereferenceable_or_null(4) %a, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.foo(%main.kv* dereferenceable_or_null(4) %a, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @"main.foo$1"(%main.kv.0* null, i8* undef, i8* undef)
|
||||
call void @"main.foo$1"(%main.kv.0* null, i8* undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
Vendored
+23
-17
@@ -1,25 +1,28 @@
|
||||
; ModuleID = 'channel.go'
|
||||
source_filename = "channel.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
|
||||
%"internal/task.gcData" = type { i8* }
|
||||
%"internal/task.state" = type { i32, i8*, %"internal/task.stackState", i1 }
|
||||
%"internal/task.stackState" = type { i32, i32 }
|
||||
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanIntSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.chanIntSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||
%chan.value = alloca i32, align 4
|
||||
@@ -28,7 +31,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, i8* null) #0
|
||||
call void @runtime.chanSend(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
|
||||
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
|
||||
ret void
|
||||
@@ -37,13 +40,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*, i8*)
|
||||
declare void @runtime.chanSend(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), 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, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.chanIntRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||
%chan.value = alloca i32, align 4
|
||||
@@ -51,38 +54,41 @@ entry:
|
||||
call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
|
||||
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
|
||||
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef, i8* null) #0
|
||||
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* nonnull %chan.value.bitcast, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
|
||||
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %chan.value.bitcast)
|
||||
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i1 @runtime.chanRecv(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*, i8*)
|
||||
declare i1 @runtime.chanRecv(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanZeroSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.chanZeroSend(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%complit = alloca {}, align 8
|
||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||
%0 = bitcast {}* %complit to i8*
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
|
||||
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||
call void @runtime.chanSend(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef, i8* null) #0
|
||||
call void @runtime.chanSend(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
|
||||
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.chanZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.chanZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%chan.blockedList = alloca %runtime.channelBlockedList, align 8
|
||||
%chan.blockedList.bitcast = bitcast %runtime.channelBlockedList* %chan.blockedList to i8*
|
||||
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef, i8* null) #0
|
||||
%0 = call i1 @runtime.chanRecv(%runtime.channel* %ch, i8* null, %runtime.channelBlockedList* nonnull %chan.blockedList, i8* undef) #0
|
||||
call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %chan.blockedList.bitcast)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.selectZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch1, %runtime.channel* dereferenceable_or_null(32) %ch2, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.selectZeroRecv(%runtime.channel* dereferenceable_or_null(32) %ch1, %runtime.channel* dereferenceable_or_null(32) %ch2, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8
|
||||
%select.send.value = alloca i32, align 4
|
||||
@@ -99,7 +105,7 @@ entry:
|
||||
%.repack4 = getelementptr inbounds [2 x %runtime.chanSelectState], [2 x %runtime.chanSelectState]* %select.states.alloca, i32 0, i32 1, i32 1
|
||||
store i8* null, i8** %.repack4, align 4
|
||||
%select.states = getelementptr inbounds [2 x %runtime.chanSelectState], [2 x %runtime.chanSelectState]* %select.states.alloca, i32 0, i32 0
|
||||
%select.result = call { i32, i1 } @runtime.tryChanSelect(i8* undef, %runtime.chanSelectState* nonnull %select.states, i32 2, i32 2, i8* undef, i8* null) #0
|
||||
%select.result = call { i32, i1 } @runtime.tryChanSelect(i8* undef, %runtime.chanSelectState* nonnull %select.states, i32 2, i32 2, i8* undef) #0
|
||||
call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %select.states.alloca.bitcast)
|
||||
%1 = extractvalue { i32, i1 } %select.result, 0
|
||||
%2 = icmp eq i32 %1, 0
|
||||
@@ -116,7 +122,7 @@ select.body: ; preds = %select.next
|
||||
br label %select.done
|
||||
}
|
||||
|
||||
declare { i32, i1 } @runtime.tryChanSelect(i8*, %runtime.chanSelectState*, i32, i32, i8*, i8*)
|
||||
declare { i32, i1 } @runtime.tryChanSelect(i8*, %runtime.chanSelectState*, i32, i32, i8*)
|
||||
|
||||
attributes #0 = { nounwind }
|
||||
attributes #1 = { argmemonly nofree nosync nounwind willreturn }
|
||||
|
||||
Vendored
+13
-11
@@ -1,18 +1,20 @@
|
||||
; ModuleID = 'float.go'
|
||||
source_filename = "float.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.f32tou32(float %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.f32tou32(float %v, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%positive = fcmp oge float %v, 0.000000e+00
|
||||
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
|
||||
@@ -24,25 +26,25 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.maxu32f(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden float @main.maxu32f(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret float 0x41F0000000000000
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.maxu32tof32(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.maxu32tof32(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret i32 -1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i32, i32, i32, i32 } @main.inftoi32(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { i32, i32, i32, i32 } @main.inftoi32(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.u32tof32tou32(i32 %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.u32tof32tou32(i32 %v, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = uitofp i32 %v to float
|
||||
%withinmax = fcmp ole float %0, 0x41EFFFFFC0000000
|
||||
@@ -52,7 +54,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.f32tou32tof32(float %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden float @main.f32tou32tof32(float %v, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%positive = fcmp oge float %v, 0.000000e+00
|
||||
%withinmax = fcmp ole float %v, 0x41EFFFFFC0000000
|
||||
@@ -65,7 +67,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.f32tou8(float %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i8 @main.f32tou8(float %v, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%positive = fcmp oge float %v, 0.000000e+00
|
||||
%withinmax = fcmp ole float %v, 2.550000e+02
|
||||
@@ -77,7 +79,7 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.f32toi8(float %v, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i8 @main.f32toi8(float %v, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%abovemin = fcmp oge float %v, -1.280000e+02
|
||||
%belowmax = fcmp ole float %v, 1.270000e+02
|
||||
|
||||
Vendored
-53
@@ -1,53 +0,0 @@
|
||||
; ModuleID = 'func.go'
|
||||
source_filename = "func.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime.funcValueWithSignature = type { i32, i8* }
|
||||
|
||||
@"reflect/types.funcid:func:{basic:int}{}" = external constant i8
|
||||
@"main.someFunc$withSignature" = linkonce_odr constant %runtime.funcValueWithSignature { i32 ptrtoint (void (i32, i8*, i8*)* @main.someFunc to i32), i8* @"reflect/types.funcid:func:{basic:int}{}" }
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.foo(i8* %callback.context, i32 %callback.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i32 @runtime.getFuncPtr(i8* %callback.context, i32 %callback.funcptr, i8* nonnull @"reflect/types.funcid:func:{basic:int}{}", i8* undef, i8* null) #0
|
||||
%1 = icmp eq i32 %0, 0
|
||||
br i1 %1, label %fpcall.throw, label %fpcall.next
|
||||
|
||||
fpcall.throw: ; preds = %entry
|
||||
call void @runtime.nilPanic(i8* undef, i8* null) #0
|
||||
unreachable
|
||||
|
||||
fpcall.next: ; preds = %entry
|
||||
%2 = inttoptr i32 %0 to void (i32, i8*, i8*)*
|
||||
call void %2(i32 3, i8* %callback.context, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @runtime.getFuncPtr(i8*, i32, i8* dereferenceable_or_null(1), i8*, i8*)
|
||||
|
||||
declare void @runtime.nilPanic(i8*, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.bar(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @main.foo(i8* undef, i32 ptrtoint (%runtime.funcValueWithSignature* @"main.someFunc$withSignature" to i32), i8* undef, i8* undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.someFunc(i32 %arg0, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { nounwind }
|
||||
Vendored
+47
@@ -0,0 +1,47 @@
|
||||
; 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 }
|
||||
Vendored
+8
-5
@@ -20,6 +20,10 @@ var (
|
||||
y [60]uintptr
|
||||
z *byte
|
||||
}
|
||||
struct4 *struct {
|
||||
x *byte
|
||||
y [61]uintptr
|
||||
}
|
||||
|
||||
slice1 []byte
|
||||
slice2 []*int
|
||||
@@ -50,14 +54,13 @@ func newStruct() {
|
||||
y [60]uintptr
|
||||
z *byte
|
||||
})
|
||||
struct4 = new(struct {
|
||||
x *byte
|
||||
y [61]uintptr
|
||||
})
|
||||
}
|
||||
|
||||
func newFuncValue() *func() {
|
||||
// On some platforms that use runtime.funcValue ("switch" style) function
|
||||
// values, a func value is allocated as having two pointer words while the
|
||||
// struct looks like {unsafe.Pointer; uintptr}. This is so that the interp
|
||||
// package won't get confused, see getPointerBitmap in compiler/llvm.go for
|
||||
// details.
|
||||
return new(func())
|
||||
}
|
||||
|
||||
|
||||
Vendored
+47
-24
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'gc.go'
|
||||
source_filename = "gc.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID*, i32 }
|
||||
@@ -17,79 +17,100 @@ target triple = "wasm32-unknown-wasi"
|
||||
@main.struct1 = hidden global {}* null, align 4
|
||||
@main.struct2 = hidden global { i32, i32 }* null, align 4
|
||||
@main.struct3 = hidden global { i8*, [60 x i32], i8* }* null, align 4
|
||||
@main.struct4 = hidden global { i8*, [61 x i32] }* null, align 4
|
||||
@main.slice1 = hidden global { i8*, i32, i32 } zeroinitializer, align 8
|
||||
@main.slice2 = hidden global { i32**, i32, i32 } zeroinitializer, align 8
|
||||
@main.slice3 = hidden global { { i8*, i32, i32 }*, i32, i32 } zeroinitializer, align 8
|
||||
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c" \00\00\00\00\00\00\01" }
|
||||
@"runtime/gc.layout:62-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\00\00\00\00\00\00\00\01" }
|
||||
@"reflect/types.type:basic:complex128" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* null, i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:basic:complex128", i32 0 }
|
||||
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:complex128", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null, i32 0 }
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.newScalar(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.newScalar(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%new = call i8* @runtime.alloc(i32 1, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%new = call i8* @runtime.alloc(i32 1, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
|
||||
store i8* %new, i8** @main.scalar1, align 4
|
||||
%new1 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%new1 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #0
|
||||
store i8* %new1, i8** bitcast (i32** @main.scalar2 to i8**), align 4
|
||||
%new2 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%new2 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #0
|
||||
store i8* %new2, i8** bitcast (i64** @main.scalar3 to i8**), align 4
|
||||
%new3 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%new3 = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %new3, i8* undef) #0
|
||||
store i8* %new3, i8** bitcast (float** @main.scalar4 to i8**), align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.newArray(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.newArray(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%new = call i8* @runtime.alloc(i32 3, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%new = call i8* @runtime.alloc(i32 3, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
|
||||
store i8* %new, i8** bitcast ([3 x i8]** @main.array1 to i8**), align 4
|
||||
%new1 = call i8* @runtime.alloc(i32 71, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%new1 = call i8* @runtime.alloc(i32 71, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #0
|
||||
store i8* %new1, i8** bitcast ([71 x i8]** @main.array2 to i8**), align 4
|
||||
%new2 = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 67 to i8*), i8* undef, i8* null) #0
|
||||
%new2 = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 67 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #0
|
||||
store i8* %new2, i8** bitcast ([3 x i8*]** @main.array3 to i8**), align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.newStruct(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.newStruct(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%new = call i8* @runtime.alloc(i32 0, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%new = call i8* @runtime.alloc(i32 0, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
|
||||
store i8* %new, i8** bitcast ({}** @main.struct1 to i8**), align 4
|
||||
%new1 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%new1 = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %new1, i8* undef) #0
|
||||
store i8* %new1, i8** bitcast ({ i32, i32 }** @main.struct2 to i8**), align 4
|
||||
%new2 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-2000000000000001" to i8*), i8* undef, i8* null) #0
|
||||
%new2 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-2000000000000001" to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %new2, i8* undef) #0
|
||||
store i8* %new2, i8** bitcast ({ i8*, [60 x i32], i8* }** @main.struct3 to i8**), align 4
|
||||
%new3 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-0001" to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %new3, i8* undef) #0
|
||||
store i8* %new3, i8** bitcast ({ i8*, [61 x i32] }** @main.struct4 to i8**), align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i8*, void ()* }* @main.newFuncValue(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { i8*, void ()* }* @main.newFuncValue(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%new = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 197 to i8*), i8* undef, i8* null) #0
|
||||
%new = call i8* @runtime.alloc(i32 8, i8* nonnull inttoptr (i32 197 to i8*), i8* undef) #0
|
||||
%0 = bitcast i8* %new to { i8*, void ()* }*
|
||||
call void @runtime.trackPointer(i8* nonnull %new, i8* undef) #0
|
||||
ret { i8*, void ()* }* %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.makeSlice(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.makeSlice(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%makeslice = call i8* @runtime.alloc(i32 5, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%makeslice = call i8* @runtime.alloc(i32 5, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #0
|
||||
store i8* %makeslice, i8** getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 0), align 8
|
||||
store i32 5, i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 1), align 4
|
||||
store i32 5, i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @main.slice1, i32 0, i32 2), align 8
|
||||
%makeslice1 = call i8* @runtime.alloc(i32 20, i8* nonnull inttoptr (i32 67 to i8*), i8* undef, i8* null) #0
|
||||
%makeslice1 = call i8* @runtime.alloc(i32 20, i8* nonnull inttoptr (i32 67 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %makeslice1, i8* undef) #0
|
||||
store i8* %makeslice1, i8** bitcast ({ i32**, i32, i32 }* @main.slice2 to i8**), align 8
|
||||
store i32 5, i32* getelementptr inbounds ({ i32**, i32, i32 }, { i32**, i32, i32 }* @main.slice2, i32 0, i32 1), align 4
|
||||
store i32 5, i32* getelementptr inbounds ({ i32**, i32, i32 }, { i32**, i32, i32 }* @main.slice2, i32 0, i32 2), align 8
|
||||
%makeslice3 = call i8* @runtime.alloc(i32 60, i8* nonnull inttoptr (i32 71 to i8*), i8* undef, i8* null) #0
|
||||
%makeslice3 = call i8* @runtime.alloc(i32 60, i8* nonnull inttoptr (i32 71 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %makeslice3, i8* undef) #0
|
||||
store i8* %makeslice3, i8** bitcast ({ { i8*, i32, i32 }*, i32, i32 }* @main.slice3 to i8**), align 8
|
||||
store i32 5, i32* getelementptr inbounds ({ { i8*, i32, i32 }*, i32, i32 }, { { i8*, i32, i32 }*, i32, i32 }* @main.slice3, i32 0, i32 1), align 4
|
||||
store i32 5, i32* getelementptr inbounds ({ { i8*, i32, i32 }*, i32, i32 }, { { i8*, i32, i32 }*, i32, i32 }* @main.slice3, i32 0, i32 2), align 8
|
||||
@@ -97,15 +118,17 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef, i8* null) #0
|
||||
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||
%.repack = bitcast i8* %0 to double*
|
||||
store double %v.r, double* %.repack, align 8
|
||||
%.repack1 = getelementptr inbounds i8, i8* %0, i32 8
|
||||
%1 = bitcast i8* %.repack1 to double*
|
||||
store double %v.i, double* %1, align 8
|
||||
%2 = insertvalue %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:basic:complex128" to i32), i8* undef }, i8* %0, 1
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||
ret %runtime._interface %2
|
||||
}
|
||||
|
||||
|
||||
Vendored
+31
-19
@@ -1,39 +1,43 @@
|
||||
; ModuleID = 'go1.17.go'
|
||||
source_filename = "go1.17.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8* @main.Add32(i8* %p, i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i8* @main.Add32(i8* %p, i32 %len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = getelementptr i8, i8* %p, i32 %len
|
||||
call void @runtime.trackPointer(i8* %0, i8* undef) #0
|
||||
ret i8* %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8* @main.Add64(i8* %p, i64 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i8* @main.Add64(i8* %p, i64 %len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = trunc i64 %len to i32
|
||||
%1 = getelementptr i8, i8* %p, i32 %0
|
||||
call void @runtime.trackPointer(i8* %1, i8* undef) #0
|
||||
ret i8* %1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden [4 x i32]* @main.SliceToArray(i32* %s.data, i32 %s.len, i32 %s.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden [4 x i32]* @main.SliceToArray(i32* %s.data, i32 %s.len, i32 %s.cap, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = icmp ult i32 %s.len, 4
|
||||
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next
|
||||
|
||||
slicetoarray.throw: ; preds = %entry
|
||||
call void @runtime.sliceToArrayPointerPanic(i8* undef, i8* null) #0
|
||||
call void @runtime.sliceToArrayPointerPanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
slicetoarray.next: ; preds = %entry
|
||||
@@ -41,12 +45,13 @@ slicetoarray.next: ; preds = %entry
|
||||
ret [4 x i32]* %1
|
||||
}
|
||||
|
||||
declare void @runtime.sliceToArrayPointerPanic(i8*, i8*)
|
||||
declare void @runtime.sliceToArrayPointerPanic(i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden [4 x i32]* @main.SliceToArrayConst(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden [4 x i32]* @main.SliceToArrayConst(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%makeslice = call i8* @runtime.alloc(i32 24, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%makeslice = call i8* @runtime.alloc(i32 24, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #0
|
||||
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
|
||||
|
||||
slicetoarray.throw: ; preds = %entry
|
||||
@@ -58,7 +63,7 @@ slicetoarray.next: ; preds = %entry
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i32*, i32, i32 } @main.SliceInt(i32* dereferenceable_or_null(4) %ptr, i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { i32*, i32, i32 } @main.SliceInt(i32* dereferenceable_or_null(4) %ptr, i32 %len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = icmp ugt i32 %len, 1073741823
|
||||
%1 = icmp eq i32* %ptr, null
|
||||
@@ -68,20 +73,22 @@ entry:
|
||||
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0
|
||||
call void @runtime.unsafeSlicePanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
unsafe.Slice.next: ; preds = %entry
|
||||
%5 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
|
||||
%6 = insertvalue { i32*, i32, i32 } %5, i32 %len, 1
|
||||
%7 = insertvalue { i32*, i32, i32 } %6, i32 %len, 2
|
||||
%8 = bitcast i32* %ptr to i8*
|
||||
call void @runtime.trackPointer(i8* %8, i8* undef) #0
|
||||
ret { i32*, i32, i32 } %7
|
||||
}
|
||||
|
||||
declare void @runtime.unsafeSlicePanic(i8*, i8*)
|
||||
declare void @runtime.unsafeSlicePanic(i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i8*, i32, i32 } @main.SliceUint16(i8* dereferenceable_or_null(1) %ptr, i16 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { i8*, i32, i32 } @main.SliceUint16(i8* dereferenceable_or_null(1) %ptr, i16 %len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = icmp eq i8* %ptr, null
|
||||
%1 = icmp ne i16 %len, 0
|
||||
@@ -89,7 +96,7 @@ entry:
|
||||
br i1 %2, label %unsafe.Slice.throw, label %unsafe.Slice.next
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0
|
||||
call void @runtime.unsafeSlicePanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
unsafe.Slice.next: ; preds = %entry
|
||||
@@ -97,11 +104,12 @@ unsafe.Slice.next: ; preds = %entry
|
||||
%4 = insertvalue { i8*, i32, i32 } undef, i8* %ptr, 0
|
||||
%5 = insertvalue { i8*, i32, i32 } %4, i32 %3, 1
|
||||
%6 = insertvalue { i8*, i32, i32 } %5, i32 %3, 2
|
||||
call void @runtime.trackPointer(i8* %ptr, i8* undef) #0
|
||||
ret { i8*, i32, i32 } %6
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i32*, i32, i32 } @main.SliceUint64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { i32*, i32, i32 } @main.SliceUint64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = icmp ugt i64 %len, 1073741823
|
||||
%1 = icmp eq i32* %ptr, null
|
||||
@@ -111,7 +119,7 @@ entry:
|
||||
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0
|
||||
call void @runtime.unsafeSlicePanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
unsafe.Slice.next: ; preds = %entry
|
||||
@@ -119,11 +127,13 @@ unsafe.Slice.next: ; preds = %entry
|
||||
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
|
||||
%7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1
|
||||
%8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2
|
||||
%9 = bitcast i32* %ptr to i8*
|
||||
call void @runtime.trackPointer(i8* %9, i8* undef) #0
|
||||
ret { i32*, i32, i32 } %8
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i32*, i32, i32 } @main.SliceInt64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { i32*, i32, i32 } @main.SliceInt64(i32* dereferenceable_or_null(4) %ptr, i64 %len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = icmp ugt i64 %len, 1073741823
|
||||
%1 = icmp eq i32* %ptr, null
|
||||
@@ -133,7 +143,7 @@ entry:
|
||||
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next
|
||||
|
||||
unsafe.Slice.throw: ; preds = %entry
|
||||
call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0
|
||||
call void @runtime.unsafeSlicePanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
unsafe.Slice.next: ; preds = %entry
|
||||
@@ -141,6 +151,8 @@ unsafe.Slice.next: ; preds = %entry
|
||||
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
|
||||
%7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1
|
||||
%8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2
|
||||
%9 = bitcast i32* %ptr to i8*
|
||||
call void @runtime.trackPointer(i8* %9, i8* undef) #0
|
||||
ret { i32*, i32, i32 } %8
|
||||
}
|
||||
|
||||
|
||||
+45
-44
@@ -5,52 +5,53 @@ target triple = "thumbv7m-unknown-unknown-eabi"
|
||||
|
||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
|
||||
%"internal/task.gcData" = type {}
|
||||
%"internal/task.state" = type { i32, i32* }
|
||||
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
||||
|
||||
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.regularFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.regularFunctionGoroutine(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* undef, i8* undef) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef, i8* null) #0
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* undef) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.regularFunction(i32, i8*, i8*)
|
||||
declare void @main.regularFunction(i32, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.regularFunction$gowrapper"(i8* %0) unnamed_addr #1 {
|
||||
entry:
|
||||
%unpack.int = ptrtoint i8* %0 to i32
|
||||
call void @main.regularFunction(i32 %unpack.int, i8* undef, i8* undef) #0
|
||||
call void @main.regularFunction(i32 %unpack.int, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @"internal/task.getGoroutineStackSize"(i32, i8*, i8*)
|
||||
declare i32 @"internal/task.getGoroutineStackSize"(i32, i8*)
|
||||
|
||||
declare void @"internal/task.start"(i32, i8*, i32, i8*, i8*)
|
||||
declare void @"internal/task.start"(i32, i8*, i32, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.inlineFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.inlineFunctionGoroutine(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* undef, i8* undef) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef, i8* null) #0
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* undef) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 %stacksize, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
@@ -59,31 +60,31 @@ entry:
|
||||
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #2 {
|
||||
entry:
|
||||
%unpack.int = ptrtoint i8* %0 to i32
|
||||
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef, i8* undef)
|
||||
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closureFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.closureFunctionGoroutine(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
%0 = bitcast i8* %n to i32*
|
||||
store i32 3, i32* %0, align 4
|
||||
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef, i8* null) #0
|
||||
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef) #0
|
||||
%2 = bitcast i8* %1 to i32*
|
||||
store i32 5, i32* %2, align 4
|
||||
%3 = getelementptr inbounds i8, i8* %1, i32 4
|
||||
%4 = bitcast i8* %3 to i8**
|
||||
store i8* %n, i8** %4, align 4
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* undef, i8* undef) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 %stacksize, i8* undef, i8* null) #0
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* undef) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 %stacksize, i8* undef) #0
|
||||
%5 = load i32, i32* %0, align 4
|
||||
call void @runtime.printint32(i32 %5, i8* undef, i8* null) #0
|
||||
call void @runtime.printint32(i32 %5, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%unpack.ptr = bitcast i8* %context to i32*
|
||||
store i32 7, i32* %unpack.ptr, align 4
|
||||
@@ -98,16 +99,16 @@ entry:
|
||||
%3 = getelementptr inbounds i8, i8* %0, i32 4
|
||||
%4 = bitcast i8* %3 to i8**
|
||||
%5 = load i8*, i8** %4, align 4
|
||||
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5, i8* undef)
|
||||
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.printint32(i32, i8*, i8*)
|
||||
declare void @runtime.printint32(i32, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef, i8* null) #0
|
||||
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef) #0
|
||||
%1 = bitcast i8* %0 to i32*
|
||||
store i32 5, i32* %1, align 4
|
||||
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
||||
@@ -116,8 +117,8 @@ entry:
|
||||
%4 = getelementptr inbounds i8, i8* %0, i32 8
|
||||
%5 = bitcast i8* %4 to void ()**
|
||||
store void ()* %fn.funcptr, void ()** %5, align 4
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* undef, i8* undef) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 %stacksize, i8* undef, i8* null) #0
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* undef) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 %stacksize, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -130,40 +131,40 @@ entry:
|
||||
%4 = bitcast i8* %3 to i8**
|
||||
%5 = load i8*, i8** %4, align 4
|
||||
%6 = getelementptr inbounds i8, i8* %0, i32 8
|
||||
%7 = bitcast i8* %6 to void (i32, i8*, i8*)**
|
||||
%8 = load void (i32, i8*, i8*)*, void (i32, i8*, i8*)** %7, align 4
|
||||
call void %8(i32 %2, i8* %5, i8* undef) #0
|
||||
%7 = bitcast i8* %6 to void (i32, i8*)**
|
||||
%8 = load void (i32, i8*)*, void (i32, i8*)** %7, align 4
|
||||
call void %8(i32 %2, i8* %5) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.recoverBuiltinGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.recoverBuiltinGoroutine(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef, i8* null) #0
|
||||
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
|
||||
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef, i8* null) #0
|
||||
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*, i8*)
|
||||
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef, i8* null) #0
|
||||
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #0
|
||||
%1 = bitcast i8* %0 to i8**
|
||||
store i8* %itf.value, i8** %1, align 4
|
||||
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
||||
@@ -175,12 +176,12 @@ entry:
|
||||
%4 = getelementptr inbounds i8, i8* %0, i32 12
|
||||
%5 = bitcast i8* %4 to i32*
|
||||
store i32 %itf.typecode, i32* %5, align 4
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* undef, i8* undef) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 %stacksize, i8* undef, i8* null) #0
|
||||
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* undef) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 %stacksize, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*, i8*) #5
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*) #5
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(i8* %0) unnamed_addr #6 {
|
||||
@@ -196,7 +197,7 @@ entry:
|
||||
%9 = getelementptr inbounds i8, i8* %0, i32 12
|
||||
%10 = bitcast i8* %9 to i32*
|
||||
%11 = load i32, i32* %10, align 4
|
||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef, i8* undef) #0
|
||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
+54
-45
@@ -1,56 +1,59 @@
|
||||
; ModuleID = 'goroutine.go'
|
||||
source_filename = "goroutine.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
|
||||
%"internal/task.gcData" = type { i8* }
|
||||
%"internal/task.state" = type { i32, i8*, %"internal/task.stackState", i1 }
|
||||
%"internal/task.stackState" = type { i32, i32 }
|
||||
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
||||
|
||||
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.regularFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.regularFunctionGoroutine(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 8192, i8* undef, i8* null) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.regularFunction$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 16384, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.regularFunction(i32, i8*, i8*)
|
||||
declare void @main.regularFunction(i32, i8*)
|
||||
|
||||
declare void @runtime.deadlock(i8*, i8*)
|
||||
declare void @runtime.deadlock(i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"main.regularFunction$gowrapper"(i8* %0) unnamed_addr #1 {
|
||||
entry:
|
||||
%unpack.int = ptrtoint i8* %0 to i32
|
||||
call void @main.regularFunction(i32 %unpack.int, i8* undef, i8* undef) #0
|
||||
call void @runtime.deadlock(i8* undef, i8* undef) #0
|
||||
call void @main.regularFunction(i32 %unpack.int, i8* undef) #0
|
||||
call void @runtime.deadlock(i8* undef) #0
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @"internal/task.start"(i32, i8*, i32, i8*, i8*)
|
||||
declare void @"internal/task.start"(i32, i8*, i32, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.inlineFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.inlineFunctionGoroutine(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 8192, i8* undef, i8* null) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.inlineFunctionGoroutine$1$gowrapper" to i32), i8* nonnull inttoptr (i32 5 to i8*), i32 16384, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
@@ -59,31 +62,35 @@ entry:
|
||||
define linkonce_odr void @"main.inlineFunctionGoroutine$1$gowrapper"(i8* %0) unnamed_addr #2 {
|
||||
entry:
|
||||
%unpack.int = ptrtoint i8* %0 to i32
|
||||
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef, i8* undef)
|
||||
call void @runtime.deadlock(i8* undef, i8* undef) #0
|
||||
call void @"main.inlineFunctionGoroutine$1"(i32 %unpack.int, i8* undef)
|
||||
call void @runtime.deadlock(i8* undef) #0
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closureFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.closureFunctionGoroutine(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
%0 = bitcast i8* %n to i32*
|
||||
call void @runtime.trackPointer(i8* nonnull %n, i8* undef) #0
|
||||
store i32 3, i32* %0, align 4
|
||||
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef, i8* null) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %n, i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* bitcast (void (i32, i8*)* @"main.closureFunctionGoroutine$1" to i8*), i8* undef) #0
|
||||
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %1, i8* undef) #0
|
||||
%2 = bitcast i8* %1 to i32*
|
||||
store i32 5, i32* %2, align 4
|
||||
%3 = getelementptr inbounds i8, i8* %1, i32 4
|
||||
%4 = bitcast i8* %3 to i8**
|
||||
store i8* %n, i8** %4, align 4
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 8192, i8* undef, i8* null) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"main.closureFunctionGoroutine$1$gowrapper" to i32), i8* nonnull %1, i32 16384, i8* undef) #0
|
||||
%5 = load i32, i32* %0, align 4
|
||||
call void @runtime.printint32(i32 %5, i8* undef, i8* null) #0
|
||||
call void @runtime.printint32(i32 %5, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%unpack.ptr = bitcast i8* %context to i32*
|
||||
store i32 7, i32* %unpack.ptr, align 4
|
||||
@@ -98,17 +105,18 @@ entry:
|
||||
%3 = getelementptr inbounds i8, i8* %0, i32 4
|
||||
%4 = bitcast i8* %3 to i8**
|
||||
%5 = load i8*, i8** %4, align 4
|
||||
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5, i8* undef)
|
||||
call void @runtime.deadlock(i8* undef, i8* undef) #0
|
||||
call void @"main.closureFunctionGoroutine$1"(i32 %2, i8* %5)
|
||||
call void @runtime.deadlock(i8* undef) #0
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare void @runtime.printint32(i32, i8*, i8*)
|
||||
declare void @runtime.printint32(i32, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.funcGoroutine(i8* %fn.context, void ()* %fn.funcptr, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef, i8* null) #0
|
||||
%0 = call i8* @runtime.alloc(i32 12, i8* null, i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||
%1 = bitcast i8* %0 to i32*
|
||||
store i32 5, i32* %1, align 4
|
||||
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
||||
@@ -117,7 +125,7 @@ entry:
|
||||
%4 = getelementptr inbounds i8, i8* %0, i32 8
|
||||
%5 = bitcast i8* %4 to void ()**
|
||||
store void ()* %fn.funcptr, void ()** %5, align 4
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 8192, i8* undef, i8* null) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @main.funcGoroutine.gowrapper to i32), i8* nonnull %0, i32 16384, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -130,41 +138,42 @@ entry:
|
||||
%4 = bitcast i8* %3 to i8**
|
||||
%5 = load i8*, i8** %4, align 4
|
||||
%6 = getelementptr inbounds i8, i8* %0, i32 8
|
||||
%7 = bitcast i8* %6 to void (i32, i8*, i8*)**
|
||||
%8 = load void (i32, i8*, i8*)*, void (i32, i8*, i8*)** %7, align 4
|
||||
call void %8(i32 %2, i8* %5, i8* undef) #0
|
||||
call void @runtime.deadlock(i8* undef, i8* undef) #0
|
||||
%7 = bitcast i8* %6 to void (i32, i8*)**
|
||||
%8 = load void (i32, i8*)*, void (i32, i8*)** %7, align 4
|
||||
call void %8(i32 %2, i8* %5) #0
|
||||
call void @runtime.deadlock(i8* undef) #0
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.recoverBuiltinGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.recoverBuiltinGoroutine(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef, i8* null) #0
|
||||
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
|
||||
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef, i8* null) #0
|
||||
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*, i8*)
|
||||
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef, i8* null) #0
|
||||
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||
%1 = bitcast i8* %0 to i8**
|
||||
store i8* %itf.value, i8** %1, align 4
|
||||
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
||||
@@ -176,11 +185,11 @@ entry:
|
||||
%4 = getelementptr inbounds i8, i8* %0, i32 12
|
||||
%5 = bitcast i8* %4 to i32*
|
||||
store i32 %itf.typecode, i32* %5, align 4
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 8192, i8* undef, i8* null) #0
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), i8* nonnull %0, i32 16384, i8* undef) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*, i8*) #5
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*) #5
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define linkonce_odr void @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper"(i8* %0) unnamed_addr #6 {
|
||||
@@ -196,8 +205,8 @@ entry:
|
||||
%9 = getelementptr inbounds i8, i8* %0, i32 12
|
||||
%10 = bitcast i8* %9 to i32*
|
||||
%11 = load i32, i32* %10, align 4
|
||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef, i8* undef) #0
|
||||
call void @runtime.deadlock(i8* undef, i8* undef) #0
|
||||
call void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8* %2, i8* %5, i32 %8, i32 %11, i8* undef) #0
|
||||
call void @runtime.deadlock(i8* undef) #0
|
||||
unreachable
|
||||
}
|
||||
|
||||
|
||||
-141
@@ -1,141 +0,0 @@
|
||||
; ModuleID = 'goroutine.go'
|
||||
source_filename = "goroutine.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime.funcValueWithSignature = type { i32, i8* }
|
||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
|
||||
%"internal/task.state" = type { i8* }
|
||||
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
||||
|
||||
@"main$pack" = internal unnamed_addr constant { i32, i8* } { i32 5, i8* undef }
|
||||
@"main$pack.1" = internal unnamed_addr constant { i32, i8* } { i32 5, i8* undef }
|
||||
@"reflect/types.funcid:func:{basic:int}{}" = external constant i8
|
||||
@"main.closureFunctionGoroutine$1$withSignature" = linkonce_odr constant %runtime.funcValueWithSignature { i32 ptrtoint (void (i32, i8*, i8*)* @"main.closureFunctionGoroutine$1" to i32), i8* @"reflect/types.funcid:func:{basic:int}{}" }
|
||||
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.regularFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @main.regularFunction to i32), i8* bitcast ({ i32, i8* }* @"main$pack" to i8*), i32 undef, i8* undef, i8* null) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.regularFunction(i32, i8*, i8*)
|
||||
|
||||
declare void @"internal/task.start"(i32, i8*, i32, i8*, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.inlineFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @"main.inlineFunctionGoroutine$1" to i32), i8* bitcast ({ i32, i8* }* @"main$pack.1" to i8*), i32 undef, i8* undef, i8* null) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closureFunctionGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
%n = call i8* @runtime.alloc(i32 4, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%0 = bitcast i8* %n to i32*
|
||||
store i32 3, i32* %0, align 4
|
||||
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef, i8* null) #0
|
||||
%2 = bitcast i8* %1 to i32*
|
||||
store i32 5, i32* %2, align 4
|
||||
%3 = getelementptr inbounds i8, i8* %1, i32 4
|
||||
%4 = bitcast i8* %3 to i8**
|
||||
store i8* %n, i8** %4, align 4
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @"main.closureFunctionGoroutine$1" to i32), i8* nonnull %1, i32 undef, i8* undef, i8* null) #0
|
||||
%5 = load i32, i32* %0, align 4
|
||||
call void @runtime.printint32(i32 %5, i8* undef, i8* null) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
%unpack.ptr = bitcast i8* %context to i32*
|
||||
store i32 7, i32* %unpack.ptr, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.printint32(i32, i8*, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.funcGoroutine(i8* %fn.context, i32 %fn.funcptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i32 @runtime.getFuncPtr(i8* %fn.context, i32 %fn.funcptr, i8* nonnull @"reflect/types.funcid:func:{basic:int}{}", i8* undef, i8* null) #0
|
||||
%1 = call i8* @runtime.alloc(i32 8, i8* null, i8* undef, i8* null) #0
|
||||
%2 = bitcast i8* %1 to i32*
|
||||
store i32 5, i32* %2, align 4
|
||||
%3 = getelementptr inbounds i8, i8* %1, i32 4
|
||||
%4 = bitcast i8* %3 to i8**
|
||||
store i8* %fn.context, i8** %4, align 4
|
||||
call void @"internal/task.start"(i32 %0, i8* nonnull %1, i32 undef, i8* undef, i8* null) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @runtime.getFuncPtr(i8*, i32, i8* dereferenceable_or_null(1), i8*, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.recoverBuiltinGoroutine(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.copyBuiltinGoroutine(i8* %dst.data, i32 %dst.len, i32 %dst.cap, i8* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
%copy.n = call i32 @runtime.sliceCopy(i8* %dst.data, i8* %src.data, i32 %dst.len, i32 %src.len, i32 1, i8* undef, i8* null) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closeBuiltinGoroutine(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef, i8* null) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.startInterfaceMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i8* @runtime.alloc(i32 16, i8* null, i8* undef, i8* null) #0
|
||||
%1 = bitcast i8* %0 to i8**
|
||||
store i8* %itf.value, i8** %1, align 4
|
||||
%2 = getelementptr inbounds i8, i8* %0, i32 4
|
||||
%.repack = bitcast i8* %2 to i8**
|
||||
store i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"main$string", i32 0, i32 0), i8** %.repack, align 4
|
||||
%.repack1 = getelementptr inbounds i8, i8* %0, i32 8
|
||||
%3 = bitcast i8* %.repack1 to i32*
|
||||
store i32 4, i32* %3, align 4
|
||||
%4 = getelementptr inbounds i8, i8* %0, i32 12
|
||||
%5 = bitcast i8* %4 to i32*
|
||||
store i32 %itf.typecode, i32* %5, align 4
|
||||
call void @"internal/task.start"(i32 ptrtoint (void (i8*, i8*, i32, i32, i8*, i8*)* @"interface:{Print:func:{basic:string}{}}.Print$invoke" to i32), i8* nonnull %0, i32 undef, i8* undef, i8* null) #0
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @"interface:{Print:func:{basic:string}{}}.Print$invoke"(i8*, i8*, i32, i32, i8*, i8*) #1
|
||||
|
||||
attributes #0 = { nounwind }
|
||||
attributes #1 = { "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" }
|
||||
Vendored
+26
-18
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'interface.go'
|
||||
source_filename = "interface.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID*, i32 }
|
||||
@@ -22,46 +22,52 @@ target triple = "wasm32-unknown-wasi"
|
||||
@"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"reflect/methods.String() string"]
|
||||
@"reflect/types.typeid:basic:int" = external constant i8
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.simpleType(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden %runtime._interface @main.simpleType(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.trackPointer(i8* null, i8* undef) #0
|
||||
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:basic:int" to i32), i8* null }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.pointerType(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden %runtime._interface @main.pointerType(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.trackPointer(i8* null, i8* undef) #0
|
||||
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:basic:int" to i32), i8* null }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.interfaceType(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden %runtime._interface @main.interfaceType(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.trackPointer(i8* null, i8* undef) #0
|
||||
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:named:error" to i32), i8* null }
|
||||
}
|
||||
|
||||
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i32) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._interface @main.anonymousInterfaceType(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden %runtime._interface @main.anonymousInterfaceType(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.trackPointer(i8* null, i8* undef) #0
|
||||
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" to i32), i8* null }
|
||||
}
|
||||
|
||||
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isInt(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.isInt(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef, i8* null) #0
|
||||
%typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef) #0
|
||||
br i1 %typecode, label %typeassert.ok, label %typeassert.next
|
||||
|
||||
typeassert.ok: ; preds = %entry
|
||||
@@ -71,10 +77,10 @@ typeassert.next: ; preds = %typeassert.ok, %ent
|
||||
ret i1 %typecode
|
||||
}
|
||||
|
||||
declare i1 @runtime.typeAssert(i32, i8* dereferenceable_or_null(1), i8*, i8*)
|
||||
declare i1 @runtime.typeAssert(i32, i8* dereferenceable_or_null(1), i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isError(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.isError(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0
|
||||
br i1 %0, label %typeassert.ok, label %typeassert.next
|
||||
@@ -87,7 +93,7 @@ typeassert.next: ; preds = %typeassert.ok, %ent
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isStringer(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.isStringer(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0
|
||||
br i1 %0, label %typeassert.ok, label %typeassert.next
|
||||
@@ -100,22 +106,24 @@ typeassert.next: ; preds = %typeassert.ok, %ent
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.callFooMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i8 @main.callFooMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8* %itf.value, i32 3, i32 %itf.typecode, i8* undef, i8* undef) #0
|
||||
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8* %itf.value, i32 3, i32 %itf.typecode, i8* undef) #0
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8*, i32, i32, i8*, i8*) #3
|
||||
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(i8*, i32, i32, i8*) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.callErrorMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden %runtime._string @main.callErrorMethod(i32 %itf.typecode, i8* %itf.value, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8* %itf.value, i32 %itf.typecode, i8* undef, i8* undef) #0
|
||||
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8* %itf.value, i32 %itf.typecode, i8* undef) #0
|
||||
%1 = extractvalue %runtime._string %0, 0
|
||||
call void @runtime.trackPointer(i8* %1, i8* undef) #0
|
||||
ret %runtime._string %0
|
||||
}
|
||||
|
||||
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8*, i32, i8*, i8*) #4
|
||||
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(i8*, i32, i8*) #4
|
||||
|
||||
attributes #0 = { nounwind }
|
||||
attributes #1 = { "tinygo-methods"="reflect/methods.Error() string" }
|
||||
|
||||
+8
-8
@@ -3,30 +3,30 @@ source_filename = "intrinsics.go"
|
||||
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "thumbv7m-unknown-unknown-eabi"
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden double @main.mySqrt(double %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden double @main.mySqrt(double %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call double @math.Sqrt(double %x, i8* undef, i8* undef) #0
|
||||
%0 = call double @math.Sqrt(double %x, i8* undef) #0
|
||||
ret double %0
|
||||
}
|
||||
|
||||
declare double @math.Sqrt(double, i8*, i8*)
|
||||
declare double @math.Sqrt(double, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden double @main.myTrunc(double %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden double @main.myTrunc(double %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call double @math.Trunc(double %x, i8* undef, i8* undef) #0
|
||||
%0 = call double @math.Trunc(double %x, i8* undef) #0
|
||||
ret double %0
|
||||
}
|
||||
|
||||
declare double @math.Trunc(double, i8*, i8*)
|
||||
declare double @math.Trunc(double, i8*)
|
||||
|
||||
attributes #0 = { nounwind }
|
||||
|
||||
Vendored
+7
-5
@@ -1,18 +1,20 @@
|
||||
; ModuleID = 'intrinsics.go'
|
||||
source_filename = "intrinsics.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden double @main.mySqrt(double %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden double @main.mySqrt(double %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call double @llvm.sqrt.f64(double %x)
|
||||
ret double %0
|
||||
@@ -22,7 +24,7 @@ entry:
|
||||
declare double @llvm.sqrt.f64(double) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden double @main.myTrunc(double %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden double @main.myTrunc(double %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call double @llvm.trunc.f64(double %x)
|
||||
ret double %0
|
||||
|
||||
Vendored
+29
-12
@@ -1,61 +1,78 @@
|
||||
; ModuleID = 'pointer.go'
|
||||
source_filename = "pointer.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden [0 x i32] @main.pointerDerefZero([0 x i32]* %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden [0 x i32] @main.pointerDerefZero([0 x i32]* %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret [0 x i32] zeroinitializer
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32* @main.pointerCastFromUnsafe(i8* %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32* @main.pointerCastFromUnsafe(i8* %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = bitcast i8* %x to i32*
|
||||
call void @runtime.trackPointer(i8* %x, i8* undef) #0
|
||||
ret i32* %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8* @main.pointerCastToUnsafe(i32* dereferenceable_or_null(4) %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i8* @main.pointerCastToUnsafe(i32* dereferenceable_or_null(4) %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = bitcast i32* %x to i8*
|
||||
call void @runtime.trackPointer(i8* %0, i8* undef) #0
|
||||
ret i8* %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8* @main.pointerCastToUnsafeNoop(i8* dereferenceable_or_null(1) %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i8* @main.pointerCastToUnsafeNoop(i8* dereferenceable_or_null(1) %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.trackPointer(i8* %x, i8* undef) #0
|
||||
ret i8* %x
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8* @main.pointerUnsafeGEPFixedOffset(i8* dereferenceable_or_null(1) %ptr, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i8* @main.pointerUnsafeGEPFixedOffset(i8* dereferenceable_or_null(1) %ptr, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.trackPointer(i8* %ptr, i8* undef) #0
|
||||
%0 = getelementptr inbounds i8, i8* %ptr, i32 10
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %0, i8* undef) #0
|
||||
ret i8* %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8* @main.pointerUnsafeGEPByteOffset(i8* dereferenceable_or_null(1) %ptr, i32 %offset, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i8* @main.pointerUnsafeGEPByteOffset(i8* dereferenceable_or_null(1) %ptr, i32 %offset, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
call void @runtime.trackPointer(i8* %ptr, i8* undef) #0
|
||||
%0 = getelementptr inbounds i8, i8* %ptr, i32 %offset
|
||||
call void @runtime.trackPointer(i8* %0, i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* %0, i8* undef) #0
|
||||
ret i8* %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32* @main.pointerUnsafeGEPIntOffset(i32* dereferenceable_or_null(4) %ptr, i32 %offset, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32* @main.pointerUnsafeGEPIntOffset(i32* dereferenceable_or_null(4) %ptr, i32 %offset, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = getelementptr i32, i32* %ptr, i32 %offset
|
||||
ret i32* %0
|
||||
%0 = bitcast i32* %ptr to i8*
|
||||
call void @runtime.trackPointer(i8* %0, i8* undef) #0
|
||||
%1 = getelementptr i32, i32* %ptr, i32 %offset
|
||||
%2 = bitcast i32* %1 to i8*
|
||||
call void @runtime.trackPointer(i8* %2, i8* undef) #0
|
||||
%3 = bitcast i32* %1 to i8*
|
||||
call void @runtime.trackPointer(i8* %3, i8* undef) #0
|
||||
ret i32* %1
|
||||
}
|
||||
|
||||
attributes #0 = { nounwind }
|
||||
|
||||
Vendored
+11
-9
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'pragma.go'
|
||||
source_filename = "pragma.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
@extern_global = external global [0 x i8], align 1
|
||||
@@ -10,10 +10,12 @@ target triple = "wasm32-unknown-wasi"
|
||||
@undefinedGlobalNotInSection = external global i32, align 4
|
||||
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
@@ -25,27 +27,27 @@ entry:
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @somepkg.someFunction1(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @somepkg.someFunction1(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @somepkg.someFunction2(i8*, i8*)
|
||||
declare void @somepkg.someFunction2(i8*)
|
||||
|
||||
; Function Attrs: inlinehint nounwind
|
||||
define hidden void @main.inlineFunc(i8* %context, i8* %parentHandle) unnamed_addr #2 {
|
||||
define hidden void @main.inlineFunc(i8* %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: noinline nounwind
|
||||
define hidden void @main.noinlineFunc(i8* %context, i8* %parentHandle) unnamed_addr #3 {
|
||||
define hidden void @main.noinlineFunc(i8* %context) unnamed_addr #3 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.functionInSection(i8* %context, i8* %parentHandle) unnamed_addr #0 section ".special_function_section" {
|
||||
define hidden void @main.functionInSection(i8* %context) unnamed_addr #0 section ".special_function_section" {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
@@ -56,7 +58,7 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.undefinedFunctionNotInSection(i8*, i8*)
|
||||
declare void @main.undefinedFunctionNotInSection(i8*)
|
||||
|
||||
attributes #0 = { nounwind }
|
||||
attributes #1 = { nounwind "wasm-export-name"="extern_func" }
|
||||
|
||||
Vendored
+39
-30
@@ -1,36 +1,38 @@
|
||||
; ModuleID = 'slice.go'
|
||||
source_filename = "slice.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceLen(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.sliceLen(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret i32 %ints.len
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceCap(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.sliceCap(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret i32 %ints.cap
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceElement(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.sliceElement(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%.not = icmp ult i32 %index, %ints.len
|
||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||
|
||||
lookup.throw: ; preds = %entry
|
||||
call void @runtime.lookupPanic(i8* undef, i8* null) #0
|
||||
call void @runtime.lookupPanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
lookup.next: ; preds = %entry
|
||||
@@ -39,12 +41,13 @@ lookup.next: ; preds = %entry
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
declare void @runtime.lookupPanic(i8*, i8*)
|
||||
declare void @runtime.lookupPanic(i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i32*, i32, i32 } @main.sliceAppendValues(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { i32*, i32, i32 } @main.sliceAppendValues(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%varargs = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%varargs = call i8* @runtime.alloc(i32 12, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
call void @runtime.trackPointer(i8* nonnull %varargs, i8* undef) #0
|
||||
%0 = bitcast i8* %varargs to i32*
|
||||
store i32 1, i32* %0, align 4
|
||||
%1 = getelementptr inbounds i8, i8* %varargs, i32 4
|
||||
@@ -54,7 +57,7 @@ entry:
|
||||
%4 = bitcast i8* %3 to i32*
|
||||
store i32 3, i32* %4, align 4
|
||||
%append.srcPtr = bitcast i32* %ints.data to i8*
|
||||
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, i8* undef, i8* null) #0
|
||||
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, i8* undef) #0
|
||||
%append.newPtr = extractvalue { i8*, i32, i32 } %append.new, 0
|
||||
%append.newBuf = bitcast i8* %append.newPtr to i32*
|
||||
%append.newLen = extractvalue { i8*, i32, i32 } %append.new, 1
|
||||
@@ -62,17 +65,18 @@ entry:
|
||||
%5 = insertvalue { i32*, i32, i32 } undef, i32* %append.newBuf, 0
|
||||
%6 = insertvalue { i32*, i32, i32 } %5, i32 %append.newLen, 1
|
||||
%7 = insertvalue { i32*, i32, i32 } %6, i32 %append.newCap, 2
|
||||
call void @runtime.trackPointer(i8* %append.newPtr, i8* undef) #0
|
||||
ret { i32*, i32, i32 } %7
|
||||
}
|
||||
|
||||
declare { i8*, i32, i32 } @runtime.sliceAppend(i8*, i8* nocapture readonly, i32, i32, i32, i32, i8*, i8*)
|
||||
declare { i8*, i32, i32 } @runtime.sliceAppend(i8*, i8* nocapture readonly, i32, i32, i32, i32, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i32*, i32, i32 } @main.sliceAppendSlice(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32* %added.data, i32 %added.len, i32 %added.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { i32*, i32, i32 } @main.sliceAppendSlice(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32* %added.data, i32 %added.len, i32 %added.cap, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%append.srcPtr = bitcast i32* %ints.data to i8*
|
||||
%append.srcPtr1 = bitcast i32* %added.data to i8*
|
||||
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* %append.srcPtr1, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, i8* undef, i8* null) #0
|
||||
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* %append.srcPtr1, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, i8* undef) #0
|
||||
%append.newPtr = extractvalue { i8*, i32, i32 } %append.new, 0
|
||||
%append.newBuf = bitcast i8* %append.newPtr to i32*
|
||||
%append.newLen = extractvalue { i8*, i32, i32 } %append.new, 1
|
||||
@@ -80,97 +84,102 @@ entry:
|
||||
%0 = insertvalue { i32*, i32, i32 } undef, i32* %append.newBuf, 0
|
||||
%1 = insertvalue { i32*, i32, i32 } %0, i32 %append.newLen, 1
|
||||
%2 = insertvalue { i32*, i32, i32 } %1, i32 %append.newCap, 2
|
||||
call void @runtime.trackPointer(i8* %append.newPtr, i8* undef) #0
|
||||
ret { i32*, i32, i32 } %2
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.sliceCopy(i32* %dst.data, i32 %dst.len, i32 %dst.cap, i32* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.sliceCopy(i32* %dst.data, i32 %dst.len, i32 %dst.cap, i32* %src.data, i32 %src.len, i32 %src.cap, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%copy.dstPtr = bitcast i32* %dst.data to i8*
|
||||
%copy.srcPtr = bitcast i32* %src.data to i8*
|
||||
%copy.n = call i32 @runtime.sliceCopy(i8* %copy.dstPtr, i8* %copy.srcPtr, i32 %dst.len, i32 %src.len, i32 4, i8* undef, i8* null) #0
|
||||
%copy.n = call i32 @runtime.sliceCopy(i8* %copy.dstPtr, i8* %copy.srcPtr, i32 %dst.len, i32 %src.len, i32 4, i8* undef) #0
|
||||
ret i32 %copy.n
|
||||
}
|
||||
|
||||
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
|
||||
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i8*, i32, i32 } @main.makeByteSlice(i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { i8*, i32, i32 } @main.makeByteSlice(i32 %len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%slice.maxcap = icmp slt i32 %len, 0
|
||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
call void @runtime.slicePanic(i8* undef, i8* null) #0
|
||||
call void @runtime.slicePanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.buf = call i8* @runtime.alloc(i32 %len, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%makeslice.buf = call i8* @runtime.alloc(i32 %len, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
%0 = insertvalue { i8*, i32, i32 } undef, i8* %makeslice.buf, 0
|
||||
%1 = insertvalue { i8*, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { i8*, i32, i32 } %1, i32 %len, 2
|
||||
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
|
||||
ret { i8*, i32, i32 } %2
|
||||
}
|
||||
|
||||
declare void @runtime.slicePanic(i8*, i8*)
|
||||
declare void @runtime.slicePanic(i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i16*, i32, i32 } @main.makeInt16Slice(i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { i16*, i32, i32 } @main.makeInt16Slice(i32 %len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%slice.maxcap = icmp slt i32 %len, 0
|
||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
call void @runtime.slicePanic(i8* undef, i8* null) #0
|
||||
call void @runtime.slicePanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.cap = shl i32 %len, 1
|
||||
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
%makeslice.array = bitcast i8* %makeslice.buf to i16*
|
||||
%0 = insertvalue { i16*, i32, i32 } undef, i16* %makeslice.array, 0
|
||||
%1 = insertvalue { i16*, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { i16*, i32, i32 } %1, i32 %len, 2
|
||||
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
|
||||
ret { i16*, i32, i32 } %2
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { [3 x i8]*, i32, i32 } @main.makeArraySlice(i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { [3 x i8]*, i32, i32 } @main.makeArraySlice(i32 %len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%slice.maxcap = icmp ugt i32 %len, 1431655765
|
||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
call void @runtime.slicePanic(i8* undef, i8* null) #0
|
||||
call void @runtime.slicePanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.cap = mul i32 %len, 3
|
||||
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
%makeslice.array = bitcast i8* %makeslice.buf to [3 x i8]*
|
||||
%0 = insertvalue { [3 x i8]*, i32, i32 } undef, [3 x i8]* %makeslice.array, 0
|
||||
%1 = insertvalue { [3 x i8]*, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { [3 x i8]*, i32, i32 } %1, i32 %len, 2
|
||||
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
|
||||
ret { [3 x i8]*, i32, i32 } %2
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { i32*, i32, i32 } @main.makeInt32Slice(i32 %len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden { i32*, i32, i32 } @main.makeInt32Slice(i32 %len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%slice.maxcap = icmp ugt i32 %len, 1073741823
|
||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||
|
||||
slice.throw: ; preds = %entry
|
||||
call void @runtime.slicePanic(i8* undef, i8* null) #0
|
||||
call void @runtime.slicePanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.cap = shl i32 %len, 2
|
||||
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0
|
||||
%makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0
|
||||
%makeslice.array = bitcast i8* %makeslice.buf to i32*
|
||||
%0 = insertvalue { i32*, i32, i32 } undef, i32* %makeslice.array, 0
|
||||
%1 = insertvalue { i32*, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { i32*, i32, i32 } %1, i32 %len, 2
|
||||
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
|
||||
ret { i32*, i32, i32 } %2
|
||||
}
|
||||
|
||||
|
||||
Vendored
+21
-19
@@ -1,46 +1,48 @@
|
||||
; ModuleID = 'string.go'
|
||||
source_filename = "string.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime._string = type { i8*, i32 }
|
||||
|
||||
@"main$string" = internal unnamed_addr constant [3 x i8] c"foo", align 1
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*)
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
declare void @runtime.trackPointer(i8* nocapture readonly, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden void @main.init(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.someString(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden %runtime._string @main.someString(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret %runtime._string { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"main$string", i32 0, i32 0), i32 3 }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.zeroLengthString(i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden %runtime._string @main.zeroLengthString(i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret %runtime._string zeroinitializer
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.stringLen(i8* %s.data, i32 %s.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i32 @main.stringLen(i8* %s.data, i32 %s.len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
ret i32 %s.len
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.stringIndex(i8* %s.data, i32 %s.len, i32 %index, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i8 @main.stringIndex(i8* %s.data, i32 %s.len, i32 %index, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%.not = icmp ult i32 %index, %s.len
|
||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||
|
||||
lookup.throw: ; preds = %entry
|
||||
call void @runtime.lookupPanic(i8* undef, i8* null) #0
|
||||
call void @runtime.lookupPanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
lookup.next: ; preds = %entry
|
||||
@@ -49,43 +51,43 @@ lookup.next: ; preds = %entry
|
||||
ret i8 %1
|
||||
}
|
||||
|
||||
declare void @runtime.lookupPanic(i8*, i8*)
|
||||
declare void @runtime.lookupPanic(i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.stringCompareEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.stringCompareEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef, i8* null) #0
|
||||
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef) #0
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringEqual(i8*, i32, i8*, i32, i8*, i8*)
|
||||
declare i1 @runtime.stringEqual(i8*, i32, i8*, i32, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.stringCompareUnequal(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.stringCompareUnequal(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef, i8* null) #0
|
||||
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef) #0
|
||||
%1 = xor i1 %0, true
|
||||
ret i1 %1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.stringCompareLarger(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i1 @main.stringCompareLarger(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = call i1 @runtime.stringLess(i8* %s2.data, i32 %s2.len, i8* %s1.data, i32 %s1.len, i8* undef, i8* null) #0
|
||||
%0 = call i1 @runtime.stringLess(i8* %s2.data, i32 %s2.len, i8* %s1.data, i32 %s1.len, i8* undef) #0
|
||||
ret i1 %0
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringLess(i8*, i32, i8*, i32, i8*, i8*)
|
||||
declare i1 @runtime.stringLess(i8*, i32, i8*, i32, i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.stringLookup(i8* %s.data, i32 %s.len, i8 %x, i8* %context, i8* %parentHandle) unnamed_addr #0 {
|
||||
define hidden i8 @main.stringLookup(i8* %s.data, i32 %s.len, i8 %x, i8* %context) unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = zext i8 %x to i32
|
||||
%.not = icmp ult i32 %0, %s.len
|
||||
br i1 %.not, label %lookup.next, label %lookup.throw
|
||||
|
||||
lookup.throw: ; preds = %entry
|
||||
call void @runtime.lookupPanic(i8* undef, i8* null) #0
|
||||
call void @runtime.lookupPanic(i8* undef) #0
|
||||
unreachable
|
||||
|
||||
lookup.next: ; preds = %entry
|
||||
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
/*
|
||||
This contains code from https://github.com/dgryski/tinygo-test-corpus
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020 Damian Gryski <damian@gryski.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
var corpus = flag.String("corpus", "", "path to test corpus")
|
||||
|
||||
func TestCorpus(t *testing.T) {
|
||||
t.Parallel()
|
||||
if *corpus == "" {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
var target string
|
||||
if *testTarget != "" {
|
||||
target = *testTarget
|
||||
}
|
||||
|
||||
repos, err := loadRepos(*corpus)
|
||||
if err != nil {
|
||||
t.Fatalf("loading corpus: %v", err)
|
||||
}
|
||||
|
||||
for _, repo := range repos {
|
||||
repo := repo
|
||||
name := repo.Repo
|
||||
if repo.Tags != "" {
|
||||
name += "(" + strings.ReplaceAll(repo.Tags, " ", "-") + ")"
|
||||
}
|
||||
if repo.Version != "" {
|
||||
name += "@" + repo.Version
|
||||
}
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if target == "wasi" && repo.SkipWASI {
|
||||
t.Skip("skip wasi")
|
||||
}
|
||||
if repo.Slow && testing.Short() {
|
||||
t.Skip("slow test")
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
defer wg.Wait()
|
||||
out := ioLogger(t, &wg)
|
||||
defer out.Close()
|
||||
|
||||
dir := t.TempDir()
|
||||
cmd := exec.Command("go", "mod", "init", "github.com/tinygo/tinygo-corpus-test")
|
||||
cmd.Dir = dir
|
||||
cmd.Stdout, cmd.Stderr = out, out
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
t.Errorf("failed to init: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var ver string
|
||||
if repo.Version != "" {
|
||||
ver = "@" + repo.Version
|
||||
}
|
||||
cmd = exec.Command("go", "get", "-t", "-d", repo.Repo+"/..."+ver)
|
||||
cmd.Dir = dir
|
||||
cmd.Stdout, cmd.Stderr = out, out
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
t.Errorf("failed to get: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
doTest := func(t *testing.T, path string) {
|
||||
var wg sync.WaitGroup
|
||||
defer wg.Wait()
|
||||
out := ioLogger(t, &wg)
|
||||
defer out.Close()
|
||||
|
||||
opts := optionsFromTarget(target, sema)
|
||||
opts.Directory = dir
|
||||
opts.Tags = repo.Tags
|
||||
|
||||
passed, err := Test(path, out, out, &opts, false, testing.Verbose(), false, "", "", "", "")
|
||||
if err != nil {
|
||||
t.Errorf("test error: %v", err)
|
||||
}
|
||||
if !passed {
|
||||
t.Error("test failed")
|
||||
}
|
||||
}
|
||||
if len(repo.Subdirs) == 0 {
|
||||
doTest(t, repo.Repo)
|
||||
return
|
||||
}
|
||||
|
||||
for _, dir := range repo.Subdirs {
|
||||
dir := dir
|
||||
t.Run(dir.Pkg, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if target == "wasi" && dir.SkipWASI {
|
||||
t.Skip("skip wasi")
|
||||
}
|
||||
if dir.Slow && testing.Short() {
|
||||
t.Skip("slow test")
|
||||
}
|
||||
|
||||
doTest(t, repo.Repo+"/"+dir.Pkg)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type T struct {
|
||||
Repo string
|
||||
Tags string
|
||||
Subdirs []Subdir
|
||||
SkipWASI bool
|
||||
Slow bool
|
||||
Version string
|
||||
}
|
||||
|
||||
type Subdir struct {
|
||||
Pkg string
|
||||
SkipWASI bool
|
||||
Slow bool
|
||||
}
|
||||
|
||||
func loadRepos(f string) ([]T, error) {
|
||||
|
||||
yf, err := os.ReadFile(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var repos []T
|
||||
err = yaml.Unmarshal(yf, &repos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return repos, nil
|
||||
}
|
||||
@@ -3,15 +3,17 @@ module github.com/tinygo-org/tinygo
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a // indirect
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a
|
||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
||||
github.com/chromedp/cdproto v0.0.0-20210113043257-dabd2f2e7693
|
||||
github.com/chromedp/chromedp v0.6.4
|
||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
|
||||
github.com/chromedp/chromedp v0.7.6
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
|
||||
github.com/mattn/go-colorable v0.1.8
|
||||
go.bug.st/serial v1.1.3
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
|
||||
golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9
|
||||
tinygo.org/x/go-llvm v0.0.0-20210907125547-fd2d62ea06be
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
tinygo.org/x/go-llvm v0.0.0-20220121152956-4fa2ab2718f3
|
||||
)
|
||||
|
||||
@@ -2,44 +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-20210113043257-dabd2f2e7693 h1:11eq/RkpaotwdF6b1TRMcdgQUPNmyFEJOB7zLvh0O/Y=
|
||||
github.com/chromedp/cdproto v0.0.0-20210113043257-dabd2f2e7693/go.mod h1:55pim6Ht4LJKdVLlyFJV/g++HsEA1hQxPbB5JyNdZC0=
|
||||
github.com/chromedp/chromedp v0.6.4 h1:Gx7ZkRyrSVmbbDDja/ieNgNGJIvElroPOyeqYQGVDSY=
|
||||
github.com/chromedp/chromedp v0.6.4/go.mod h1:vodUdJf5dF/b8n0UBJv6NeM/QK28RjP3j+eM7fq4+84=
|
||||
github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee h1:+SFdIVfQpG0s0DHYzou0kgfE0n0ZjKPwbiRJsXrZegU=
|
||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
||||
github.com/chromedp/chromedp v0.7.6 h1:2juGaktzjwULlsn+DnvIZXFUckEp5xs+GOBroaea+jA=
|
||||
github.com/chromedp/chromedp v0.7.6/go.mod h1:ayT4YU/MGAALNfOg9gNrpGSAdnU51PMx+FCeuT1iXzo=
|
||||
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
|
||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs=
|
||||
github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
|
||||
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
|
||||
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.bug.st/serial v1.1.3 h1:YEBxJa9pKS9Wdg46B/jiaKbvvbUrjhZZZITfJHEJhaE=
|
||||
go.bug.st/serial v1.1.3/go.mod h1:8TT7u/SwwNIpJ8QaG4s+HTjFt9ReXs2cdOU7ZEk50Dk=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -52,10 +58,12 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -65,8 +73,12 @@ golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9 h1:nvvuMxmx1q0gfRki3T0hj
|
||||
golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
tinygo.org/x/go-llvm v0.0.0-20210907125547-fd2d62ea06be h1:syIpWbi/yESuoyijF2nhRdgX4422sNfmij+o73B3+vU=
|
||||
tinygo.org/x/go-llvm v0.0.0-20210907125547-fd2d62ea06be/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
tinygo.org/x/go-llvm v0.0.0-20220121152956-4fa2ab2718f3 h1:vQSFy0kNQegAfL/F6iyWQa4bF941Xc1gyJUkGy2m448=
|
||||
tinygo.org/x/go-llvm v0.0.0-20220121152956-4fa2ab2718f3/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
// Version of TinyGo.
|
||||
// Update this value before release of new version of software.
|
||||
const Version = "0.22.0-dev"
|
||||
const Version = "0.23.0-dev"
|
||||
|
||||
// GetGorootVersion returns the major and minor version for a given GOROOT path.
|
||||
// If the goroot cannot be determined, (0, 0) is returned.
|
||||
|
||||
+3
-7
@@ -11,12 +11,6 @@ import (
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// Version of the interp package. It must be incremented whenever the interp
|
||||
// package is changed in a way that affects the output so that cached package
|
||||
// builds will be invalidated.
|
||||
// This version is independent of the TinyGo version number.
|
||||
const Version = 2 // last change: fix GEP on untyped pointers
|
||||
|
||||
// Enable extra checks, which should be disabled by default.
|
||||
// This may help track down bugs by adding a few more sanity checks.
|
||||
const checks = true
|
||||
@@ -28,6 +22,7 @@ type runner struct {
|
||||
builder llvm.Builder
|
||||
pointerSize uint32 // cached pointer size from the TargetData
|
||||
i8ptrType llvm.Type // often used type so created in advance
|
||||
uintptrType llvm.Type // equivalent to uintptr in Go
|
||||
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
|
||||
debug bool // log debug messages
|
||||
pkgName string // package name of the currently executing package
|
||||
@@ -50,6 +45,7 @@ func newRunner(mod llvm.Module, debug bool) *runner {
|
||||
}
|
||||
r.pointerSize = uint32(r.targetData.PointerSize())
|
||||
r.i8ptrType = llvm.PointerType(mod.Context().Int8Type(), 0)
|
||||
r.uintptrType = mod.Context().IntType(r.targetData.PointerSize() * 8)
|
||||
r.maxAlign = r.targetData.PrefTypeAlignment(r.i8ptrType) // assume pointers are maximally aligned (this is not always the case)
|
||||
return &r
|
||||
}
|
||||
@@ -122,7 +118,7 @@ func Run(mod llvm.Module, debug bool) error {
|
||||
// Create a call to the package initializer (which was
|
||||
// previously deleted).
|
||||
i8undef := llvm.Undef(r.i8ptrType)
|
||||
r.builder.CreateCall(fn, []llvm.Value{i8undef, i8undef}, "")
|
||||
r.builder.CreateCall(fn, []llvm.Value{i8undef}, "")
|
||||
// Make sure that any globals touched by the package
|
||||
// initializer, won't be accessed by later package initializers.
|
||||
r.markExternalLoad(fn)
|
||||
|
||||
+26
-9
@@ -17,10 +17,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
locals := make([]value, len(fn.locals))
|
||||
r.callsExecuted++
|
||||
|
||||
if time.Since(r.start) > time.Minute {
|
||||
// Running for more than a minute. This should never happen.
|
||||
return nil, mem, r.errorAt(fn.blocks[0].instructions[0], fmt.Errorf("interp: running for more than a minute, timing out (executed calls: %d)", r.callsExecuted))
|
||||
}
|
||||
t0 := time.Since(r.start)
|
||||
|
||||
// Parameters are considered a kind of local values.
|
||||
for i, param := range params {
|
||||
@@ -106,6 +103,13 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
}
|
||||
switch inst.opcode {
|
||||
case llvm.Ret:
|
||||
const maxInterpSeconds = 180
|
||||
if t0 > maxInterpSeconds*time.Second {
|
||||
// Running for more than maxInterpSeconds seconds. This should never happen, but does.
|
||||
// See github.com/tinygo-org/tinygo/issues/2124
|
||||
return nil, mem, r.errorAt(fn.blocks[0].instructions[0], fmt.Errorf("interp: running for more than %d seconds, timing out (executed calls: %d)", maxInterpSeconds, r.callsExecuted))
|
||||
}
|
||||
|
||||
if len(operands) != 0 {
|
||||
if r.debug {
|
||||
fmt.Fprintln(os.Stderr, indent+"ret", operands[0])
|
||||
@@ -197,7 +201,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
// which case this call won't even get to this point but will
|
||||
// already be emitted in initAll.
|
||||
continue
|
||||
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet" || callFn.name == "os.runtime_args":
|
||||
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet" ||
|
||||
callFn.name == "os.runtime_args" || callFn.name == "internal/task.start" || callFn.name == "internal/task.Current":
|
||||
// These functions should be run at runtime. Specifically:
|
||||
// * Print and panic functions are best emitted directly without
|
||||
// interpreting them, otherwise we get a ton of putchar (etc.)
|
||||
@@ -208,6 +213,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
// * os.runtime_args reads globals that are initialized outside
|
||||
// the view of the interp package so it always needs to be run
|
||||
// at runtime.
|
||||
// * internal/task.start, internal/task.Current: start and read shcheduler state,
|
||||
// which is modified elsewhere.
|
||||
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
||||
if err != nil {
|
||||
return nil, mem, err
|
||||
@@ -376,6 +383,10 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
if !actualTypePtrToInt.IsAConstantInt().IsNil() && actualTypePtrToInt.ZExtValue() == 0 {
|
||||
locals[inst.localIndex] = literalValue{uint8(0)}
|
||||
break
|
||||
}
|
||||
actualType := actualTypePtrToInt.Operand(0)
|
||||
if strings.TrimPrefix(actualType.Name(), "reflect/types.type:") == strings.TrimPrefix(assertedType.Name(), "reflect/types.typeid:") {
|
||||
locals[inst.localIndex] = literalValue{uint8(1)}
|
||||
@@ -433,7 +444,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
}
|
||||
|
||||
// Load the type code of the interface value.
|
||||
typecodeIDBitCast, err := operands[len(operands)-3].toLLVMValue(inst.llvmInst.Operand(len(operands)-4).Type(), &mem)
|
||||
typecodeIDBitCast, err := operands[len(operands)-2].toLLVMValue(inst.llvmInst.Operand(len(operands)-3).Type(), &mem)
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
@@ -481,7 +492,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
// Call a function with a definition available. Run it as usual,
|
||||
// possibly trying to recover from it if it failed to execute.
|
||||
if r.debug {
|
||||
argStrings := make([]string, len(operands)-1)
|
||||
argStrings := make([]string, len(operands))
|
||||
for i := range argStrings {
|
||||
argStrings[i] = operands[i+1].String()
|
||||
}
|
||||
@@ -521,7 +532,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
size := operands[1].(literalValue).value.(uint64)
|
||||
if mem.hasExternalStore(ptr) {
|
||||
if inst.llvmInst.IsVolatile() || inst.llvmInst.Ordering() != llvm.AtomicOrderingNotAtomic || mem.hasExternalStore(ptr) {
|
||||
// If there could be an external store (for example, because a
|
||||
// pointer to the object was passed to a function that could not
|
||||
// be interpreted at compile time) then the load must be done at
|
||||
@@ -551,7 +562,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
if mem.hasExternalLoadOrStore(ptr) {
|
||||
if inst.llvmInst.IsVolatile() || inst.llvmInst.Ordering() != llvm.AtomicOrderingNotAtomic || mem.hasExternalLoadOrStore(ptr) {
|
||||
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
||||
if err != nil {
|
||||
return nil, mem, err
|
||||
@@ -925,12 +936,18 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me
|
||||
if inst.llvmInst.IsVolatile() {
|
||||
result.SetVolatile(true)
|
||||
}
|
||||
if ordering := inst.llvmInst.Ordering(); ordering != llvm.AtomicOrderingNotAtomic {
|
||||
result.SetOrdering(ordering)
|
||||
}
|
||||
case llvm.Store:
|
||||
mem.markExternalStore(operands[1])
|
||||
result = r.builder.CreateStore(operands[0], operands[1])
|
||||
if inst.llvmInst.IsVolatile() {
|
||||
result.SetVolatile(true)
|
||||
}
|
||||
if ordering := inst.llvmInst.Ordering(); ordering != llvm.AtomicOrderingNotAtomic {
|
||||
result.SetOrdering(ordering)
|
||||
}
|
||||
case llvm.BitCast:
|
||||
result = r.builder.CreateBitCast(operands[0], inst.llvmInst.Type(), inst.name)
|
||||
case llvm.ExtractValue:
|
||||
|
||||
+8
-1
@@ -903,7 +903,14 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value,
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
if llvmValue.Type() != llvmType {
|
||||
llvmValue = llvm.ConstBitCast(llvmValue, llvmType)
|
||||
if llvmValue.Type().PointerAddressSpace() != llvmType.PointerAddressSpace() {
|
||||
// Special case for AVR function pointers.
|
||||
// Because go-llvm doesn't have addrspacecast at the moment,
|
||||
// do it indirectly with a ptrtoint/inttoptr pair.
|
||||
llvmValue = llvm.ConstIntToPtr(llvm.ConstPtrToInt(llvmValue, mem.r.uintptrType), llvmType)
|
||||
} else {
|
||||
llvmValue = llvm.ConstBitCast(llvmValue, llvmType)
|
||||
}
|
||||
}
|
||||
return llvmValue, nil
|
||||
}
|
||||
|
||||
Vendored
+3
@@ -5,6 +5,7 @@ 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
|
||||
@@ -23,5 +24,7 @@ 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
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -2,6 +2,7 @@ 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:
|
||||
|
||||
Vendored
+39
-8
@@ -7,28 +7,33 @@ 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, 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)
|
||||
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)
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @foo.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||
define internal void @foo.init(i8* %context) unnamed_addr {
|
||||
store i64 5, i64* @foo.knownAtRuntime
|
||||
unreachable ; this triggers a revert of @foo.init.
|
||||
}
|
||||
|
||||
define internal void @bar.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||
define internal void @bar.init(i8* %context) unnamed_addr {
|
||||
%val = load i64, i64* @foo.knownAtRuntime
|
||||
store i64 %val, i64* @bar.knownAtRuntime
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @baz.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||
define internal void @baz.init(i8* %context) 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
|
||||
@@ -36,8 +41,34 @@ define internal void @baz.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||
unreachable ; trigger revert
|
||||
}
|
||||
|
||||
define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||
define internal void @main.init(i8* %context) 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
|
||||
}
|
||||
|
||||
Vendored
+26
-4
@@ -5,24 +5,46 @@ 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, i8* undef)
|
||||
call fastcc void @foo.init(i8* undef, i8* undef)
|
||||
call fastcc void @baz.init(i8* undef)
|
||||
call fastcc void @foo.init(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, i8* %parentHandle) unnamed_addr {
|
||||
define internal fastcc void @foo.init(i8* %context) unnamed_addr {
|
||||
store i64 5, i64* @foo.knownAtRuntime, align 8
|
||||
unreachable
|
||||
}
|
||||
|
||||
define internal fastcc void @baz.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||
define internal fastcc void @baz.init(i8* %context) 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
|
||||
}
|
||||
|
||||
Submodule
+1
Submodule lib/macos-minimal-sdk added at ebb736fda2
+1
-1
Submodule lib/stm32-svd updated: 5f417214ef...e6db8e32d5
+93
-88
@@ -14,8 +14,8 @@ package loader
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
@@ -43,27 +44,21 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
|
||||
return "", errors.New("could not determine TINYGOROOT")
|
||||
}
|
||||
|
||||
// Determine the location of the cached GOROOT.
|
||||
version, err := goenv.GorootVersionString(goroot)
|
||||
// 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)
|
||||
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 the merge links to create a cache key.
|
||||
data, err := json.Marshal(merge)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
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
|
||||
@@ -74,14 +69,21 @@ 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
|
||||
}
|
||||
tmpgoroot, err := ioutil.TempDir(goenv.Get("GOCACHE"), cachedgorootName+".tmp")
|
||||
|
||||
// Create a temporary directory to construct the goroot within.
|
||||
tmpgoroot, err := ioutil.TempDir(goenv.Get("GOCACHE"), cachedGorootName+".tmp")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -90,16 +92,34 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
|
||||
// (for example, when there was an error).
|
||||
defer os.RemoveAll(tmpgoroot)
|
||||
|
||||
for _, name := range []string{"bin", "lib", "pkg"} {
|
||||
err = symlink(filepath.Join(goroot, name), filepath.Join(tmpgoroot, name))
|
||||
// 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))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
err = mergeDirectory(goroot, tinygoroot, tmpgoroot, "", pathsToOverride(needsSyscallPackage(config.BuildTags())))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Rename the new merged gorooot into place.
|
||||
err = os.Rename(tmpgoroot, cachedgoroot)
|
||||
if err != nil {
|
||||
if os.IsExist(err) {
|
||||
@@ -122,86 +142,71 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
|
||||
return cachedgoroot, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
// 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
|
||||
}
|
||||
|
||||
// Merge subdirectories. Start by making the directory to merge.
|
||||
err := os.Mkdir(filepath.Join(tmpgoroot, "src", importPath), 0777)
|
||||
// Add files from TinyGo.
|
||||
tinygoDir := filepath.Join(tinygoSrc, dir)
|
||||
tinygoEntries, err := ioutil.ReadDir(tinygoDir)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 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
|
||||
var hasTinyGoFiles bool
|
||||
for _, e := range tinygoEntries {
|
||||
if e.IsDir() {
|
||||
// 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
|
||||
continue
|
||||
}
|
||||
|
||||
// Link this file.
|
||||
name := e.Name()
|
||||
merges[filepath.Join("src", dir, name)] = filepath.Join(tinygoDir, name)
|
||||
|
||||
hasTinyGoFiles = true
|
||||
}
|
||||
|
||||
// Symlink all directories from $GOROOT that are not part of the TinyGo
|
||||
// Add all directories from $GOROOT that are not part of the TinyGo
|
||||
// overrides.
|
||||
gorootEntries, err := ioutil.ReadDir(filepath.Join(goroot, "src", importPath))
|
||||
goDir := filepath.Join(goSrc, dir)
|
||||
goEntries, err := ioutil.ReadDir(goDir)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
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 {
|
||||
for _, e := range goEntries {
|
||||
isDir := e.IsDir()
|
||||
if hasTinyGoFiles && !isDir {
|
||||
// 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.
|
||||
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
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
// Merge the special directories from goroot.
|
||||
for _, dir := range []string{"bin", "lib", "pkg"} {
|
||||
merges[dir] = filepath.Join(goroot, dir)
|
||||
}
|
||||
|
||||
return merges, nil
|
||||
}
|
||||
|
||||
// needsSyscallPackage returns whether the syscall package should be overriden
|
||||
@@ -219,7 +224,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,
|
||||
|
||||
+6
-1
@@ -3,9 +3,11 @@ 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
|
||||
@@ -24,7 +26,10 @@ func List(config *compileopts.Config, extraArgs, pkgs []string) (*exec.Cmd, erro
|
||||
if config.CgoEnabled() {
|
||||
cgoEnabled = "1"
|
||||
}
|
||||
cmd := exec.Command("go", args...)
|
||||
cmd := exec.Command(filepath.Join(goenv.Get("GOROOT"), "bin", "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
|
||||
}
|
||||
|
||||
+17
-7
@@ -47,6 +47,14 @@ 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
|
||||
@@ -86,9 +94,14 @@ func Load(config *compileopts.Config, inputPkgs []string, clangHeaders string, t
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wd, err := os.Getwd()
|
||||
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
|
||||
}
|
||||
}
|
||||
p := &Program{
|
||||
config: config,
|
||||
@@ -405,10 +418,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
||||
var initialCFlags []string
|
||||
initialCFlags = append(initialCFlags, p.program.config.CFlags()...)
|
||||
initialCFlags = append(initialCFlags, "-I"+p.Dir)
|
||||
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)
|
||||
generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.program.fset, initialCFlags, p.program.clangHeaders)
|
||||
p.CFlags = append(initialCFlags, cflags...)
|
||||
p.CGoHeaders = headerCode
|
||||
for path, hash := range accessedFiles {
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
@@ -18,6 +19,7 @@ import (
|
||||
"runtime/pprof"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
@@ -28,7 +30,6 @@ 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"
|
||||
@@ -177,14 +178,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, options *compileopts.Options, testCompileOnly, testVerbose, testShort bool, testRunRegexp string, outpath string) (bool, error) {
|
||||
func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options, testCompileOnly, testVerbose, testShort bool, testRunRegexp string, testBenchRegexp string, testBenchTime string, outpath string) (bool, error) {
|
||||
options.TestConfig.CompileTestBinary = true
|
||||
config, err := builder.NewConfig(options)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
passed := true
|
||||
passed := false
|
||||
err = builder.Build(pkgName, outpath, config, func(result builder.BuildResult) error {
|
||||
if testCompileOnly || outpath != "" {
|
||||
// Write test binary to the specified file name.
|
||||
@@ -197,13 +198,18 @@ func Test(pkgName string, options *compileopts.Options, testCompileOnly, testVer
|
||||
}
|
||||
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, result, testVerbose, testShort, testRunRegexp)
|
||||
passed, err = runPackageTest(config, stdout, stderr, result, testVerbose, testShort, testRunRegexp, testBenchRegexp, testBenchTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -212,26 +218,40 @@ func Test(pkgName string, options *compileopts.Options, testCompileOnly, testVer
|
||||
// Print the result.
|
||||
importPath := strings.TrimSuffix(result.ImportPath, ".test")
|
||||
if passed {
|
||||
fmt.Printf("ok \t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
fmt.Fprintf(stdout, "ok \t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
} else {
|
||||
fmt.Printf("FAIL\t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
fmt.Fprintf(stdout, "FAIL\t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err, ok := err.(loader.NoTestFilesError); ok {
|
||||
fmt.Printf("? \t%s\t[no test files]\n", err.ImportPath)
|
||||
fmt.Fprintf(stdout, "? \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, result builder.BuildResult, testVerbose, testShort bool, testRunRegexp string) (bool, error) {
|
||||
func runPackageTest(config *compileopts.Config, stdout, stderr io.Writer, result builder.BuildResult, testVerbose, testShort bool, testRunRegexp string, testBenchRegexp string, testBenchTime string) (bool, error) {
|
||||
var cmd *exec.Cmd
|
||||
if len(config.Target.Emulator) == 0 {
|
||||
emulator := config.Emulator()
|
||||
if len(emulator) == 0 {
|
||||
// Run directly.
|
||||
var flags []string
|
||||
if testVerbose {
|
||||
@@ -243,15 +263,33 @@ func runPackageTest(config *compileopts.Config, result builder.BuildResult, test
|
||||
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(config.Target.Emulator[1:], result.Binary)
|
||||
if config.Target.Emulator[0] == "wasmtime" {
|
||||
// allow reading from current directory: --dir=.
|
||||
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)
|
||||
}
|
||||
|
||||
// mark end of wasmtime arguments and start of program ones: --
|
||||
args = append(args, "--dir=.", "--")
|
||||
args = append(args, "--")
|
||||
if testVerbose {
|
||||
args = append(args, "-test.v")
|
||||
}
|
||||
@@ -261,11 +299,15 @@ func runPackageTest(config *compileopts.Config, result builder.BuildResult, test
|
||||
if testRunRegexp != "" {
|
||||
args = append(args, "-test.run="+testRunRegexp)
|
||||
}
|
||||
if testBenchRegexp != "" {
|
||||
args = append(args, "-test.bench="+testBenchRegexp)
|
||||
}
|
||||
}
|
||||
cmd = executeCommand(config.Options, config.Target.Emulator[0], args...)
|
||||
cmd = executeCommand(config.Options, emulator[0], args...)
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Dir = result.MainDir
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
if _, ok := err.(*exec.ExitError); ok {
|
||||
@@ -459,12 +501,13 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
|
||||
gdbInterface, openocdInterface := config.Programmer()
|
||||
switch gdbInterface {
|
||||
case "msd", "command", "":
|
||||
if len(config.Target.Emulator) != 0 {
|
||||
if config.Target.Emulator[0] == "mgba" {
|
||||
emulator := config.Emulator()
|
||||
if len(emulator) != 0 {
|
||||
if emulator[0] == "mgba" {
|
||||
gdbInterface = "mgba"
|
||||
} else if config.Target.Emulator[0] == "simavr" {
|
||||
} else if emulator[0] == "simavr" {
|
||||
gdbInterface = "simavr"
|
||||
} else if strings.HasPrefix(config.Target.Emulator[0], "qemu-system-") {
|
||||
} else if strings.HasPrefix(emulator[0], "qemu-system-") {
|
||||
gdbInterface = "qemu"
|
||||
} else {
|
||||
// Assume QEMU as an emulator.
|
||||
@@ -532,34 +575,34 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
|
||||
}
|
||||
case "qemu":
|
||||
port = ":1234"
|
||||
|
||||
emulator := config.Emulator()
|
||||
// Run in an emulator.
|
||||
args := append(config.Target.Emulator[1:], result.Binary, "-s", "-S")
|
||||
daemon = executeCommand(config.Options, config.Target.Emulator[0], args...)
|
||||
args := append(emulator[1:], result.Binary, "-s", "-S")
|
||||
daemon = executeCommand(config.Options, 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(config.Target.Emulator[1:], "-g", "1234", result.Binary)
|
||||
daemon = executeCommand(config.Options, config.Target.Emulator[0], args...)
|
||||
args := append(emulator[1:], "-g", "1234", result.Binary)
|
||||
daemon = executeCommand(config.Options, emulator[0], args...)
|
||||
daemon.Stdout = os.Stdout
|
||||
daemon.Stderr = os.Stderr
|
||||
case "mgba":
|
||||
port = ":2345"
|
||||
|
||||
emulator := config.Emulator()
|
||||
// Run in an emulator.
|
||||
args := append(config.Target.Emulator[1:], result.Binary, "-g")
|
||||
daemon = executeCommand(config.Options, config.Target.Emulator[0], args...)
|
||||
args := append(emulator[1:], result.Binary, "-g")
|
||||
daemon = executeCommand(config.Options, emulator[0], args...)
|
||||
daemon.Stdout = os.Stdout
|
||||
daemon.Stderr = os.Stderr
|
||||
case "simavr":
|
||||
port = ":1234"
|
||||
|
||||
emulator := config.Emulator()
|
||||
// Run in an emulator.
|
||||
args := append(config.Target.Emulator[1:], "-g", result.Binary)
|
||||
daemon = executeCommand(config.Options, config.Target.Emulator[0], args...)
|
||||
args := append(emulator[1:], "-g", result.Binary)
|
||||
daemon = executeCommand(config.Options, emulator[0], args...)
|
||||
daemon.Stdout = os.Stdout
|
||||
daemon.Stderr = os.Stderr
|
||||
case "msd":
|
||||
@@ -654,7 +697,8 @@ func Run(pkgName string, options *compileopts.Options) error {
|
||||
}
|
||||
|
||||
return builder.Build(pkgName, ".elf", config, func(result builder.BuildResult) error {
|
||||
if len(config.Target.Emulator) == 0 {
|
||||
emulator := config.Emulator()
|
||||
if len(emulator) == 0 {
|
||||
// Run directly.
|
||||
cmd := executeCommand(config.Options, result.Binary)
|
||||
cmd.Stdout = os.Stdout
|
||||
@@ -670,8 +714,8 @@ func Run(pkgName string, options *compileopts.Options) error {
|
||||
return nil
|
||||
} else {
|
||||
// Run in an emulator.
|
||||
args := append(config.Target.Emulator[1:], result.Binary)
|
||||
cmd := executeCommand(config.Options, config.Target.Emulator[0], args...)
|
||||
args := append(emulator[1:], result.Binary)
|
||||
cmd := executeCommand(config.Options, emulator[0], args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
@@ -719,7 +763,12 @@ func flashUF2UsingMSD(volume, tmppath string, options *compileopts.Options) erro
|
||||
var infoPath string
|
||||
switch runtime.GOOS {
|
||||
case "linux", "freebsd":
|
||||
infoPath = "/media/*/" + volume + "/INFO_UF2.TXT"
|
||||
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"
|
||||
}
|
||||
case "darwin":
|
||||
infoPath = "/Volumes/" + volume + "/INFO_UF2.TXT"
|
||||
case "windows":
|
||||
@@ -743,7 +792,12 @@ func flashHexUsingMSD(volume, tmppath string, options *compileopts.Options) erro
|
||||
var destPath string
|
||||
switch runtime.GOOS {
|
||||
case "linux", "freebsd":
|
||||
destPath = "/media/*/" + volume
|
||||
fi, err := os.Stat("/run/media")
|
||||
if err != nil || !fi.IsDir() {
|
||||
destPath = "/media/*/" + volume
|
||||
} else {
|
||||
destPath = "/run/media/*/" + volume
|
||||
}
|
||||
case "darwin":
|
||||
destPath = "/Volumes/" + volume
|
||||
case "windows":
|
||||
@@ -1045,15 +1099,6 @@ 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 {
|
||||
@@ -1138,10 +1183,11 @@ 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, extalloc, conservative)")
|
||||
gc := flag.String("gc", "", "garbage collector to use (none, leaking, conservative)")
|
||||
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
|
||||
scheduler := flag.String("scheduler", "", "which scheduler to use (none, coroutines, tasks, asyncify)")
|
||||
scheduler := flag.String("scheduler", "", "which scheduler to use (none, tasks, asyncify)")
|
||||
serial := flag.String("serial", "", "which serial output to use (none, uart, usb)")
|
||||
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")
|
||||
@@ -1163,8 +1209,10 @@ func main() {
|
||||
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
|
||||
|
||||
var flagJSON, flagDeps, flagTest *bool
|
||||
if command == "help" || command == "list" {
|
||||
if command == "help" || command == "list" || command == "info" {
|
||||
flagJSON = flag.Bool("json", false, "print data in JSON format")
|
||||
}
|
||||
if command == "help" || command == "list" {
|
||||
flagDeps = flag.Bool("deps", false, "supply -deps flag to go list")
|
||||
flagTest = flag.Bool("test", false, "supply -test flag to go list")
|
||||
}
|
||||
@@ -1173,12 +1221,16 @@ func main() {
|
||||
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
|
||||
@@ -1224,10 +1276,11 @@ func main() {
|
||||
PanicStrategy: *panicStrategy,
|
||||
Scheduler: *scheduler,
|
||||
Serial: *serial,
|
||||
Work: *work,
|
||||
PrintIR: *printIR,
|
||||
DumpSSA: *dumpSSA,
|
||||
VerifyIR: *verifyIR,
|
||||
Parallelism: *parallelism,
|
||||
Semaphore: make(chan struct{}, *parallelism),
|
||||
Debug: !*nodebug,
|
||||
PrintSizes: *printSize,
|
||||
PrintStacks: *printStacks,
|
||||
@@ -1315,11 +1368,13 @@ func main() {
|
||||
handleCompilerError(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
spec, err := compileopts.LoadTarget(options)
|
||||
if err != nil {
|
||||
handleCompilerError(err)
|
||||
}
|
||||
config := &compileopts.Config{
|
||||
Options: options,
|
||||
Target: &compileopts.TargetSpec{
|
||||
Triple: *target,
|
||||
},
|
||||
Target: spec,
|
||||
}
|
||||
path, err := lib.Load(config, tmpdir)
|
||||
handleCompilerError(err)
|
||||
@@ -1358,16 +1413,69 @@ func main() {
|
||||
if len(pkgNames) == 0 {
|
||||
pkgNames = []string{"."}
|
||||
}
|
||||
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
|
||||
}
|
||||
if outpath != "" && len(pkgNames) > 1 {
|
||||
fmt.Println("cannot use -o flag with multiple packages")
|
||||
os.Exit(1)
|
||||
}
|
||||
if !allTestsPassed {
|
||||
|
||||
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:
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// 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 {
|
||||
fmt.Println("FAIL")
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -1424,14 +1532,37 @@ func main() {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
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)
|
||||
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)
|
||||
}
|
||||
case "list":
|
||||
config, err := builder.NewConfig(options)
|
||||
if err != nil {
|
||||
@@ -1505,3 +1636,117 @@ 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
|
||||
}
|
||||
|
||||
+328
-100
@@ -6,12 +6,16 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -27,7 +31,18 @@ const TESTDATA = "testdata"
|
||||
|
||||
var testTarget = flag.String("target", "", "override test target")
|
||||
|
||||
func TestCompiler(t *testing.T) {
|
||||
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()
|
||||
|
||||
tests := []string{
|
||||
"alias.go",
|
||||
"atomic.go",
|
||||
@@ -54,7 +69,6 @@ func TestCompiler(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)
|
||||
@@ -67,12 +81,13 @@ func TestCompiler(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), tests, t)
|
||||
runPlatTests(optionsFromTarget(*testTarget, sema), tests, t)
|
||||
return
|
||||
}
|
||||
|
||||
t.Run("Host", func(t *testing.T) {
|
||||
runPlatTests(optionsFromTarget(""), tests, t)
|
||||
t.Parallel()
|
||||
runPlatTests(optionsFromTarget("", sema), tests, t)
|
||||
})
|
||||
|
||||
// Test a few build options.
|
||||
@@ -82,38 +97,29 @@ func TestCompiler(t *testing.T) {
|
||||
// Test with few optimizations enabled (no inlining, etc).
|
||||
t.Run("opt=1", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
runTestWithConfig("stdlib.go", t, compileopts.Options{
|
||||
GOOS: goenv.Get("GOOS"),
|
||||
GOARCH: goenv.Get("GOARCH"),
|
||||
GOARM: goenv.Get("GOARM"),
|
||||
Opt: "1",
|
||||
}, nil, nil)
|
||||
opts := optionsFromTarget("", sema)
|
||||
opts.Opt = "1"
|
||||
runTestWithConfig("stdlib.go", t, opts, 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()
|
||||
runTestWithConfig("print.go", t, compileopts.Options{
|
||||
GOOS: goenv.Get("GOOS"),
|
||||
GOARCH: goenv.Get("GOARCH"),
|
||||
GOARM: goenv.Get("GOARM"),
|
||||
Opt: "0",
|
||||
}, nil, nil)
|
||||
opts := optionsFromTarget("", sema)
|
||||
opts.Opt = "0"
|
||||
runTestWithConfig("print.go", t, opts, nil, nil)
|
||||
})
|
||||
|
||||
t.Run("ldflags", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
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",
|
||||
},
|
||||
opts := optionsFromTarget("", sema)
|
||||
opts.GlobalValues = map[string]map[string]string{
|
||||
"main": {
|
||||
"someGlobal": "foobar",
|
||||
},
|
||||
}, nil, nil)
|
||||
}
|
||||
runTestWithConfig("ldflags.go", t, opts, nil, nil)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -124,34 +130,89 @@ func TestCompiler(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Run("EmulatedCortexM3", func(t *testing.T) {
|
||||
runPlatTests(optionsFromTarget("cortex-m-qemu"), tests, t)
|
||||
t.Parallel()
|
||||
runPlatTests(optionsFromTarget("cortex-m-qemu", sema), tests, t)
|
||||
})
|
||||
|
||||
t.Run("EmulatedRISCV", func(t *testing.T) {
|
||||
runPlatTests(optionsFromTarget("riscv-qemu"), tests, 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)
|
||||
})
|
||||
|
||||
if runtime.GOOS == "linux" {
|
||||
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)
|
||||
})
|
||||
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("WebAssembly", func(t *testing.T) {
|
||||
runPlatTests(optionsFromTarget("wasm"), tests, t)
|
||||
t.Parallel()
|
||||
runPlatTests(optionsFromTarget("wasm", sema), tests, t)
|
||||
})
|
||||
t.Run("WASI", func(t *testing.T) {
|
||||
runPlatTests(optionsFromTarget("wasi"), tests, t)
|
||||
t.Parallel()
|
||||
runPlatTests(optionsFromTarget("wasi", sema), tests, t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
t.Parallel()
|
||||
emuCheck(t, options)
|
||||
|
||||
spec, err := compileopts.LoadTarget(&options)
|
||||
if err != nil {
|
||||
t.Fatal("failed to load target spec:", err)
|
||||
}
|
||||
|
||||
for _, name := range tests {
|
||||
name := name // redefine to avoid race condition
|
||||
@@ -160,10 +221,12 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
runTest(name, options, t, nil, nil)
|
||||
})
|
||||
}
|
||||
t.Run("env.go", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
runTest("env.go", options, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"})
|
||||
})
|
||||
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"})
|
||||
})
|
||||
}
|
||||
if options.Target == "wasi" || options.Target == "wasm" {
|
||||
t.Run("alias.go-scheduler-none", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
@@ -186,36 +249,51 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
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])
|
||||
}
|
||||
|
||||
// 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)
|
||||
t.Errorf("searching for emulator: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func optionsFromTarget(target string) compileopts.Options {
|
||||
func optionsFromTarget(target string, sema chan struct{}) 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,
|
||||
GOOS: goenv.Get("GOOS"),
|
||||
GOARCH: goenv.Get("GOARCH"),
|
||||
GOARM: goenv.Get("GOARM"),
|
||||
Target: target,
|
||||
Semaphore: sema,
|
||||
Debug: true,
|
||||
VerifyIR: true,
|
||||
Opt: "z",
|
||||
}
|
||||
}
|
||||
|
||||
// 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) compileopts.Options {
|
||||
func optionsFromOSARCH(osarch string, sema chan struct{}) compileopts.Options {
|
||||
parts := strings.Split(osarch, "/")
|
||||
options := compileopts.Options{
|
||||
GOOS: parts[0],
|
||||
GOARCH: parts[1],
|
||||
GOOS: parts[0],
|
||||
GOARCH: parts[1],
|
||||
Semaphore: sema,
|
||||
Debug: true,
|
||||
VerifyIR: true,
|
||||
Opt: "z",
|
||||
}
|
||||
if options.GOARCH == "arm" {
|
||||
options.GOARM = parts[2]
|
||||
@@ -228,13 +306,6 @@ 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.
|
||||
@@ -293,22 +364,35 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
if spec.GOOS == "windows" {
|
||||
binary += ".exe"
|
||||
}
|
||||
err = runBuild("./"+path, binary, &options)
|
||||
err = Build("./"+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
|
||||
if len(spec.Emulator) == 0 {
|
||||
cmd = exec.Command(binary)
|
||||
|
||||
// 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)
|
||||
} else {
|
||||
args := append(spec.Emulator[1:], binary)
|
||||
cmd = exec.Command(spec.Emulator[0], args...)
|
||||
args := append(emulator[1:], binary)
|
||||
cmd = exec.CommandContext(ctx, emulator[0], args...)
|
||||
}
|
||||
if len(spec.Emulator) != 0 && spec.Emulator[0] == "wasmtime" {
|
||||
|
||||
if len(emulator) != 0 && emulator[0] == "wasmtime" {
|
||||
// Allow reading from the current directory.
|
||||
cmd.Args = append(cmd.Args, "--dir=.")
|
||||
for _, v := range environmentVars {
|
||||
@@ -323,47 +407,41 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
}
|
||||
|
||||
// Run the test.
|
||||
runComplete := make(chan struct{})
|
||||
ranTooLong := false
|
||||
stdout := &bytes.Buffer{}
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if len(emulator) != 0 && emulator[0] == "simavr" {
|
||||
cmd.Stdout = os.Stderr
|
||||
cmd.Stderr = stdout
|
||||
} else {
|
||||
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 ranTooLong {
|
||||
if cerr := ctx.Err(); cerr == context.DeadlineExceeded {
|
||||
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 {
|
||||
@@ -387,6 +465,156 @@ 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.
|
||||
|
||||
@@ -15,5 +15,9 @@ 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)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//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,6 +1,7 @@
|
||||
// Hand created file. DO NOT DELETE.
|
||||
// Cortex-M System Control Block-related definitions.
|
||||
|
||||
//go:build cortexm
|
||||
// +build cortexm
|
||||
|
||||
package arm
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
//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,3 +1,4 @@
|
||||
//go:build feather_m4_can
|
||||
// +build feather_m4_can
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build feather_m4_can
|
||||
// +build feather_m4_can
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build circuitplay_express
|
||||
// +build circuitplay_express
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build pyportal
|
||||
// +build pyportal
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build circuitplay_express
|
||||
// +build circuitplay_express
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build pca10040
|
||||
// +build pca10040
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build stm32
|
||||
// +build stm32
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build wioterminal
|
||||
// +build wioterminal
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build arduino_mega1280
|
||||
// +build arduino_mega1280
|
||||
|
||||
package main
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user