mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-27 15:18:41 +00:00
Compare commits
240 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ff626dcee | |||
| 19e2d12517 | |||
| 6184a6cd35 | |||
| 1fd75ffbda | |||
| 61d36fb3f8 | |||
| b318a941a4 | |||
| 725518f007 | |||
| 04d1261f8a | |||
| 3e2230eadb | |||
| 4f908f4877 | |||
| 319683b863 | |||
| 4af3f618f8 | |||
| 89340f82dc | |||
| 824bf24445 | |||
| 80269b98ba | |||
| 3788b31ba5 | |||
| f4ce11ef37 | |||
| a5f78a3900 | |||
| e409950492 | |||
| 208eb1a817 | |||
| 2920492e0a | |||
| 87a8aafc4f | |||
| f026422b04 | |||
| fb91c7097f | |||
| d7773d3e86 | |||
| b04b690842 | |||
| 8a357af3d8 | |||
| 7ac1ca0ae2 | |||
| 2f3d821b13 | |||
| 6f462fba4c | |||
| ac396708da | |||
| d150badf33 | |||
| 2d85fc6a64 | |||
| 5ca3e4a2da | |||
| e6caa3fe9e | |||
| 571447c7c1 | |||
| 9cb263479c | |||
| f18c6e342f | |||
| 2d5a8d407b | |||
| 36958b2875 | |||
| fae0402fde | |||
| 4517a0c17b | |||
| 6abaee4640 | |||
| 1270a50104 | |||
| 868262f4a7 | |||
| d33ace7b59 | |||
| dd6fa89aa6 | |||
| d513cae5d2 | |||
| e612f7cf3f | |||
| 385a7920e6 | |||
| 077b35e9ad | |||
| 880e940417 | |||
| ad6c89bf64 | |||
| ae6220262a | |||
| e731a31eb9 | |||
| 3023ba584b | |||
| 3a8ef33c72 | |||
| 20b58a0128 | |||
| bfccf3592a | |||
| 272fea13e7 | |||
| b6fd0c818e | |||
| c383a407e3 | |||
| 7b7601d77c | |||
| f7c0466f78 | |||
| 81ce7fb738 | |||
| c2776dcf78 | |||
| ad0340d437 | |||
| 30c4df16f2 | |||
| fe27b674cd | |||
| c78dbcd3f2 | |||
| 8890b57ba0 | |||
| ee3a05f1de | |||
| 9307204111 | |||
| 71878c2c0c | |||
| cef2a82c97 | |||
| 1d9f26cee1 | |||
| 6e58c44390 | |||
| 7d6b667bba | |||
| 72f30ca6ec | |||
| 293b620faf | |||
| ad0af607ef | |||
| da23cdeae4 | |||
| d419cc11bf | |||
| 441dfc98d7 | |||
| 2b3b870bfe | |||
| 7748c4922e | |||
| 50f700ddb5 | |||
| f986ea84ac | |||
| 797a5a2031 | |||
| 3d433fe9f1 | |||
| 1154212c15 | |||
| 22bf045c9a | |||
| 39029cc376 | |||
| 7122755725 | |||
| dcee228c4e | |||
| 9d6e30701b | |||
| 85b59e66da | |||
| 90b0bf646c | |||
| c55ac9f28e | |||
| 2733e376bd | |||
| 331cfb65b7 | |||
| 055950421a | |||
| cfcc894855 | |||
| 8bd0155c51 | |||
| 32a056c32a | |||
| 8e8ad9004f | |||
| 62d8cdb218 | |||
| b6fdbee14e | |||
| a5ceb793be | |||
| 7c546525ea | |||
| d628e3e2cb | |||
| d97e4dbccf | |||
| a7ddb33bea | |||
| 8a93196f1f | |||
| 6714974aba | |||
| d67ec3b266 | |||
| 78775007fa | |||
| ad4d722f54 | |||
| 6384ecace0 | |||
| 38881a2850 | |||
| 0f1cf14743 | |||
| 7c34f7704e | |||
| 377415a6c3 | |||
| 1e13c6d18f | |||
| 14121f4b0e | |||
| 7768195835 | |||
| c095b7e9c4 | |||
| 1f6d34d995 | |||
| 9951eb9990 | |||
| c8f77d26a8 | |||
| 8eaa9bd8d0 | |||
| 6061f3db92 | |||
| 410aa0e0d8 | |||
| c66836cf3a | |||
| ca9211b582 | |||
| cb7d470ba4 | |||
| 5baee9a8ee | |||
| c47f52b546 | |||
| a2588d8db3 | |||
| f529b6071d | |||
| 5557e97888 | |||
| d04b07fa8b | |||
| 7486277012 | |||
| 36d60b8349 | |||
| c55191283b | |||
| ad30085b93 | |||
| e9ca41735a | |||
| df1f83f4e1 | |||
| 5879d785a9 | |||
| 186018abeb | |||
| 828b9614c2 | |||
| f5e933cd4d | |||
| 0952b1b984 | |||
| ed55f56d85 | |||
| edb8766aab | |||
| 413bb55e2c | |||
| 0db1a4bec1 | |||
| 2867da164d | |||
| 7b8ae2d6b6 | |||
| 5b8127fd4e | |||
| cc3e785692 | |||
| 0ea5cfc8fe | |||
| 70f1a5429a | |||
| 2fb2113168 | |||
| cb39611389 | |||
| 45764325b4 | |||
| bb66232164 | |||
| 9679e7f1cc | |||
| 6cdfc298cf | |||
| 9a4bfd0e96 | |||
| ee3106be98 | |||
| 57f49af726 | |||
| 38a80b45d3 | |||
| e9003e2deb | |||
| 204659bdcd | |||
| 08ca1d13d0 | |||
| 53db436a7d | |||
| 0ad15551c8 | |||
| afd65e224a | |||
| 5f50c3b60b | |||
| 8858d49989 | |||
| cf39d8b2c8 | |||
| d92a31b440 | |||
| 9c77a38358 | |||
| d0445d6f83 | |||
| a40b11f535 | |||
| 8c90f4facf | |||
| c7c9a76af5 | |||
| 6984af43a0 | |||
| 81c56c3ab8 | |||
| 3d9a1ca22a | |||
| c2083014b3 | |||
| 603a81f194 | |||
| cfc32794a7 | |||
| 1d9c53d00e | |||
| 8d2a07b927 | |||
| ffe6dfd21b | |||
| cf21380264 | |||
| 534b3b0c0b | |||
| ceeb233ff6 | |||
| de3f0af829 | |||
| a511f18c64 | |||
| 731bd5cd1b | |||
| 4acf59546e | |||
| 2ee4d9aaa1 | |||
| b58b7c59ae | |||
| e14b6a7009 | |||
| a1a2d1ab81 | |||
| 07591178cd | |||
| 43bdc888dd | |||
| 4229e670ce | |||
| 76a7ad2a3e | |||
| e4f551ac7f | |||
| 338590cc75 | |||
| 22d70604d8 | |||
| c6add1e769 | |||
| c6609a02fa | |||
| a449c4813a | |||
| 19fb1bfafc | |||
| f91b6ad0df | |||
| 94459cefe5 | |||
| 803ba4f54d | |||
| 2919fa8b14 | |||
| 6420e90124 | |||
| 2d289addb7 | |||
| 4df145dcb4 | |||
| e065da20cb | |||
| d7c77b6761 | |||
| f51029484a | |||
| 03cfcbc17c | |||
| 649f49e000 | |||
| 3bcd4dc3e0 | |||
| 772c71ec27 | |||
| 9b896dc981 | |||
| d4189feca6 | |||
| 777048cfa9 | |||
| 2b215955ca | |||
| ce25f00769 | |||
| 1a59aecb63 | |||
| cca32e67a9 |
+16
-16
@@ -5,17 +5,17 @@ commands:
|
||||
steps:
|
||||
- run:
|
||||
name: "Pull submodules"
|
||||
command: git submodule update --init --recursive
|
||||
command: git submodule update --init
|
||||
llvm-source-linux:
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- llvm-source-16-v3
|
||||
- llvm-source-18-v1
|
||||
- run:
|
||||
name: "Fetch LLVM source"
|
||||
command: make llvm-source
|
||||
- save_cache:
|
||||
key: llvm-source-16-v3
|
||||
key: llvm-source-18-v1
|
||||
paths:
|
||||
- llvm-project/clang/lib/Headers
|
||||
- llvm-project/clang/include
|
||||
@@ -33,13 +33,13 @@ commands:
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- binaryen-linux-v2
|
||||
- binaryen-linux-v3
|
||||
- run:
|
||||
name: "Build Binaryen"
|
||||
command: |
|
||||
make binaryen
|
||||
- save_cache:
|
||||
key: binaryen-linux-v2
|
||||
key: binaryen-linux-v3
|
||||
paths:
|
||||
- build/wasm-opt
|
||||
test-linux:
|
||||
@@ -75,10 +75,10 @@ commands:
|
||||
- run: go install -tags=llvm<<parameters.llvm>> .
|
||||
- restore_cache:
|
||||
keys:
|
||||
- wasi-libc-sysroot-systemclang-v6
|
||||
- wasi-libc-sysroot-systemclang-v7
|
||||
- run: make wasi-libc
|
||||
- save_cache:
|
||||
key: wasi-libc-sysroot-systemclang-v6
|
||||
key: wasi-libc-sysroot-systemclang-v7
|
||||
paths:
|
||||
- lib/wasi-libc/sysroot
|
||||
- when:
|
||||
@@ -88,7 +88,7 @@ commands:
|
||||
# Do this before gen-device so that it doesn't check the
|
||||
# formatting of generated files.
|
||||
name: Check Go code formatting
|
||||
command: make fmt-check
|
||||
command: make fmt-check lint
|
||||
- run: make gen-device -j4
|
||||
- run: make smoketest XTENSA=0
|
||||
- save_cache:
|
||||
@@ -98,19 +98,19 @@ commands:
|
||||
- /go/pkg/mod
|
||||
|
||||
jobs:
|
||||
test-llvm15-go118:
|
||||
test-llvm15-go119:
|
||||
docker:
|
||||
- image: golang:1.18-bullseye
|
||||
- image: golang:1.19-bullseye
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "15"
|
||||
resource_class: large
|
||||
test-llvm17-go121:
|
||||
test-llvm18-go122:
|
||||
docker:
|
||||
- image: golang:1.21-bullseye
|
||||
- image: golang:1.22-bullseye
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "17"
|
||||
llvm: "18"
|
||||
resource_class: large
|
||||
|
||||
workflows:
|
||||
@@ -118,6 +118,6 @@ workflows:
|
||||
jobs:
|
||||
# This tests our lowest supported versions of Go and LLVM, to make sure at
|
||||
# least the smoke tests still pass.
|
||||
- test-llvm15-go118
|
||||
# This tests the upcoming LLVM 17 support.
|
||||
- test-llvm17-go121
|
||||
- test-llvm15-go119
|
||||
# This tests LLVM 18 support when linking against system libraries.
|
||||
- test-llvm18-go122
|
||||
|
||||
@@ -14,26 +14,36 @@ concurrency:
|
||||
jobs:
|
||||
build-macos:
|
||||
name: build-macos
|
||||
runs-on: macos-11
|
||||
strategy:
|
||||
matrix:
|
||||
# macos-12: amd64 (oldest supported version as of 05-02-2024)
|
||||
# macos-14: arm64 (oldest arm64 version)
|
||||
os: [macos-12, macos-14]
|
||||
include:
|
||||
- os: macos-12
|
||||
goarch: amd64
|
||||
- os: macos-14
|
||||
goarch: arm64
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-16-macos-v1
|
||||
key: llvm-source-18-${{ matrix.os }}-v2
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -44,7 +54,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -55,10 +65,10 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore LLVM build cache
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-16-macos-v1
|
||||
key: llvm-build-18-${{ matrix.os }}-v3
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -73,16 +83,16 @@ jobs:
|
||||
make llvm-build
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save LLVM build cache
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache wasi-libc sysroot
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-v4
|
||||
key: wasi-libc-sysroot-${{ matrix.os }}-v1
|
||||
path: lib/wasi-libc/sysroot
|
||||
- name: Build wasi-libc
|
||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||
@@ -98,7 +108,7 @@ jobs:
|
||||
run: make tinygo-test
|
||||
- name: Make release artifact
|
||||
shell: bash
|
||||
run: cp -p build/release.tar.gz build/tinygo.darwin-amd64.tar.gz
|
||||
run: cp -p build/release.tar.gz build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
|
||||
- name: Publish release artifact
|
||||
# Note: this release artifact is double-zipped, see:
|
||||
# https://github.com/actions/upload-artifact/issues/39
|
||||
@@ -106,10 +116,10 @@ jobs:
|
||||
# - 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
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: darwin-amd64-double-zipped
|
||||
path: build/tinygo.darwin-amd64.tar.gz
|
||||
name: darwin-${{ matrix.goarch }}-double-zipped
|
||||
path: build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
|
||||
- name: Smoke tests
|
||||
shell: bash
|
||||
run: make smoketest TINYGO=$(PWD)/build/tinygo
|
||||
@@ -118,33 +128,32 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
version: [16, 17]
|
||||
version: [16, 17, 18]
|
||||
steps:
|
||||
- name: Update Homebrew
|
||||
run: brew update
|
||||
- name: Set up Homebrew
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
- name: Fix Python symlinks
|
||||
run: |
|
||||
# Github runners have broken symlinks, so relink
|
||||
# see: https://github.com/actions/setup-python/issues/577
|
||||
brew unlink python
|
||||
brew link --overwrite python
|
||||
brew list -1 | grep python | while read formula; do brew unlink $formula; brew link --overwrite $formula; done
|
||||
- name: Install LLVM
|
||||
run: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.version }}
|
||||
brew install llvm@${{ matrix.version }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Build TinyGo (LLVM ${{ matrix.version }})
|
||||
run: go install -tags=llvm${{ matrix.version }}
|
||||
- name: Check binary
|
||||
run: tinygo version
|
||||
- name: Build TinyGo (default LLVM)
|
||||
if: matrix.version == 16
|
||||
if: matrix.version == 18
|
||||
run: go install
|
||||
- name: Check binary
|
||||
if: matrix.version == 16
|
||||
if: matrix.version == 18
|
||||
run: tinygo version
|
||||
|
||||
@@ -19,15 +19,26 @@ jobs:
|
||||
packages: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Free Disk space
|
||||
shell: bash
|
||||
run: |
|
||||
df -h
|
||||
sudo rm -rf /opt/hostedtoolcache
|
||||
sudo rm -rf /usr/local/lib/android
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf /usr/local/graalvm
|
||||
sudo rm -rf /usr/local/share/boost
|
||||
df -h
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
tinygo/tinygo-dev
|
||||
@@ -36,24 +47,23 @@ jobs:
|
||||
type=sha,format=long
|
||||
type=raw,value=latest
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
- name: Log in to Github Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-contexts: tinygo-llvm-build=docker-image://tinygo/llvm-16
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
- name: Trigger Drivers repo build on Github Actions
|
||||
|
||||
+63
-59
@@ -18,32 +18,32 @@ jobs:
|
||||
# statically linked binary.
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: golang:1.21-alpine
|
||||
image: golang:1.22-alpine
|
||||
steps:
|
||||
- name: Install apk dependencies
|
||||
# tar: needed for actions/cache@v3
|
||||
# tar: needed for actions/cache@v4
|
||||
# git+openssh: needed for checkout (I think?)
|
||||
# ruby: needed to install fpm
|
||||
run: apk add tar git openssh make g++ ruby
|
||||
run: apk add tar git openssh make g++ ruby-dev
|
||||
- name: Work around CVE-2022-24765
|
||||
# We're not on a multi-user machine, so this is safe.
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-16-linux-alpine-v1
|
||||
key: llvm-source-18-linux-alpine-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -65,10 +65,10 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore LLVM build cache
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-16-linux-alpine-v1
|
||||
key: llvm-build-18-linux-alpine-v2
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -83,13 +83,13 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save LLVM build cache
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-alpine-v1
|
||||
@@ -100,10 +100,10 @@ jobs:
|
||||
apk add cmake samurai python3
|
||||
make binaryen STATIC=1
|
||||
- name: Cache wasi-libc
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-linux-alpine-v1
|
||||
key: wasi-libc-sysroot-linux-alpine-v2
|
||||
path: lib/wasi-libc/sysroot
|
||||
- name: Build wasi-libc
|
||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||
@@ -113,13 +113,15 @@ jobs:
|
||||
gem install --version 4.0.7 public_suffix
|
||||
gem install --version 2.7.6 dotenv
|
||||
gem install --no-document fpm
|
||||
- name: Run linter
|
||||
run: make lint
|
||||
- name: Build TinyGo release
|
||||
run: |
|
||||
make release deb -j3 STATIC=1
|
||||
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
|
||||
cp -p build/release.deb /tmp/tinygo_amd64.deb
|
||||
- name: Publish release artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-amd64-double-zipped
|
||||
path: |
|
||||
@@ -131,20 +133,22 @@ jobs:
|
||||
needs: build-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
go-version: '1.21'
|
||||
submodules: true
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Install wasmtime
|
||||
run: |
|
||||
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
|
||||
curl https://github.com/bytecodealliance/wasmtime/releases/download/v14.0.4/wasmtime-v14.0.4-x86_64-linux.tar.xz -o wasmtime-v14.0.4-x86_64-linux.tar.xz -SfL
|
||||
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v14.0.4-x86_64-linux.tar.xz --strip-components=1 wasmtime-v14.0.4-x86_64-linux/*
|
||||
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||
with:
|
||||
version: "19.0.1"
|
||||
- name: Install wasm-tools
|
||||
uses: bytecodealliance/actions/wasm-tools/setup@v1
|
||||
- name: Download release artifact
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: linux-amd64-double-zipped
|
||||
- name: Extract release tarball
|
||||
@@ -152,8 +156,8 @@ jobs:
|
||||
mkdir -p ~/lib
|
||||
tar -C ~/lib -xf tinygo.linux-amd64.tar.gz
|
||||
ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo
|
||||
- run: make tinygo-test-wasi-fast
|
||||
- run: make tinygo-test-wasip1-fast
|
||||
- run: make tinygo-test-wasip2-fast
|
||||
- run: make smoketest
|
||||
assert-test-linux:
|
||||
# Run all tests that can run on Linux, with LLVM assertions enabled to catch
|
||||
@@ -161,7 +165,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install apt dependencies
|
||||
@@ -176,25 +180,25 @@ jobs:
|
||||
simavr \
|
||||
ninja-build
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16'
|
||||
node-version: '18'
|
||||
- name: Install wasmtime
|
||||
run: |
|
||||
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
|
||||
curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v14.0.4/wasmtime-v14.0.4-x86_64-linux.tar.xz -o wasmtime-v14.0.4-x86_64-linux.tar.xz -SfL
|
||||
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v14.0.4-x86_64-linux.tar.xz --strip-components=1 wasmtime-v14.0.4-x86_64-linux/*
|
||||
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||
with:
|
||||
version: "19.0.1"
|
||||
- name: Setup `wasm-tools`
|
||||
uses: bytecodealliance/actions/wasm-tools/setup@v1
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-16-linux-asserts-v1
|
||||
key: llvm-source-18-linux-asserts-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -205,7 +209,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -216,10 +220,10 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore LLVM build cache
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-16-linux-asserts-v1
|
||||
key: llvm-build-18-linux-asserts-v2
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -232,13 +236,13 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save LLVM build cache
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-asserts-v1
|
||||
@@ -247,10 +251,10 @@ jobs:
|
||||
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
||||
run: make binaryen
|
||||
- name: Cache wasi-libc
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-linux-asserts-v5
|
||||
key: wasi-libc-sysroot-linux-asserts-v6
|
||||
path: lib/wasi-libc/sysroot
|
||||
- name: Build wasi-libc
|
||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||
@@ -290,7 +294,7 @@ jobs:
|
||||
needs: build-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Install apt dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
@@ -299,15 +303,15 @@ jobs:
|
||||
g++-${{ matrix.toolchain }} \
|
||||
libc6-dev-${{ matrix.libc }}-cross
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-16-linux-v1
|
||||
key: llvm-source-18-linux-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -318,7 +322,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -329,10 +333,10 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore LLVM build cache
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-16-linux-${{ matrix.goarch }}-v1
|
||||
key: llvm-build-18-linux-${{ matrix.goarch }}-v2
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -347,22 +351,22 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save LLVM build cache
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-${{ matrix.goarch }}-v3
|
||||
key: binaryen-linux-${{ matrix.goarch }}-v4
|
||||
path: build/wasm-opt
|
||||
- name: Build Binaryen
|
||||
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
sudo apt-get install --no-install-recommends ninja-build
|
||||
git submodule update --init --recursive lib/binaryen
|
||||
git submodule update --init lib/binaryen
|
||||
make CROSS=${{ matrix.toolchain }} binaryen
|
||||
- name: Install fpm
|
||||
run: |
|
||||
@@ -373,7 +377,7 @@ jobs:
|
||||
run: |
|
||||
make CROSS=${{ matrix.toolchain }}
|
||||
- name: Download amd64 release
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: linux-amd64-double-zipped
|
||||
- name: Extract amd64 release
|
||||
@@ -390,7 +394,7 @@ jobs:
|
||||
cp -p build/release.tar.gz /tmp/tinygo.linux-${{ matrix.goarch }}.tar.gz
|
||||
cp -p build/release.deb /tmp/tinygo_${{ matrix.libc }}.deb
|
||||
- name: Publish release artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-${{ matrix.goarch }}-double-zipped
|
||||
path: |
|
||||
|
||||
@@ -25,18 +25,18 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
tinygo/llvm-16
|
||||
ghcr.io/${{ github.repository_owner }}/llvm-16
|
||||
tinygo/llvm-18
|
||||
ghcr.io/${{ github.repository_owner }}/llvm-18
|
||||
tags: |
|
||||
type=sha,format=long
|
||||
type=raw,value=latest
|
||||
@@ -46,13 +46,13 @@ jobs:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
- name: Log in to Github Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
target: tinygo-llvm-build
|
||||
context: .
|
||||
|
||||
@@ -16,22 +16,22 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Pull musl
|
||||
run: |
|
||||
git submodule update --init lib/musl
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-16-linux-nix-v1
|
||||
key: llvm-source-18-linux-nix-v1
|
||||
path: |
|
||||
llvm-project/compiler-rt
|
||||
- name: Download LLVM source
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
# Command that's part of sizediff.yml. This is put in a separate file so that it
|
||||
# still works after checking out the dev branch (that is, when going from LLVM
|
||||
# 16 to LLVM 17 for example, both Clang 16 and Clang 17 are installed).
|
||||
|
||||
echo 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main' | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends -y \
|
||||
llvm-18-dev \
|
||||
clang-18 \
|
||||
libclang-18-dev \
|
||||
lld-18
|
||||
@@ -9,7 +9,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
sizediff:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
@@ -18,34 +18,26 @@ jobs:
|
||||
run: |
|
||||
echo "$HOME/go/bin" >> $GITHUB_PATH
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # fetch all history (no sparse checkout)
|
||||
submodules: true
|
||||
- name: Install apt dependencies
|
||||
run: |
|
||||
echo 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main' | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends -y \
|
||||
llvm-16-dev \
|
||||
clang-16 \
|
||||
libclang-16-dev \
|
||||
lld-16
|
||||
run: ./.github/workflows/sizediff-install-pkgs.sh
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-16-sizediff-v1
|
||||
key: llvm-source-18-sizediff-v1
|
||||
path: |
|
||||
llvm-project/compiler-rt
|
||||
- name: Download LLVM source
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: go-cache-linux-sizediff-v1-${{ hashFiles('go.mod') }}
|
||||
key: go-cache-linux-sizediff-v2-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
@@ -55,22 +47,25 @@ jobs:
|
||||
- name: Save HEAD
|
||||
run: git branch github-actions-saved-HEAD HEAD
|
||||
|
||||
# Compute sizes for the dev branch
|
||||
- name: Checkout dev branch
|
||||
run: git checkout --no-recurse-submodules `git merge-base HEAD origin/dev`
|
||||
- name: Build tinygo binary for the dev branch
|
||||
run: go install
|
||||
- name: Determine binary sizes on the dev branch
|
||||
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-dev.txt)
|
||||
|
||||
# Compute sizes for the PR branch
|
||||
- name: Checkout PR branch
|
||||
run: git checkout --no-recurse-submodules github-actions-saved-HEAD
|
||||
- name: Build tinygo binary for the PR branch
|
||||
run: go install
|
||||
- name: Determine binary sizes on the PR branch
|
||||
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-pr.txt)
|
||||
|
||||
# Compute sizes for the dev branch
|
||||
- name: Checkout dev branch
|
||||
run: |
|
||||
git reset --hard origin/dev
|
||||
git checkout --no-recurse-submodules `git merge-base HEAD origin/dev`
|
||||
- name: Install apt dependencies on the dev branch
|
||||
# this is only needed on a PR that changes the LLVM version
|
||||
run: ./.github/workflows/sizediff-install-pkgs.sh
|
||||
- name: Build tinygo binary for the dev branch
|
||||
run: go install
|
||||
- name: Determine binary sizes on the dev branch
|
||||
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-dev.txt)
|
||||
|
||||
# Create comment
|
||||
# TODO: add a summary, something like:
|
||||
# - overall size difference (percent)
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: Configure pagefile
|
||||
uses: al-cheb/configure-pagefile-action@v1.3
|
||||
uses: al-cheb/configure-pagefile-action@v1.4
|
||||
with:
|
||||
minimum-size: 8GB
|
||||
maximum-size: 24GB
|
||||
@@ -29,19 +29,19 @@ jobs:
|
||||
run: |
|
||||
scoop install ninja binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Restore cached LLVM source
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-16-windows-v1
|
||||
key: llvm-source-18-windows-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save cached LLVM source
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -63,10 +63,10 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore cached LLVM build
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-16-windows-v2
|
||||
key: llvm-build-18-windows-v2
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -80,16 +80,16 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save cached LLVM build
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache wasi-libc sysroot
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-v4
|
||||
key: wasi-libc-sysroot-v5
|
||||
path: lib/wasi-libc/sysroot
|
||||
- name: Build wasi-libc
|
||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||
@@ -116,7 +116,7 @@ jobs:
|
||||
# - have a dobule-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@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-amd64-double-zipped
|
||||
path: build/release/release.zip
|
||||
@@ -126,7 +126,7 @@ jobs:
|
||||
needs: build-windows
|
||||
steps:
|
||||
- name: Configure pagefile
|
||||
uses: al-cheb/configure-pagefile-action@v1.3
|
||||
uses: al-cheb/configure-pagefile-action@v1.4
|
||||
with:
|
||||
minimum-size: 8GB
|
||||
maximum-size: 24GB
|
||||
@@ -139,14 +139,14 @@ jobs:
|
||||
run: |
|
||||
scoop install binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: windows-amd64-double-zipped
|
||||
path: build/
|
||||
@@ -163,20 +163,20 @@ jobs:
|
||||
needs: build-windows
|
||||
steps:
|
||||
- name: Configure pagefile
|
||||
uses: al-cheb/configure-pagefile-action@v1.3
|
||||
uses: al-cheb/configure-pagefile-action@v1.4
|
||||
with:
|
||||
minimum-size: 8GB
|
||||
maximum-size: 24GB
|
||||
disk-root: "C:"
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: windows-amd64-double-zipped
|
||||
path: build/
|
||||
@@ -192,7 +192,7 @@ jobs:
|
||||
needs: build-windows
|
||||
steps:
|
||||
- name: Configure pagefile
|
||||
uses: al-cheb/configure-pagefile-action@v1.3
|
||||
uses: al-cheb/configure-pagefile-action@v1.4
|
||||
with:
|
||||
minimum-size: 8GB
|
||||
maximum-size: 24GB
|
||||
@@ -205,14 +205,14 @@ jobs:
|
||||
run: |
|
||||
scoop install binaryen && scoop install wasmtime@14.0.4
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: windows-amd64-double-zipped
|
||||
path: build/
|
||||
@@ -220,5 +220,5 @@ jobs:
|
||||
shell: bash
|
||||
working-directory: build
|
||||
run: 7z x release.zip -r
|
||||
- name: Test stdlib packages on wasi
|
||||
run: make tinygo-test-wasi-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo
|
||||
- name: Test stdlib packages on wasip1
|
||||
run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo
|
||||
|
||||
+6
-1
@@ -1,3 +1,8 @@
|
||||
.DS_Store
|
||||
.vscode
|
||||
go.work
|
||||
go.work.sum
|
||||
|
||||
docs/_build
|
||||
src/device/avr/*.go
|
||||
src/device/avr/*.ld
|
||||
@@ -17,7 +22,7 @@ src/device/kendryte/*.go
|
||||
src/device/kendryte/*.s
|
||||
src/device/rp/*.go
|
||||
src/device/rp/*.s
|
||||
vendor
|
||||
./vendor
|
||||
llvm-build
|
||||
llvm-project
|
||||
build/*
|
||||
|
||||
+10
-2
@@ -9,10 +9,11 @@
|
||||
url = https://github.com/avr-rust/avr-mcu.git
|
||||
[submodule "lib/cmsis-svd"]
|
||||
path = lib/cmsis-svd
|
||||
url = https://github.com/tinygo-org/cmsis-svd
|
||||
url = https://github.com/cmsis-svd/cmsis-svd-data.git
|
||||
branch = main
|
||||
[submodule "lib/wasi-libc"]
|
||||
path = lib/wasi-libc
|
||||
url = https://github.com/CraneStation/wasi-libc
|
||||
url = https://github.com/WebAssembly/wasi-libc
|
||||
[submodule "lib/picolibc"]
|
||||
path = lib/picolibc
|
||||
url = https://github.com/keith-packard/picolibc.git
|
||||
@@ -34,3 +35,10 @@
|
||||
[submodule "lib/renesas-svd"]
|
||||
path = lib/renesas-svd
|
||||
url = https://github.com/tinygo-org/renesas-svd.git
|
||||
[submodule "src/net"]
|
||||
path = src/net
|
||||
url = https://github.com/tinygo-org/net.git
|
||||
branch = dev
|
||||
[submodule "lib/wasi-cli"]
|
||||
path = lib/wasi-cli
|
||||
url = https://github.com/WebAssembly/wasi-cli
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ tarball. If you want to help with development of TinyGo itself, you should follo
|
||||
LLVM, Clang and LLD are quite light on dependencies, requiring only standard
|
||||
build tools to be built. Go is of course necessary to build TinyGo itself.
|
||||
|
||||
* Go (1.18+)
|
||||
* Go (1.19+)
|
||||
* GNU Make
|
||||
* Standard build tools (gcc/clang)
|
||||
* git
|
||||
@@ -85,7 +85,7 @@ Now that we have a working static build, it's time to make a release tarball:
|
||||
|
||||
If you did not clone the repository with the `--recursive` option, you will get errors until you initialize the project submodules:
|
||||
|
||||
git submodule update --init --recursive
|
||||
git submodule update --init
|
||||
|
||||
The release tarball is stored in build/release.tar.gz, and can be extracted with
|
||||
the following command (for example in ~/lib):
|
||||
|
||||
+160
@@ -1,3 +1,163 @@
|
||||
0.32.0
|
||||
---
|
||||
|
||||
* **general**
|
||||
- fix wasi-libc include headers on Nix
|
||||
- apply OpenOCD commands after target configuration
|
||||
- fix a minor race condition when determining the build tags
|
||||
- support UF2 drives with a space in their name on Linux
|
||||
- add LLVM 18 support
|
||||
- drop support for Go 1.18 to be able to stay up to date
|
||||
|
||||
* **compiler**
|
||||
- move `-panic=trap` support to the compiler/runtime
|
||||
- fix symbol table index for WebAssembly archives
|
||||
- fix ed25519 build errors by adjusting the alias names
|
||||
- add aliases to generic AES functions
|
||||
- fix race condition by temporarily applying a proposed patch
|
||||
- `builder`: keep un-wasm-opt'd .wasm if -work was passed
|
||||
- `builder`: make sure wasm-opt command line is printed if asked
|
||||
- `cgo`: implement shift operations in preprocessor macros
|
||||
- `interp`: checking for methodset existance
|
||||
|
||||
* **standard library**
|
||||
- `machine`: add `__tinygo_spi_tx` function to simulator
|
||||
- `machine`: fix simulator I2C support
|
||||
- `machine`: add GetRNG support to simulator
|
||||
- `machine`: add `TxFifoFreeLevel` for CAN
|
||||
- `os`: add `Link`
|
||||
- `os`: add `FindProcess` for posix
|
||||
- `os`: add `Process.Release` for unix
|
||||
- `os`: add `SetReadDeadline` stub
|
||||
- `os`, `os/signal`: add signal stubs
|
||||
- `os/user`: add stubs for `Lookup{,Group}` and `Group`
|
||||
- `reflect`: use int in `StringHeader` and `SliceHeader` on non-AVR platforms
|
||||
- `reflect`: fix `NumMethods` for Interface type
|
||||
- `runtime`: skip negative sleep durations in sleepTicks
|
||||
|
||||
* **targets**
|
||||
- `esp32`: add I2C support
|
||||
- `rp2040`: move UART0 and UART1 to common file
|
||||
- `rp2040`: make all RP2040 boards available for simulation
|
||||
- `rp2040`: fix timeUnit type
|
||||
- `stm32`: add i2c `Frequency` and `SetBaudRate` function for chips that were missing implementation
|
||||
- `wasm-unknown`: add math and memory builtins that LLVM needs
|
||||
- `wasip1`: replace existing `-target=wasi` support with wasip1 as supported in Go 1.21+
|
||||
|
||||
* **boards**
|
||||
- `adafruit-esp32-feather-v2`: add the Adafruit ESP32 Feather V2
|
||||
- `badger2040-w`: add support for the Badger2040 W
|
||||
- `feather-nrf52840-sense`: fix lack of LXFO
|
||||
- `m5paper`: add support for the M5 Paper
|
||||
- `mksnanov3`: limit programming speed to 1800 kHz
|
||||
- `nucleol476rg`: add stm32 nucleol476rg support
|
||||
- `pico-w`: add the Pico W (which is near-idential to the pico target)
|
||||
- `thingplus-rp2040`, `waveshare-rp2040-zero`: add WS2812 definition
|
||||
- `pca10059-s140v7`: add this variant to the PCA10059 board
|
||||
|
||||
|
||||
0.31.2
|
||||
---
|
||||
|
||||
* **general**
|
||||
* update the `net` submodule to updated version with `Buffers` implementation
|
||||
|
||||
* **compiler**
|
||||
* `syscall`: add wasm_unknown tag to some additional files so it can compile more code
|
||||
|
||||
* **standard library**
|
||||
* `runtime`: add Frame.Entry field
|
||||
|
||||
|
||||
0.31.1
|
||||
---
|
||||
|
||||
* **general**
|
||||
* fix Binaryen build in make task
|
||||
* update final build stage of Docker `dev` image to go1.22
|
||||
* only use GHA cache for building Docker `dev` image
|
||||
* update the `net` submodule to latest version
|
||||
|
||||
* **compiler**
|
||||
* `interp`: make getelementptr offsets signed
|
||||
* `interp`: return a proper error message when indexing out of range
|
||||
|
||||
|
||||
0.31.0
|
||||
---
|
||||
|
||||
* **general**
|
||||
* remove LLVM 14 support
|
||||
* add LLVM 17 support, and use it by default
|
||||
* add Nix flake support
|
||||
* update bundled Binaryen to version 116
|
||||
* add `ports` subcommand that lists available serial ports for `-port` and `-monitor`
|
||||
* support wasmtime version 14
|
||||
* add `-serial=rtt` for serial output over SWD
|
||||
* add Go 1.22 support and use it by default
|
||||
* change minimum Node.js version from 16 to 18
|
||||
* **compiler**
|
||||
* use the new LLVM pass manager
|
||||
* allow systems with more stack space to allocate larger values on the stack
|
||||
* `build`: fix a crash due to sharing GlobalValues between build instances
|
||||
* `cgo`: add `C._Bool` type
|
||||
* `cgo`: fix calling CGo callback inside generic function
|
||||
* `compileopts`: set `purego` build tag by default so that more packages can be built
|
||||
* `compileopts`: force-enable CGo to avoid build issues
|
||||
* `compiler`: fix crash on type assert on interfaces with no methods
|
||||
* `interp`: print LLVM instruction in traceback
|
||||
* `interp`: support runtime times by running them at runtime
|
||||
* `loader`: enforce Go language version in the type checker (this may break existing programs with an incorrect Go version in go.mod)
|
||||
* `transform`: fix bug in StringToBytes optimization pass
|
||||
* **standard library**
|
||||
* `crypto/tls`: stub out a lot of functions
|
||||
* `internal/task`, `machine`: make TinyGo code usable with "big Go" CGo
|
||||
* `machine`: implement `I2C.SetBaudRate` consistently across chips
|
||||
* `machine`: implement `SPI.Configure` consistently across chips
|
||||
* `machine`: add `DeviceID` for nrf, rp2040, sam, stm32
|
||||
* `machine`: use smaller UART buffer size on atmega chips
|
||||
* `machine/usb`: allow setting a serial number using a linker flag
|
||||
* `math`: support more math functions on baremetal (picolibc) systems
|
||||
* `net`: replace entire net package with a new one based on the netdev driver
|
||||
* `os/user`: add bare-bones implementation of this package
|
||||
* `reflect`: stub `CallSlice` and `FuncOf`
|
||||
* `reflect`: add `TypeFor[T]`
|
||||
* `reflect`: update `IsZero` to Go 1.22 semantics
|
||||
* `reflect`: move indirect values into interface when setting interfaces
|
||||
* `runtime`: stub `Breakpoint`
|
||||
* `sync`: implement trylock
|
||||
* **targets**
|
||||
* `atmega`: use UART double speed mode for fewer errors and higher throughput
|
||||
* `atmega328pb`: refactor to enable extra uart
|
||||
* `avr`: don't compile large parts of picolibc (math, stdio) for LLVM 17 support
|
||||
* `esp32`: switch over to the official SVD file
|
||||
* `esp32c3`: implement USB_SERIAL for USBCDC communication
|
||||
* `esp32c3`: implement I2C
|
||||
* `esp32c3`: implement RNG
|
||||
* `esp32c3`: add more ROM functions and update linker script for the in-progress wifi support
|
||||
* `esp32c3`: update to newer SVD files
|
||||
* `rp2040`: add support for UART hardware flow control
|
||||
* `rp2040`: add definition for `machine.PinToggle`
|
||||
* `rp2040`: set XOSC startup delay multiplier
|
||||
* `samd21`: add support for UART hardware flow control
|
||||
* `samd51`: add support for UART hardware flow control
|
||||
* `wasm`: increase default stack size to 64k for wasi/wasm targets
|
||||
* `wasm`: bump wasi-libc version to SDK 20
|
||||
* `wasm`: remove line of dead code in wasm_exec.js
|
||||
* **new targets/boards**
|
||||
* `qtpy-esp32c3`: add Adafruit QT Py ESP32-C3 board
|
||||
* `mksnanov3`: add support for the MKS Robin Nano V3.x
|
||||
* `nrf52840-generic`: add generic nrf52840 chip support
|
||||
* `thumby`: add support for Thumby
|
||||
* `wasm`: add new `wasm-unknown` target that doesn't depend on WASI or a browser
|
||||
* **boards**
|
||||
* `arduino-mkrwifi1010`, `arduino-nano33`, `nano-rp2040`, `matrixportal-m4`, `metro-m4-airlift`, `pybadge`, `pyportal`: add `ninafw` build tag and some constants for BLE support
|
||||
* `gopher-badge`: fix typo in USB product name
|
||||
* `nano-rp2040`: add UART1 and correct mappings for NINA via UART
|
||||
* `pico`: bump default stack size from 2kB to 8kB
|
||||
* `wioterminal`: expose UART4
|
||||
|
||||
|
||||
0.30.0
|
||||
---
|
||||
|
||||
|
||||
+22
-19
@@ -1,10 +1,15 @@
|
||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||
FROM golang:1.21 AS tinygo-llvm
|
||||
FROM golang:1.22 AS tinygo-llvm
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y apt-utils make cmake clang-15 ninja-build
|
||||
apt-get install -y apt-utils make cmake clang-15 ninja-build && \
|
||||
rm -rf \
|
||||
/var/lib/apt/lists/* \
|
||||
/var/log/* \
|
||||
/var/tmp/* \
|
||||
/tmp/*
|
||||
|
||||
COPY ./Makefile /tinygo/Makefile
|
||||
COPY ./GNUmakefile /tinygo/GNUmakefile
|
||||
|
||||
RUN cd /tinygo/ && \
|
||||
make llvm-source
|
||||
@@ -15,26 +20,24 @@ FROM tinygo-llvm AS tinygo-llvm-build
|
||||
RUN cd /tinygo/ && \
|
||||
make llvm-build
|
||||
|
||||
# tinygo-compiler stage builds the compiler itself
|
||||
FROM tinygo-llvm-build AS tinygo-compiler
|
||||
# tinygo-compiler-build stage builds the compiler itself
|
||||
FROM tinygo-llvm-build AS tinygo-compiler-build
|
||||
|
||||
COPY . /tinygo
|
||||
|
||||
# update submodules
|
||||
# build the compiler and tools
|
||||
RUN cd /tinygo/ && \
|
||||
rm -rf ./lib/*/ && \
|
||||
git submodule sync && \
|
||||
git submodule update --init --recursive --force
|
||||
|
||||
RUN cd /tinygo/ && \
|
||||
make
|
||||
|
||||
# tinygo-tools stage installs the needed dependencies to compile TinyGo programs for all platforms.
|
||||
FROM tinygo-compiler AS tinygo-tools
|
||||
|
||||
RUN cd /tinygo/ && \
|
||||
make wasi-libc binaryen && \
|
||||
git submodule update --init && \
|
||||
make gen-device -j4 && \
|
||||
cp build/* $GOPATH/bin/
|
||||
make build/release
|
||||
|
||||
# tinygo-compiler copies the compiler build over to a base Go container (without
|
||||
# all the build tools etc).
|
||||
FROM golang:1.22 AS tinygo-compiler
|
||||
|
||||
# Copy tinygo build.
|
||||
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
|
||||
|
||||
# Configure the container.
|
||||
ENV PATH="${PATH}:/tinygo/bin"
|
||||
CMD ["tinygo"]
|
||||
|
||||
+123
-37
@@ -10,7 +10,7 @@ LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
|
||||
|
||||
# Try to autodetect LLVM build tools.
|
||||
# Versions are listed here in descending priority order.
|
||||
LLVM_VERSIONS = 17 16 15
|
||||
LLVM_VERSIONS = 18 17 16 15
|
||||
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)
|
||||
@@ -31,6 +31,7 @@ export GOROOT = $(shell $(GO) env GOROOT)
|
||||
|
||||
# Flags to pass to go test.
|
||||
GOTESTFLAGS ?=
|
||||
GOTESTPKGS ?= ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
|
||||
|
||||
# tinygo binary for tests
|
||||
TINYGO ?= $(call detect,tinygo,tinygo $(CURDIR)/build/tinygo)
|
||||
@@ -110,7 +111,7 @@ endif
|
||||
|
||||
.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-nxp gen-device-avr gen-device-rp
|
||||
|
||||
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf debuginfopdb executionengine frontendhlsl frontendopenmp instrumentation interpreter ipo irreader libdriver linker lto mc mcjit objcarcopts option profiledata scalaropts support target windowsdriver windowsmanifest
|
||||
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf debuginfopdb executionengine frontenddriver frontendhlsl frontendopenmp instrumentation interpreter ipo irreader libdriver linker lto mc mcjit objcarcopts option profiledata scalaropts support target windowsdriver windowsmanifest
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
EXE = .exe
|
||||
@@ -146,7 +147,7 @@ endif
|
||||
MD5SUM ?= md5sum
|
||||
|
||||
# Libraries that should be linked in for the statically linked Clang.
|
||||
CLANG_LIB_NAMES = clangAnalysis clangAST clangASTMatchers clangBasic clangCodeGen clangCrossTU clangDriver clangDynamicASTMatchers clangEdit clangExtractAPI clangFormat clangFrontend clangFrontendTool clangHandleCXX clangHandleLLVM clangIndex clangLex clangParse clangRewrite clangRewriteFrontend clangSema clangSerialization clangSupport clangTooling clangToolingASTDiff clangToolingCore clangToolingInclusions
|
||||
CLANG_LIB_NAMES = clangAnalysis clangAPINotes clangAST clangASTMatchers clangBasic clangCodeGen clangCrossTU clangDriver clangDynamicASTMatchers clangEdit clangExtractAPI clangFormat clangFrontend clangFrontendTool clangHandleCXX clangHandleLLVM clangIndex clangLex clangParse clangRewrite clangRewriteFrontend clangSema clangSerialization clangSupport clangTooling clangToolingASTDiff clangToolingCore clangToolingInclusions
|
||||
CLANG_LIBS = $(START_GROUP) $(addprefix -l,$(CLANG_LIB_NAMES)) $(END_GROUP) -lstdc++
|
||||
|
||||
# Libraries that should be linked in for the statically linked LLD.
|
||||
@@ -165,7 +166,7 @@ LIB_NAMES = clang $(CLANG_LIB_NAMES) $(LLD_LIB_NAMES) $(EXTRA_LIB_NAMES)
|
||||
# library path (for ninja).
|
||||
# This list also includes a few tools that are necessary as part of the full
|
||||
# TinyGo build.
|
||||
NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm $(addprefix lib/lib,$(addsuffix .a,$(LIB_NAMES)))
|
||||
NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm lld $(addprefix lib/lib,$(addsuffix .a,$(LIB_NAMES)))
|
||||
|
||||
# For static linking.
|
||||
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
|
||||
@@ -190,7 +191,7 @@ gen-device: gen-device-stm32
|
||||
endif
|
||||
|
||||
gen-device-avr:
|
||||
@if [ ! -e lib/avr/README.md ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init --recursive"; exit 1; fi
|
||||
@if [ ! -e lib/avr/README.md ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
|
||||
$(GO) build -o ./build/gen-device-avr ./tools/gen-device-avr/
|
||||
./build/gen-device-avr lib/avr/packs/atmega src/device/avr/
|
||||
./build/gen-device-avr lib/avr/packs/tiny src/device/avr/
|
||||
@@ -238,13 +239,13 @@ gen-device-renesas: build/gen-device-svd
|
||||
|
||||
# Get LLVM sources.
|
||||
$(LLVM_PROJECTDIR)/llvm:
|
||||
git clone -b xtensa_release_16.x --depth=1 https://github.com/espressif/llvm-project $(LLVM_PROJECTDIR)
|
||||
git clone -b tinygo_xtensa_release_18.1.2 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
|
||||
llvm-source: $(LLVM_PROJECTDIR)/llvm
|
||||
|
||||
# Configure LLVM.
|
||||
TINYGO_SOURCE_DIR=$(shell pwd)
|
||||
$(LLVM_BUILDDIR)/build.ninja:
|
||||
mkdir -p $(LLVM_BUILDDIR) && cd $(LLVM_BUILDDIR) && cmake -G Ninja $(TINYGO_SOURCE_DIR)/$(LLVM_PROJECTDIR)/llvm "-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64;RISCV;WebAssembly" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=AVR;Xtensa" -DCMAKE_BUILD_TYPE=Release -DLIBCLANG_BUILD_STATIC=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ZLIB=OFF -DLLVM_ENABLE_ZSTD=OFF -DLLVM_ENABLE_LIBEDIT=OFF -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_ENABLE_OCAMLDOC=OFF -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF -DCLANG_ENABLE_ARCMT=OFF $(LLVM_OPTION)
|
||||
mkdir -p $(LLVM_BUILDDIR) && cd $(LLVM_BUILDDIR) && cmake -G Ninja $(TINYGO_SOURCE_DIR)/$(LLVM_PROJECTDIR)/llvm "-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64;AVR;Mips;RISCV;WebAssembly" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=Xtensa" -DCMAKE_BUILD_TYPE=Release -DLIBCLANG_BUILD_STATIC=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ZLIB=OFF -DLLVM_ENABLE_ZSTD=OFF -DLLVM_ENABLE_LIBEDIT=OFF -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_ENABLE_OCAMLDOC=OFF -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF -DCLANG_ENABLE_ARCMT=OFF $(LLVM_OPTION)
|
||||
|
||||
# Build LLVM.
|
||||
$(LLVM_BUILDDIR): $(LLVM_BUILDDIR)/build.ninja
|
||||
@@ -256,7 +257,7 @@ ifneq ($(USE_SYSTEM_BINARYEN),1)
|
||||
binaryen: build/wasm-opt$(EXE)
|
||||
build/wasm-opt$(EXE):
|
||||
mkdir -p build
|
||||
cd lib/binaryen && cmake -G Ninja . -DBUILD_STATIC_LIB=ON $(BINARYEN_OPTION) && ninja bin/wasm-opt$(EXE)
|
||||
cd lib/binaryen && cmake -G Ninja . -DBUILD_STATIC_LIB=ON -DBUILD_TESTS=OFF -DENABLE_WERROR=OFF $(BINARYEN_OPTION) && ninja bin/wasm-opt$(EXE)
|
||||
cp lib/binaryen/bin/wasm-opt$(EXE) build/wasm-opt$(EXE)
|
||||
endif
|
||||
|
||||
@@ -264,26 +265,38 @@ endif
|
||||
.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 --recursive"; exit 1; fi
|
||||
@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 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC="$(CLANG)" AR=$(LLVM_AR) NM=$(LLVM_NM)
|
||||
|
||||
# Generate WASI syscall bindings
|
||||
WASM_TOOLS_MODULE=github.com/ydnar/wasm-tools-go
|
||||
.PHONY: wasi-syscall
|
||||
wasi-syscall: wasi-cm
|
||||
go run -modfile ./internal/wasm-tools/go.mod $(WASM_TOOLS_MODULE)/cmd/wit-bindgen-go generate --versioned -o ./src/internal -p internal --cm internal/cm ./lib/wasi-cli/wit
|
||||
|
||||
# Copy package cm into src/internal/cm
|
||||
.PHONY: wasi-cm
|
||||
wasi-cm:
|
||||
# rm -rf ./src/internal/cm
|
||||
rsync -rv --delete --exclude '*_test.go' $(shell go list -modfile ./internal/wasm-tools/go.mod -m -f {{.Dir}} $(WASM_TOOLS_MODULE))/cm ./src/internal/
|
||||
|
||||
# Check for Node.js used during WASM tests.
|
||||
NODEJS_VERSION := $(word 1,$(subst ., ,$(shell node -v | cut -c 2-)))
|
||||
MIN_NODEJS_VERSION=16
|
||||
MIN_NODEJS_VERSION=18
|
||||
|
||||
.PHONY: check-nodejs-version
|
||||
check-nodejs-version:
|
||||
ifeq (, $(shell which node))
|
||||
@echo "Install NodeJS version 16+ to run tests."; exit 1;
|
||||
@echo "Install NodeJS version 18+ to run tests."; exit 1;
|
||||
endif
|
||||
@if [ $(NODEJS_VERSION) -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version 16+ to run tests."; exit 1; fi
|
||||
@if [ $(NODEJS_VERSION) -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version 18+ to run tests."; exit 1; fi
|
||||
|
||||
# Build the Go compiler.
|
||||
tinygo:
|
||||
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " $(MAKE) llvm-source"; echo " $(MAKE) $(LLVM_BUILDDIR)"; exit 1; fi
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
|
||||
test: wasi-libc check-nodejs-version
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags "byollvm osusergo" ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags "byollvm osusergo" $(GOTESTPKGS)
|
||||
|
||||
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
|
||||
TEST_PACKAGES_SLOW = \
|
||||
@@ -426,17 +439,38 @@ tinygo-bench-fast:
|
||||
|
||||
# Same thing, except for wasi rather than the current platform.
|
||||
tinygo-test-wasi:
|
||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||
$(TINYGO) test -target wasip1 $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||
tinygo-test-wasip1:
|
||||
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||
tinygo-test-wasi-fast:
|
||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||
tinygo-test-wasip1-fast:
|
||||
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||
tinygo-bench-wasi:
|
||||
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
|
||||
tinygo-bench-wasi-fast:
|
||||
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST)
|
||||
$(TINYGO) test -target=wasip1 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||
|
||||
tinygo-test-wasip2-slow:
|
||||
$(TINYGO) test -target=wasip2 $(TEST_PACKAGES_SLOW)
|
||||
tinygo-test-wasip2-fast:
|
||||
$(TINYGO) test -target=wasip2 $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||
|
||||
tinygo-test-wasip2-sum-slow:
|
||||
TINYGO=$(TINYGO) \
|
||||
TARGET=wasip2 \
|
||||
TESTOPTS="-x -work" \
|
||||
PACKAGES="$(TEST_PACKAGES_SLOW)" \
|
||||
gotestsum --raw-command -- ./tools/tgtestjson.sh
|
||||
tinygo-test-wasip2-sum-fast:
|
||||
TINYGO=$(TINYGO) \
|
||||
TARGET=wasip2 \
|
||||
TESTOPTS="-x -work" \
|
||||
PACKAGES="$(TEST_PACKAGES_FAST)" \
|
||||
gotestsum --raw-command -- ./tools/tgtestjson.sh
|
||||
tinygo-bench-wasip1:
|
||||
$(TINYGO) test -target wasip1 -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
|
||||
tinygo-bench-wasip1-fast:
|
||||
$(TINYGO) test -target wasip1 -bench . $(TEST_PACKAGES_FAST)
|
||||
|
||||
tinygo-bench-wasip2:
|
||||
$(TINYGO) test -target wasip2 -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
|
||||
tinygo-bench-wasip2-fast:
|
||||
$(TINYGO) test -target wasip2 -bench . $(TEST_PACKAGES_FAST)
|
||||
|
||||
# Test external packages in a large corpus.
|
||||
test-corpus:
|
||||
@@ -444,7 +478,7 @@ test-corpus:
|
||||
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
|
||||
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=wasip1
|
||||
|
||||
tinygo-baremetal:
|
||||
# Regression tests that run on a baremetal target and don't fit in either main_test.go or smoketest.
|
||||
@@ -490,7 +524,7 @@ smoketest:
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=nano-rp2040 examples/rtcinterrupt
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/serial
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/machinetest
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/systick
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -522,7 +556,9 @@ ifneq ($(WASM), 0)
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_bluefruit examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=mch2022 examples/serial
|
||||
$(TINYGO) build -size short -o test.wasm -tags=mch2022 examples/machinetest
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=gopher_badge examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
endif
|
||||
# test all targets/boards
|
||||
@@ -598,6 +634,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10056-s140v7 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10059-s140v7 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=reelboard-s140v7 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/blinky1
|
||||
@@ -616,7 +654,7 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-nrf52840 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=qtpy examples/serial
|
||||
$(TINYGO) build -size short -o test.hex -target=qtpy examples/machinetest
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=teensy41 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -654,6 +692,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=badger2040 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=badger2040-w examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=tufty2040 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=thingplus-rp2040 examples/blinky1
|
||||
@@ -670,6 +710,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=thumby examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
# test pwm
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -684,6 +726,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/usb-midi
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=nrf52840-s140v6-uf2-generic examples/machinetest
|
||||
@$(MD5SUM) test.hex
|
||||
ifneq ($(STM32), 0)
|
||||
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -699,6 +743,8 @@ ifneq ($(STM32), 0)
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=nucleo-l432kc examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=nucleo-l476rg examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=nucleo-l552ze examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=nucleo-wl55jc examples/blinky1
|
||||
@@ -717,8 +763,12 @@ ifneq ($(STM32), 0)
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=swan examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=mksnanov3 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
endif
|
||||
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
|
||||
$(TINYGO) build -size short -o test.hex -target=atmega328pb examples/blinkm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/machinetest
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -745,22 +795,22 @@ ifneq ($(XTENSA), 0)
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/serial
|
||||
$(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target m5stack examples/serial
|
||||
$(TINYGO) build -size short -o test.bin -target m5stack examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target m5stick-c examples/serial
|
||||
$(TINYGO) build -size short -o test.bin -target m5stick-c examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/serial
|
||||
$(TINYGO) build -size short -o test.bin -target m5paper examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
endif
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3 examples/serial
|
||||
$(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/serial
|
||||
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c3 examples/serial
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c3 examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -769,6 +819,7 @@ endif
|
||||
ifneq ($(WASM), 0)
|
||||
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
|
||||
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
|
||||
$(TINYGO) build -size short -o wasm.wasm -target=wasm-unknown examples/hello-wasm-unknown
|
||||
endif
|
||||
# test various compiler flags
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -gc=none -scheduler=none examples/blinky1
|
||||
@@ -777,11 +828,14 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -serial=none examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -serial=rtt examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -o test.nro -target=nintendoswitch examples/serial
|
||||
@$(MD5SUM) test.nro
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
|
||||
@$(MD5SUM) test.hex
|
||||
GOOS=linux GOARCH=arm $(TINYGO) build -size short -o test.elf ./testdata/cgo
|
||||
GOOS=linux GOARCH=mips $(TINYGO) build -size short -o test.elf ./testdata/cgo
|
||||
GOOS=windows GOARCH=amd64 $(TINYGO) build -size short -o test.exe ./testdata/cgo
|
||||
GOOS=windows GOARCH=arm64 $(TINYGO) build -size short -o test.exe ./testdata/cgo
|
||||
GOOS=darwin GOARCH=amd64 $(TINYGO) build -size short -o test ./testdata/cgo
|
||||
@@ -809,7 +863,10 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
|
||||
@mkdir -p build/release/tinygo/lib/nrfx
|
||||
@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/lib/wasi-libc/libc-bottom-half/headers
|
||||
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
|
||||
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||
@mkdir -p build/release/tinygo/lib/wasi-cli/
|
||||
@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
|
||||
@@ -826,6 +883,7 @@ endif
|
||||
@cp -rp lib/musl/arch/arm build/release/tinygo/lib/musl/arch
|
||||
@cp -rp lib/musl/arch/generic build/release/tinygo/lib/musl/arch
|
||||
@cp -rp lib/musl/arch/i386 build/release/tinygo/lib/musl/arch
|
||||
@cp -rp lib/musl/arch/mips build/release/tinygo/lib/musl/arch
|
||||
@cp -rp lib/musl/arch/x86_64 build/release/tinygo/lib/musl/arch
|
||||
@cp -rp lib/musl/crt/crt1.c build/release/tinygo/lib/musl/crt
|
||||
@cp -rp lib/musl/COPYRIGHT build/release/tinygo/lib/musl
|
||||
@@ -836,6 +894,7 @@ endif
|
||||
@cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src
|
||||
@cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
|
||||
@cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src
|
||||
@cp -rp lib/musl/src/linux build/release/tinygo/lib/musl/src
|
||||
@cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
|
||||
@cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
|
||||
@cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src
|
||||
@@ -859,7 +918,16 @@ endif
|
||||
@cp -rp lib/picolibc/newlib/libm/common build/release/tinygo/lib/picolibc/newlib/libm
|
||||
@cp -rp lib/picolibc/newlib/libm/math build/release/tinygo/lib/picolibc/newlib/libm
|
||||
@cp -rp lib/picolibc-stdio.c build/release/tinygo/lib
|
||||
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
|
||||
@cp -rp lib/wasi-libc/libc-bottom-half/headers/public build/release/tinygo/lib/wasi-libc/libc-bottom-half/headers
|
||||
@cp -rp lib/wasi-libc/libc-top-half/musl/arch/generic build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
|
||||
@cp -rp lib/wasi-libc/libc-top-half/musl/arch/wasm32 build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
|
||||
@cp -rp lib/wasi-libc/libc-top-half/musl/src/include build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||
@cp -rp lib/wasi-libc/libc-top-half/musl/src/internal build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||
@cp -rp lib/wasi-libc/libc-top-half/musl/src/math build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||
@cp -rp lib/wasi-libc/libc-top-half/musl/src/string build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||
@cp -rp lib/wasi-libc/libc-top-half/musl/include build/release/tinygo/lib/wasi-libc/libc-top-half/musl
|
||||
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
|
||||
@cp -rp lib/wasi-cli/wit build/release/tinygo/lib/wasi-cli/wit
|
||||
@cp -rp llvm-project/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt-builtins
|
||||
@cp -rp llvm-project/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
|
||||
@cp -rp src build/release/tinygo/src
|
||||
@@ -886,3 +954,21 @@ ifneq ($(RELEASEONLY), 1)
|
||||
release: build/release
|
||||
deb: build/release
|
||||
endif
|
||||
|
||||
.PHONY: tools
|
||||
tools:
|
||||
go generate -C ./internal/tools -tags tools ./
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
go run github.com/mgechev/revive -version
|
||||
# TODO: lint more directories!
|
||||
# revive.toml isn't flexible enough to filter out just one kind of error from a checker, so do it with grep here.
|
||||
# Can't use grep with friendly formatter. Plain output isn't too bad, though.
|
||||
# Use 'grep .' to get rid of stray blank line
|
||||
go run github.com/mgechev/revive -config revive.toml compiler/... src/{os,reflect}/*.go | grep -v "should have comment or be unexported" | grep '.' | awk '{print}; END {exit NR>0}'
|
||||
|
||||
.PHONY: spell
|
||||
spell:
|
||||
# Check for typos in comments. Skip git submodules etc.
|
||||
go run github.com/client9/misspell/cmd/misspell -i 'ackward,devided,extint,inbetween,programmmer,rela' $$( find . -depth 1 -type d | egrep -w -v 'lib|llvm|src/net' )
|
||||
|
||||
@@ -41,7 +41,7 @@ tinygo flash -target arduino examples/blinky1
|
||||
|
||||
TinyGo is very useful for compiling programs both for use in browsers (WASM) as well as for use on servers and other edge devices (WASI).
|
||||
|
||||
TinyGo programs can run in Fastly Compute@Edge (https://developer.fastly.com/learning/compute/go/), Fermyon Spin (https://developer.fermyon.com/spin/go-components), wazero (https://wazero.io/languages/tinygo/) and many other WebAssembly runtimes.
|
||||
TinyGo programs can run in [Fastly Compute](https://www.fastly.com/documentation/guides/compute/go/), [Fermyon Spin](https://developer.fermyon.com/spin/go-components), [wazero](https://wazero.io/languages/tinygo/) and many other WebAssembly runtimes.
|
||||
|
||||
Here is a small TinyGo program for use by a WASI host application:
|
||||
|
||||
@@ -54,14 +54,14 @@ func add(x, y uint32) uint32 {
|
||||
return x + y
|
||||
}
|
||||
|
||||
// main is required for the `wasi` target, even if it isn't used.
|
||||
// main is required for the `wasip1` target, even if it isn't used.
|
||||
func main() {}
|
||||
```
|
||||
|
||||
This compiles the above TinyGo program for use on any WASI runtime:
|
||||
|
||||
```shell
|
||||
tinygo build -o main.wasm -target=wasi main.go
|
||||
tinygo build -o main.wasm -target=wasip1 main.go
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
+16
-6
@@ -78,17 +78,27 @@ func makeArchive(arfile *os.File, objs []string) error {
|
||||
} else if dbg, err := wasm.Parse(objfile); err == nil {
|
||||
for _, s := range dbg.Sections {
|
||||
switch section := s.(type) {
|
||||
case *wasm.SectionImport:
|
||||
for _, ln := range section.Entries {
|
||||
|
||||
if ln.Kind != wasm.ExtKindFunction {
|
||||
// Not a function
|
||||
case *wasm.SectionLinking:
|
||||
for _, symbol := range section.Symbols {
|
||||
if symbol.Flags&wasm.LinkingSymbolFlagUndefined != 0 {
|
||||
// Don't list undefined functions.
|
||||
continue
|
||||
}
|
||||
if symbol.Flags&wasm.LinkingSymbolFlagBindingLocal != 0 {
|
||||
// Don't include local symbols.
|
||||
continue
|
||||
}
|
||||
if symbol.Kind != wasm.LinkingSymbolKindFunction && symbol.Kind != wasm.LinkingSymbolKindData {
|
||||
// Link functions and data symbols.
|
||||
// Some data symbols need to be included, such as
|
||||
// __log_data.
|
||||
continue
|
||||
}
|
||||
// Include in the archive.
|
||||
symbolTable = append(symbolTable, struct {
|
||||
name string
|
||||
fileIndex int
|
||||
}{ln.Field, i})
|
||||
}{symbol.Name, i})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+84
-24
@@ -168,6 +168,13 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
return BuildResult{}, errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?")
|
||||
}
|
||||
libcDependencies = append(libcDependencies, dummyCompileJob(path))
|
||||
case "wasmbuiltins":
|
||||
libcJob, unlock, err := WasmBuiltins.load(config, tmpdir)
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
}
|
||||
defer unlock()
|
||||
libcDependencies = append(libcDependencies, libcJob)
|
||||
case "mingw-w64":
|
||||
_, unlock, err := MinGW.load(config, tmpdir)
|
||||
if err != nil {
|
||||
@@ -197,8 +204,10 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
Scheduler: config.Scheduler(),
|
||||
AutomaticStackSize: config.AutomaticStackSize(),
|
||||
DefaultStackSize: config.StackSize(),
|
||||
MaxStackAlloc: config.MaxStackAlloc(),
|
||||
NeedsStackObjects: config.NeedsStackObjects(),
|
||||
Debug: !config.Options.SkipDWARF, // emit DWARF except when -internal-nodwarf is passed
|
||||
PanicStrategy: config.PanicStrategy(),
|
||||
}
|
||||
|
||||
// Load the target machine, which is the LLVM object that contains all
|
||||
@@ -344,10 +353,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
}
|
||||
packageActionIDJobs[pkg.ImportPath] = packageActionIDJob
|
||||
|
||||
// Build the SSA for the given package.
|
||||
ssaPkg := program.Package(pkg.Pkg)
|
||||
ssaPkg.Build()
|
||||
|
||||
// Now create the job to actually build the package. It will exit early
|
||||
// if the package is already compiled.
|
||||
job := &compileJob{
|
||||
@@ -370,7 +375,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
defer mod.Context().Dispose()
|
||||
defer mod.Dispose()
|
||||
if errs != nil {
|
||||
return newMultiError(errs)
|
||||
return newMultiError(errs, pkg.ImportPath)
|
||||
}
|
||||
if err := llvm.VerifyModule(mod, llvm.PrintMessageAction); err != nil {
|
||||
return errors.New("verification error after compiling package " + pkg.ImportPath)
|
||||
@@ -764,7 +769,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
if sizeLevel >= 2 {
|
||||
// Workaround with roughly the same effect as
|
||||
// https://reviews.llvm.org/D119342.
|
||||
// Can hopefully be removed in LLVM 18.
|
||||
// Can hopefully be removed in LLVM 19.
|
||||
ldflags = append(ldflags,
|
||||
"-mllvm", "--rotation-max-header-size=0")
|
||||
}
|
||||
@@ -807,21 +812,8 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
|
||||
// Run wasm-opt for wasm binaries
|
||||
if arch := strings.Split(config.Triple(), "-")[0]; arch == "wasm32" {
|
||||
var opt string
|
||||
switch config.Options.Opt {
|
||||
case "none", "0":
|
||||
opt = "-O0"
|
||||
case "1":
|
||||
opt = "-O1"
|
||||
case "2":
|
||||
opt = "-O2"
|
||||
case "s":
|
||||
opt = "-Os"
|
||||
case "z":
|
||||
opt = "-Oz"
|
||||
default:
|
||||
return fmt.Errorf("unknown opt level: %q", config.Options.Opt)
|
||||
}
|
||||
optLevel, _, _ := config.OptLevel()
|
||||
opt := "-" + optLevel
|
||||
|
||||
var args []string
|
||||
|
||||
@@ -829,14 +821,26 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
args = append(args, "--asyncify")
|
||||
}
|
||||
|
||||
exeunopt := result.Executable
|
||||
|
||||
if config.Options.Work {
|
||||
// Keep the work direction around => don't overwrite the .wasm binary with the optimized version
|
||||
exeunopt += ".pre-wasm-opt"
|
||||
os.Rename(result.Executable, exeunopt)
|
||||
}
|
||||
|
||||
args = append(args,
|
||||
opt,
|
||||
"-g",
|
||||
result.Executable,
|
||||
exeunopt,
|
||||
"--output", result.Executable,
|
||||
)
|
||||
|
||||
cmd := exec.Command(goenv.Get("WASMOPT"), args...)
|
||||
wasmopt := goenv.Get("WASMOPT")
|
||||
if config.Options.PrintCommands != nil {
|
||||
config.Options.PrintCommands(wasmopt, args...)
|
||||
}
|
||||
cmd := exec.Command(wasmopt, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
@@ -846,6 +850,62 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
}
|
||||
}
|
||||
|
||||
// Run wasm-tools for component-model binaries
|
||||
witPackage := strings.ReplaceAll(config.Target.WITPackage, "{root}", goenv.Get("TINYGOROOT"))
|
||||
if config.Options.WITPackage != "" {
|
||||
witPackage = config.Options.WITPackage
|
||||
}
|
||||
witWorld := config.Target.WITWorld
|
||||
if config.Options.WITWorld != "" {
|
||||
witWorld = config.Options.WITWorld
|
||||
}
|
||||
if witPackage != "" && witWorld != "" {
|
||||
|
||||
// wasm-tools component embed -w wasi:cli/command
|
||||
// $$(tinygo env TINYGOROOT)/lib/wasi-cli/wit/ main.wasm -o embedded.wasm
|
||||
args := []string{
|
||||
"component",
|
||||
"embed",
|
||||
"-w", witWorld,
|
||||
witPackage,
|
||||
result.Executable,
|
||||
"-o", result.Executable,
|
||||
}
|
||||
|
||||
wasmtools := goenv.Get("WASMTOOLS")
|
||||
if config.Options.PrintCommands != nil {
|
||||
config.Options.PrintCommands(wasmtools, args...)
|
||||
}
|
||||
cmd := exec.Command(wasmtools, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("wasm-tools failed: %w", err)
|
||||
}
|
||||
|
||||
// wasm-tools component new embedded.wasm -o component.wasm
|
||||
args = []string{
|
||||
"component",
|
||||
"new",
|
||||
result.Executable,
|
||||
"-o", result.Executable,
|
||||
}
|
||||
|
||||
if config.Options.PrintCommands != nil {
|
||||
config.Options.PrintCommands(wasmtools, args...)
|
||||
}
|
||||
cmd = exec.Command(wasmtools, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("wasm-tools failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Print code size if requested.
|
||||
if config.Options.PrintSizes == "short" || config.Options.PrintSizes == "full" {
|
||||
packagePathMap := make(map[string]string, len(lprogram.Packages))
|
||||
@@ -1070,7 +1130,7 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config, globalValues m
|
||||
// O0/O1/O2/Os/Oz optimization pipeline).
|
||||
errs := transform.Optimize(mod, config)
|
||||
if len(errs) > 0 {
|
||||
return newMultiError(errs)
|
||||
return newMultiError(errs, "")
|
||||
}
|
||||
if err := llvm.VerifyModule(mod, llvm.PrintMessageAction); err != nil {
|
||||
return errors.New("verification failure after LLVM optimization passes")
|
||||
|
||||
@@ -33,8 +33,10 @@ func TestClangAttributes(t *testing.T) {
|
||||
"k210",
|
||||
"nintendoswitch",
|
||||
"riscv-qemu",
|
||||
"wasi",
|
||||
"wasip1",
|
||||
"wasip2",
|
||||
"wasm",
|
||||
"wasm-unknown",
|
||||
}
|
||||
if hasBuiltinTools {
|
||||
// hasBuiltinTools is set when TinyGo is statically linked with LLVM,
|
||||
@@ -55,11 +57,14 @@ func TestClangAttributes(t *testing.T) {
|
||||
{GOOS: "linux", GOARCH: "arm", GOARM: "6"},
|
||||
{GOOS: "linux", GOARCH: "arm", GOARM: "7"},
|
||||
{GOOS: "linux", GOARCH: "arm64"},
|
||||
{GOOS: "linux", GOARCH: "mips"},
|
||||
{GOOS: "linux", GOARCH: "mipsle"},
|
||||
{GOOS: "darwin", GOARCH: "amd64"},
|
||||
{GOOS: "darwin", GOARCH: "arm64"},
|
||||
{GOOS: "windows", GOARCH: "amd64"},
|
||||
{GOOS: "windows", GOARCH: "arm64"},
|
||||
{GOOS: "wasip1", GOARCH: "wasm"},
|
||||
{GOOS: "wasip2", GOARCH: "wasm"},
|
||||
} {
|
||||
name := "GOOS=" + options.GOOS + ",GOARCH=" + options.GOARCH
|
||||
if options.GOARCH == "arm" {
|
||||
|
||||
+5
-7
@@ -8,14 +8,14 @@ import (
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
)
|
||||
|
||||
// These are the GENERIC_SOURCES according to CMakeList.txt.
|
||||
// These are the GENERIC_SOURCES according to CMakeList.txt except for
|
||||
// divmodsi4.c and udivmodsi4.c.
|
||||
var genericBuiltins = []string{
|
||||
"absvdi2.c",
|
||||
"absvsi2.c",
|
||||
"absvti2.c",
|
||||
"adddf3.c",
|
||||
"addsf3.c",
|
||||
"addtf3.c",
|
||||
"addvdi3.c",
|
||||
"addvsi3.c",
|
||||
"addvti3.c",
|
||||
@@ -40,12 +40,12 @@ var genericBuiltins = []string{
|
||||
"divdf3.c",
|
||||
"divdi3.c",
|
||||
"divmoddi4.c",
|
||||
//"divmodsi4.c",
|
||||
"divmodti4.c",
|
||||
"divsc3.c",
|
||||
"divsf3.c",
|
||||
"divsi3.c",
|
||||
"divtc3.c",
|
||||
"divti3.c",
|
||||
"divtf3.c",
|
||||
"extendsfdf2.c",
|
||||
"extendhfsf2.c",
|
||||
"ffsdi2.c",
|
||||
@@ -91,7 +91,6 @@ var genericBuiltins = []string{
|
||||
"mulsc3.c",
|
||||
"mulsf3.c",
|
||||
"multi3.c",
|
||||
"multf3.c",
|
||||
"mulvdi3.c",
|
||||
"mulvsi3.c",
|
||||
"mulvti3.c",
|
||||
@@ -111,13 +110,11 @@ var genericBuiltins = []string{
|
||||
"popcountti2.c",
|
||||
"powidf2.c",
|
||||
"powisf2.c",
|
||||
"powitf2.c",
|
||||
"subdf3.c",
|
||||
"subsf3.c",
|
||||
"subvdi3.c",
|
||||
"subvsi3.c",
|
||||
"subvti3.c",
|
||||
"subtf3.c",
|
||||
"trampoline_setup.c",
|
||||
"truncdfhf2.c",
|
||||
"truncdfsf2.c",
|
||||
@@ -126,6 +123,7 @@ var genericBuiltins = []string{
|
||||
"ucmpti2.c",
|
||||
"udivdi3.c",
|
||||
"udivmoddi4.c",
|
||||
//"udivmodsi4.c",
|
||||
"udivmodti4.c",
|
||||
"udivsi3.c",
|
||||
"udivti3.c",
|
||||
|
||||
+25
-13
@@ -1,5 +1,12 @@
|
||||
//go:build byollvm
|
||||
|
||||
// Source: https://github.com/llvm/llvm-project/blob/main/clang/tools/driver/cc1as_main.cpp
|
||||
// This file needs to be updated each LLVM release.
|
||||
// There are a few small modifications to make, like:
|
||||
// * ExecuteAssembler is made non-static.
|
||||
// * The struct AssemblerImplementation is moved to cc1as.h so it can be
|
||||
// included elsewhere.
|
||||
|
||||
//===-- cc1as.cpp - Clang Assembler --------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
@@ -21,8 +28,8 @@
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "clang/Frontend/Utils.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/MC/MCAsmBackend.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
@@ -46,7 +53,6 @@
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
@@ -55,6 +61,8 @@
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/TargetParser/Host.h"
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <system_error>
|
||||
@@ -74,10 +82,10 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
||||
// Parse the arguments.
|
||||
const OptTable &OptTbl = getDriverOptTable();
|
||||
|
||||
const unsigned IncludedFlagsBitmask = options::CC1AsOption;
|
||||
llvm::opt::Visibility VisibilityMask(options::CC1AsOption);
|
||||
unsigned MissingArgIndex, MissingArgCount;
|
||||
InputArgList Args = OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount,
|
||||
IncludedFlagsBitmask);
|
||||
InputArgList Args =
|
||||
OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount, VisibilityMask);
|
||||
|
||||
// Check for missing argument error.
|
||||
if (MissingArgCount) {
|
||||
@@ -90,7 +98,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
||||
for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
|
||||
auto ArgString = A->getAsString(Args);
|
||||
std::string Nearest;
|
||||
if (OptTbl.findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
|
||||
if (OptTbl.findNearest(ArgString, Nearest, VisibilityMask) > 1)
|
||||
Diags.Report(diag::err_drv_unknown_argument) << ArgString;
|
||||
else
|
||||
Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
|
||||
@@ -151,8 +159,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
||||
|
||||
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
|
||||
auto Split = StringRef(Arg).split('=');
|
||||
Opts.DebugPrefixMap.insert(
|
||||
{std::string(Split.first), std::string(Split.second)});
|
||||
Opts.DebugPrefixMap.emplace_back(Split.first, Split.second);
|
||||
}
|
||||
|
||||
// Frontend Options
|
||||
@@ -225,6 +232,9 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
||||
.Case("default", EmitDwarfUnwindType::Default);
|
||||
}
|
||||
|
||||
Opts.EmitCompactUnwindNonCanonical =
|
||||
Args.hasArg(OPT_femit_compact_unwind_non_canonical);
|
||||
|
||||
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
|
||||
|
||||
return Success;
|
||||
@@ -260,8 +270,8 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
||||
MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
|
||||
|
||||
if (std::error_code EC = Buffer.getError()) {
|
||||
Error = EC.message();
|
||||
return Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
|
||||
return Diags.Report(diag::err_fe_error_reading)
|
||||
<< Opts.InputFile << EC.message();
|
||||
}
|
||||
|
||||
SourceMgr SrcMgr;
|
||||
@@ -278,6 +288,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
||||
|
||||
MCTargetOptions MCOptions;
|
||||
MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
|
||||
MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical;
|
||||
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
|
||||
|
||||
std::unique_ptr<MCAsmInfo> MAI(
|
||||
@@ -510,9 +521,10 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
|
||||
if (Asm.ShowHelp) {
|
||||
getDriverOptTable().printHelp(
|
||||
llvm::outs(), "clang -cc1as [options] file...",
|
||||
"Clang Integrated Assembler",
|
||||
/*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,
|
||||
/*ShowAllAliases=*/false);
|
||||
"Clang Integrated Assembler", /*ShowHidden=*/false,
|
||||
/*ShowAllAliases=*/false,
|
||||
llvm::opt::Visibility(driver::options::CC1AsOption));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+9
-1
@@ -1,3 +1,6 @@
|
||||
// Source: https://github.com/llvm/llvm-project/blob/main/clang/tools/driver/cc1as_main.cpp
|
||||
// See cc1as.cpp for details.
|
||||
|
||||
//===-- cc1as.h - Clang Assembler ----------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
@@ -44,7 +47,7 @@ struct AssemblerInvocation {
|
||||
std::string DwarfDebugFlags;
|
||||
std::string DwarfDebugProducer;
|
||||
std::string DebugCompilationDir;
|
||||
std::map<const std::string, const std::string> DebugPrefixMap;
|
||||
llvm::SmallVector<std::pair<std::string, std::string>, 0> DebugPrefixMap;
|
||||
llvm::DebugCompressionType CompressDebugSections =
|
||||
llvm::DebugCompressionType::None;
|
||||
std::string MainFileName;
|
||||
@@ -89,6 +92,10 @@ struct AssemblerInvocation {
|
||||
/// Whether to emit DWARF unwind info.
|
||||
EmitDwarfUnwindType EmitDwarfUnwind;
|
||||
|
||||
// Whether to emit compact-unwind for non-canonical entries.
|
||||
// Note: maybe overriden by other constraints.
|
||||
unsigned EmitCompactUnwindNonCanonical : 1;
|
||||
|
||||
/// The name of the relocation model to use.
|
||||
std::string RelocationModel;
|
||||
|
||||
@@ -128,6 +135,7 @@ public:
|
||||
DwarfVersion = 0;
|
||||
EmbedBitcode = 0;
|
||||
EmitDwarfUnwind = EmitDwarfUnwindType::Default;
|
||||
EmitCompactUnwindNonCanonical = false;
|
||||
}
|
||||
|
||||
static bool CreateFromArgs(AssemblerInvocation &Res,
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
#include <clang/FrontendTool/Utils.h>
|
||||
#include <llvm/ADT/IntrusiveRefCntPtr.h>
|
||||
#include <llvm/Option/Option.h>
|
||||
#include <llvm/Support/Host.h>
|
||||
#include <llvm/TargetParser/Host.h>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace clang;
|
||||
|
||||
+2
-2
@@ -27,10 +27,10 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if major != 1 || minor < 18 || minor > 21 {
|
||||
if major != 1 || minor < 19 || minor > 22 {
|
||||
// Note: when this gets updated, also update the Go compatibility matrix:
|
||||
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
||||
return nil, fmt.Errorf("requires go version 1.18 through 1.21, got go%d.%d", major, minor)
|
||||
return nil, fmt.Errorf("requires go version 1.19 through 1.22, got go%d.%d", major, minor)
|
||||
}
|
||||
|
||||
return &compileopts.Config{
|
||||
|
||||
+5
-3
@@ -3,7 +3,8 @@ package builder
|
||||
// MultiError is a list of multiple errors (actually: diagnostics) returned
|
||||
// during LLVM IR generation.
|
||||
type MultiError struct {
|
||||
Errs []error
|
||||
ImportPath string
|
||||
Errs []error
|
||||
}
|
||||
|
||||
func (e *MultiError) Error() string {
|
||||
@@ -15,14 +16,15 @@ func (e *MultiError) Error() string {
|
||||
// newMultiError returns a *MultiError if there is more than one error, or
|
||||
// returns that error directly when there is only one. Passing an empty slice
|
||||
// will lead to a panic.
|
||||
func newMultiError(errs []error) error {
|
||||
// The importPath may be passed if this error is for a single package.
|
||||
func newMultiError(errs []error, importPath string) error {
|
||||
switch len(errs) {
|
||||
case 0:
|
||||
panic("attempted to create empty MultiError")
|
||||
case 1:
|
||||
return errs[0]
|
||||
default:
|
||||
return &MultiError{errs}
|
||||
return &MultiError{importPath, errs}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,6 +182,9 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
if strings.HasPrefix(target, "riscv64-") {
|
||||
args = append(args, "-march=rv64gc")
|
||||
}
|
||||
if strings.HasPrefix(target, "mips") {
|
||||
args = append(args, "-fno-pic")
|
||||
}
|
||||
|
||||
var once sync.Once
|
||||
|
||||
|
||||
+9
-20
@@ -5,7 +5,11 @@
|
||||
#include <lld/Common/Driver.h>
|
||||
#include <llvm/Support/Parallel.h>
|
||||
|
||||
extern "C" {
|
||||
LLD_HAS_DRIVER(coff)
|
||||
LLD_HAS_DRIVER(elf)
|
||||
LLD_HAS_DRIVER(mingw)
|
||||
LLD_HAS_DRIVER(macho)
|
||||
LLD_HAS_DRIVER(wasm)
|
||||
|
||||
static void configure() {
|
||||
#if _WIN64
|
||||
@@ -16,28 +20,13 @@ static void configure() {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool tinygo_link_elf(int argc, char **argv) {
|
||||
configure();
|
||||
std::vector<const char*> args(argv, argv + argc);
|
||||
return lld::elf::link(args, llvm::outs(), llvm::errs(), false, false);
|
||||
}
|
||||
extern "C" {
|
||||
|
||||
bool tinygo_link_macho(int argc, char **argv) {
|
||||
bool tinygo_link(int argc, char **argv) {
|
||||
configure();
|
||||
std::vector<const char*> args(argv, argv + argc);
|
||||
return lld::macho::link(args, llvm::outs(), llvm::errs(), false, false);
|
||||
}
|
||||
|
||||
bool tinygo_link_mingw(int argc, char **argv) {
|
||||
configure();
|
||||
std::vector<const char*> args(argv, argv + argc);
|
||||
return lld::mingw::link(args, llvm::outs(), llvm::errs(), false, false);
|
||||
}
|
||||
|
||||
bool tinygo_link_wasm(int argc, char **argv) {
|
||||
configure();
|
||||
std::vector<const char*> args(argv, argv + argc);
|
||||
return lld::wasm::link(args, llvm::outs(), llvm::errs(), false, false);
|
||||
lld::Result r = lld::lldMain(args, llvm::outs(), llvm::errs(), LLD_ALL_DRIVERS);
|
||||
return !r.retCode;
|
||||
}
|
||||
|
||||
} // external "C"
|
||||
|
||||
@@ -119,6 +119,7 @@ var Musl = Library{
|
||||
"internal/syscall_ret.c",
|
||||
"internal/vdso.c",
|
||||
"legacy/*.c",
|
||||
"linux/*.c",
|
||||
"malloc/*.c",
|
||||
"malloc/mallocng/*.c",
|
||||
"mman/*.c",
|
||||
|
||||
@@ -337,6 +337,12 @@ var picolibcSourcesLarge = []string{
|
||||
"libm/common/math_err_may_uflow.c",
|
||||
"libm/common/math_err_check_uflow.c",
|
||||
"libm/common/math_err_check_oflow.c",
|
||||
"libm/common/math_errf_divzerof.c",
|
||||
"libm/common/math_errf_invalidf.c",
|
||||
"libm/common/math_errf_may_uflowf.c",
|
||||
"libm/common/math_errf_oflowf.c",
|
||||
"libm/common/math_errf_uflowf.c",
|
||||
"libm/common/math_errf_with_errnof.c",
|
||||
"libm/common/math_inexact.c",
|
||||
"libm/common/math_inexactf.c",
|
||||
"libm/common/log.c",
|
||||
|
||||
@@ -42,8 +42,8 @@ func TestBinarySize(t *testing.T) {
|
||||
tests := []sizeTest{
|
||||
// microcontrollers
|
||||
{"hifive1b", "examples/echo", 4484, 280, 0, 2252},
|
||||
{"microbit", "examples/serial", 2724, 388, 8, 2256},
|
||||
{"wioterminal", "examples/pininterrupt", 6000, 1484, 116, 6816},
|
||||
{"microbit", "examples/serial", 2732, 388, 8, 2256},
|
||||
{"wioterminal", "examples/pininterrupt", 6016, 1484, 116, 6816},
|
||||
|
||||
// TODO: also check wasm. Right now this is difficult, because
|
||||
// wasm binaries are run through wasm-opt and therefore the
|
||||
|
||||
@@ -12,10 +12,7 @@ import (
|
||||
#include <stdbool.h>
|
||||
#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);
|
||||
bool tinygo_link(int argc, char **argv);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
@@ -26,16 +23,7 @@ const hasBuiltinTools = true
|
||||
// This version actually runs the tools because TinyGo was compiled while
|
||||
// linking statically with LLVM (with the byollvm build tag).
|
||||
func RunTool(tool string, args ...string) error {
|
||||
linker := "elf"
|
||||
if tool == "ld.lld" && len(args) >= 2 {
|
||||
if args[0] == "-m" && (args[1] == "i386pep" || args[1] == "arm64pe") {
|
||||
linker = "mingw"
|
||||
} else if args[0] == "-flavor" {
|
||||
linker = args[1]
|
||||
args = args[2:]
|
||||
}
|
||||
}
|
||||
args = append([]string{"tinygo:" + tool}, args...)
|
||||
args = append([]string{tool}, args...)
|
||||
|
||||
var cflag *C.char
|
||||
buf := C.calloc(C.size_t(len(args)), C.size_t(unsafe.Sizeof(cflag)))
|
||||
@@ -51,19 +39,8 @@ func RunTool(tool string, args ...string) error {
|
||||
switch tool {
|
||||
case "clang":
|
||||
ok = C.tinygo_clang_driver(C.int(len(args)), (**C.char)(buf))
|
||||
case "ld.lld":
|
||||
switch linker {
|
||||
case "darwin":
|
||||
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":
|
||||
ok = C.tinygo_link_mingw(C.int(len(args)), (**C.char)(buf))
|
||||
default:
|
||||
return errors.New("unknown linker: " + linker)
|
||||
}
|
||||
case "wasm-ld":
|
||||
ok = C.tinygo_link_wasm(C.int(len(args)), (**C.char)(buf))
|
||||
case "ld.lld", "wasm-ld":
|
||||
ok = C.tinygo_link(C.int(len(args)), (**C.char)(buf))
|
||||
default:
|
||||
return errors.New("unknown tool: " + tool)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
)
|
||||
|
||||
var WasmBuiltins = Library{
|
||||
name: "wasmbuiltins",
|
||||
makeHeaders: func(target, includeDir string) error {
|
||||
if err := os.Mkdir(includeDir+"/bits", 0o777); err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.Create(includeDir + "/bits/alltypes.h")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := f.Write([]byte(wasmAllTypes)); err != nil {
|
||||
return err
|
||||
}
|
||||
return f.Close()
|
||||
},
|
||||
cflags: func(target, headerPath string) []string {
|
||||
libcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc")
|
||||
return []string{
|
||||
"-Werror",
|
||||
"-Wall",
|
||||
"-std=gnu11",
|
||||
"-nostdlibinc",
|
||||
"-isystem", libcDir + "/libc-top-half/musl/arch/wasm32",
|
||||
"-isystem", libcDir + "/libc-top-half/musl/arch/generic",
|
||||
"-isystem", libcDir + "/libc-top-half/musl/src/internal",
|
||||
"-isystem", libcDir + "/libc-top-half/musl/src/include",
|
||||
"-isystem", libcDir + "/libc-top-half/musl/include",
|
||||
"-isystem", libcDir + "/libc-bottom-half/headers/public",
|
||||
"-I" + headerPath,
|
||||
}
|
||||
},
|
||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc") },
|
||||
librarySources: func(target string) ([]string, error) {
|
||||
return []string{
|
||||
// memory builtins needed for llvm.memcpy.*, llvm.memmove.*, and
|
||||
// llvm.memset.* LLVM intrinsics.
|
||||
"libc-top-half/musl/src/string/memcpy.c",
|
||||
"libc-top-half/musl/src/string/memmove.c",
|
||||
"libc-top-half/musl/src/string/memset.c",
|
||||
|
||||
// exp, exp2, and log are needed for LLVM math builtin functions
|
||||
// like llvm.exp.*.
|
||||
"libc-top-half/musl/src/math/__math_divzero.c",
|
||||
"libc-top-half/musl/src/math/__math_invalid.c",
|
||||
"libc-top-half/musl/src/math/__math_oflow.c",
|
||||
"libc-top-half/musl/src/math/__math_uflow.c",
|
||||
"libc-top-half/musl/src/math/__math_xflow.c",
|
||||
"libc-top-half/musl/src/math/exp.c",
|
||||
"libc-top-half/musl/src/math/exp_data.c",
|
||||
"libc-top-half/musl/src/math/exp2.c",
|
||||
"libc-top-half/musl/src/math/log.c",
|
||||
"libc-top-half/musl/src/math/log_data.c",
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
|
||||
// alltypes.h for wasm-libc, using the types as defined inside Clang.
|
||||
const wasmAllTypes = `
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
typedef __INT8_TYPE__ int8_t;
|
||||
typedef __INT16_TYPE__ int16_t;
|
||||
typedef __INT32_TYPE__ int32_t;
|
||||
typedef __INT64_TYPE__ int64_t;
|
||||
typedef __UINT8_TYPE__ uint8_t;
|
||||
typedef __UINT16_TYPE__ uint16_t;
|
||||
typedef __UINT32_TYPE__ uint32_t;
|
||||
typedef __UINT64_TYPE__ uint64_t;
|
||||
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||
|
||||
// This type is used internally in wasi-libc.
|
||||
typedef double double_t;
|
||||
`
|
||||
+10
-2
@@ -25,9 +25,15 @@ import (
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
)
|
||||
|
||||
// Function that's only defined in Go 1.22.
|
||||
var setASTFileFields = func(f *ast.File, start, end token.Pos) {
|
||||
}
|
||||
|
||||
// cgoPackage holds all CGo-related information of a package.
|
||||
type cgoPackage struct {
|
||||
generated *ast.File
|
||||
packageName string
|
||||
cgoFiles []*ast.File
|
||||
generatedPos token.Pos
|
||||
errors []error
|
||||
currentDir string // current working directory
|
||||
@@ -165,8 +171,9 @@ 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, importPath string, fset *token.FileSet, cflags []string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
|
||||
func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cflags []string) ([]*ast.File, []string, []string, []string, map[string][]byte, []error) {
|
||||
p := &cgoPackage{
|
||||
packageName: files[0].Name.Name,
|
||||
currentDir: dir,
|
||||
importPath: importPath,
|
||||
fset: fset,
|
||||
@@ -202,6 +209,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
||||
// This is always a bug in the cgo package.
|
||||
panic("unexpected error: " + err.Error())
|
||||
}
|
||||
p.cgoFiles = append(p.cgoFiles, p.generated)
|
||||
// If the Comments field is not set to nil, the go/format package will get
|
||||
// confused about where comments should go.
|
||||
p.generated.Comments = nil
|
||||
@@ -332,7 +340,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
||||
// Print the newly generated in-memory AST, for debugging.
|
||||
//ast.Print(fset, p.generated)
|
||||
|
||||
return p.generated, p.cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
|
||||
return p.cgoFiles, p.cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
|
||||
}
|
||||
|
||||
func (p *cgoPackage) newCGoFile(file *ast.File, index int) *cgoFile {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
//go:build go1.22
|
||||
|
||||
package cgo
|
||||
|
||||
// Code specifically for Go 1.22.
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
)
|
||||
|
||||
func init() {
|
||||
setASTFileFields = func(f *ast.File, start, end token.Pos) {
|
||||
f.FileStart = start
|
||||
f.FileEnd = end
|
||||
}
|
||||
}
|
||||
+12
-5
@@ -7,6 +7,7 @@ import (
|
||||
"go/ast"
|
||||
"go/format"
|
||||
"go/parser"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"os"
|
||||
@@ -55,7 +56,7 @@ func TestCGo(t *testing.T) {
|
||||
}
|
||||
|
||||
// Process the AST with CGo.
|
||||
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", "main", fset, cflags)
|
||||
cgoFiles, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", "main", fset, cflags)
|
||||
|
||||
// Check the AST for type errors.
|
||||
var typecheckErrors []error
|
||||
@@ -66,7 +67,7 @@ func TestCGo(t *testing.T) {
|
||||
Importer: simpleImporter{},
|
||||
Sizes: types.SizesFor("gccgo", "arm"),
|
||||
}
|
||||
_, err = config.Check("", fset, []*ast.File{f, cgoAST}, nil)
|
||||
_, err = config.Check("", fset, append([]*ast.File{f}, cgoFiles...), nil)
|
||||
if err != nil && len(typecheckErrors) == 0 {
|
||||
// Only report errors when no type errors are found (an
|
||||
// unexpected condition).
|
||||
@@ -91,7 +92,7 @@ func TestCGo(t *testing.T) {
|
||||
}
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
err = format.Node(buf, fset, cgoAST)
|
||||
err = format.Node(buf, fset, cgoFiles[0])
|
||||
if err != nil {
|
||||
t.Errorf("could not write out CGo AST: %v", err)
|
||||
}
|
||||
@@ -216,10 +217,16 @@ func (i simpleImporter) Import(path string) (*types.Package, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// formatDiagnostics formats the error message to be an indented comment. It
|
||||
// formatDiagnostic formats the error message to be an indented comment. It
|
||||
// also fixes Windows path name issues (backward slashes).
|
||||
func formatDiagnostic(err error) string {
|
||||
msg := err.Error()
|
||||
var msg string
|
||||
switch err := err.(type) {
|
||||
case scanner.Error:
|
||||
msg = err.Pos.String() + ": " + err.Msg
|
||||
default:
|
||||
msg = err.Error()
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
// Fix Windows path slashes.
|
||||
msg = strings.ReplaceAll(msg, "testdata\\", "testdata/")
|
||||
|
||||
+18
-4
@@ -17,6 +17,8 @@ var (
|
||||
token.OR: precedenceOr,
|
||||
token.XOR: precedenceXor,
|
||||
token.AND: precedenceAnd,
|
||||
token.SHL: precedenceShift,
|
||||
token.SHR: precedenceShift,
|
||||
token.ADD: precedenceAdd,
|
||||
token.SUB: precedenceAdd,
|
||||
token.MUL: precedenceMul,
|
||||
@@ -25,11 +27,13 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// See: https://en.cppreference.com/w/c/language/operator_precedence
|
||||
const (
|
||||
precedenceLowest = iota + 1
|
||||
precedenceOr
|
||||
precedenceXor
|
||||
precedenceAnd
|
||||
precedenceShift
|
||||
precedenceAdd
|
||||
precedenceMul
|
||||
precedencePrefix
|
||||
@@ -82,7 +86,7 @@ func parseConstExpr(t *tokenizer, precedence int) (ast.Expr, *scanner.Error) {
|
||||
|
||||
for t.peekToken != token.EOF && precedence < precedences[t.peekToken] {
|
||||
switch t.peekToken {
|
||||
case token.OR, token.XOR, token.AND, token.ADD, token.SUB, token.MUL, token.QUO, token.REM:
|
||||
case token.OR, token.XOR, token.AND, token.SHL, token.SHR, token.ADD, token.SUB, token.MUL, token.QUO, token.REM:
|
||||
t.Next()
|
||||
leftExpr, err = parseBinaryExpr(t, leftExpr)
|
||||
}
|
||||
@@ -191,7 +195,9 @@ func (t *tokenizer) Next() {
|
||||
t.curValue = t.peekValue
|
||||
|
||||
// Parse the next peek token.
|
||||
t.peekPos += token.Pos(len(t.curValue))
|
||||
if t.peekPos != token.NoPos {
|
||||
t.peekPos += token.Pos(len(t.curValue))
|
||||
}
|
||||
for {
|
||||
if len(t.buf) == 0 {
|
||||
t.peekToken = token.EOF
|
||||
@@ -203,15 +209,23 @@ func (t *tokenizer) Next() {
|
||||
// Skip whitespace.
|
||||
// Based on this source, not sure whether it represents C whitespace:
|
||||
// https://en.cppreference.com/w/cpp/string/byte/isspace
|
||||
t.peekPos++
|
||||
if t.peekPos != token.NoPos {
|
||||
t.peekPos++
|
||||
}
|
||||
t.buf = t.buf[1:]
|
||||
case len(t.buf) >= 2 && (string(t.buf[:2]) == "||" || string(t.buf[:2]) == "&&"):
|
||||
case len(t.buf) >= 2 && (string(t.buf[:2]) == "||" || string(t.buf[:2]) == "&&" || string(t.buf[:2]) == "<<" || string(t.buf[:2]) == ">>"):
|
||||
// Two-character tokens.
|
||||
switch c {
|
||||
case '&':
|
||||
t.peekToken = token.LAND
|
||||
case '|':
|
||||
t.peekToken = token.LOR
|
||||
case '<':
|
||||
t.peekToken = token.SHL
|
||||
case '>':
|
||||
t.peekToken = token.SHR
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
t.peekValue = t.buf[:2]
|
||||
t.buf = t.buf[2:]
|
||||
|
||||
@@ -40,6 +40,10 @@ func TestParseConst(t *testing.T) {
|
||||
{`5&5`, `5 & 5`},
|
||||
{`5|5`, `5 | 5`},
|
||||
{`5^5`, `5 ^ 5`},
|
||||
{`5<<5`, `5 << 5`},
|
||||
{`5>>5`, `5 >> 5`},
|
||||
{`5>>5 + 3`, `5 >> (5 + 3)`},
|
||||
{`5>>5 ^ 3`, `5>>5 ^ 3`},
|
||||
{`5||5`, `error: 1:2: unexpected token ||, expected end of expression`}, // logical binops aren't supported yet
|
||||
{`(5/5)`, `(5 / 5)`},
|
||||
{`1 - 2`, `1 - 2`},
|
||||
|
||||
+43
-39
@@ -4,6 +4,7 @@ package cgo
|
||||
// modification. It does not touch the AST itself.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
@@ -369,42 +370,45 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
gen.Specs = append(gen.Specs, valueSpec)
|
||||
return gen, nil
|
||||
case C.CXCursor_MacroDefinition:
|
||||
// Extract tokens from the Clang tokenizer.
|
||||
// See: https://stackoverflow.com/a/19074846/559350
|
||||
sourceRange := C.tinygo_clang_getCursorExtent(c)
|
||||
start := C.clang_getRangeStart(sourceRange)
|
||||
end := C.clang_getRangeEnd(sourceRange)
|
||||
var file, endFile C.CXFile
|
||||
var startOffset, endOffset C.unsigned
|
||||
C.clang_getExpansionLocation(start, &file, nil, nil, &startOffset)
|
||||
if file == nil {
|
||||
f.addError(pos, "internal error: could not find file where macro is defined")
|
||||
return nil, nil
|
||||
}
|
||||
C.clang_getExpansionLocation(end, &endFile, nil, nil, &endOffset)
|
||||
if file != endFile {
|
||||
f.addError(pos, "internal error: expected start and end location of a macro to be in the same file")
|
||||
return nil, nil
|
||||
}
|
||||
if startOffset > endOffset {
|
||||
f.addError(pos, "internal error: start offset of macro is after end offset")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// read file contents and extract the relevant byte range
|
||||
tu := C.tinygo_clang_Cursor_getTranslationUnit(c)
|
||||
var size C.size_t
|
||||
sourcePtr := C.clang_getFileContents(tu, file, &size)
|
||||
if endOffset >= C.uint(size) {
|
||||
f.addError(pos, "internal error: end offset of macro lies after end of file")
|
||||
return nil, nil
|
||||
var rawTokens *C.CXToken
|
||||
var numTokens C.unsigned
|
||||
C.clang_tokenize(tu, sourceRange, &rawTokens, &numTokens)
|
||||
tokens := unsafe.Slice(rawTokens, numTokens)
|
||||
// Convert this range of tokens back to source text.
|
||||
// Ugly, but it works well enough.
|
||||
sourceBuf := &bytes.Buffer{}
|
||||
var startOffset int
|
||||
for i, token := range tokens {
|
||||
spelling := getString(C.clang_getTokenSpelling(tu, token))
|
||||
location := C.clang_getTokenLocation(tu, token)
|
||||
var tokenOffset C.unsigned
|
||||
C.clang_getExpansionLocation(location, nil, nil, nil, &tokenOffset)
|
||||
if i == 0 {
|
||||
// The first token is the macro name itself.
|
||||
// Skip it (after using its location).
|
||||
startOffset = int(tokenOffset) + len(name)
|
||||
} else {
|
||||
// Later tokens are the macro contents.
|
||||
for int(tokenOffset) > (startOffset + sourceBuf.Len()) {
|
||||
// Pad the source text with whitespace (that must have been
|
||||
// present in the original source as well).
|
||||
sourceBuf.WriteByte(' ')
|
||||
}
|
||||
sourceBuf.WriteString(spelling)
|
||||
}
|
||||
}
|
||||
source := string(((*[1 << 28]byte)(unsafe.Pointer(sourcePtr)))[startOffset:endOffset:endOffset])
|
||||
if !strings.HasPrefix(source, name) {
|
||||
f.addError(pos, fmt.Sprintf("internal error: expected macro value to start with %#v, got %#v", name, source))
|
||||
return nil, nil
|
||||
}
|
||||
value := source[len(name):]
|
||||
C.clang_disposeTokens(tu, rawTokens, numTokens)
|
||||
value := sourceBuf.String()
|
||||
// Try to convert this #define into a Go constant expression.
|
||||
expr, scannerError := parseConst(pos+token.Pos(len(name)), f.fset, value)
|
||||
tokenPos := token.NoPos
|
||||
if pos != token.NoPos {
|
||||
tokenPos = pos + token.Pos(len(name))
|
||||
}
|
||||
expr, scannerError := parseConst(tokenPos, f.fset, value)
|
||||
if scannerError != nil {
|
||||
f.errors = append(f.errors, *scannerError)
|
||||
return nil, nil
|
||||
@@ -589,6 +593,13 @@ func (p *cgoPackage) getClangLocationPosition(location C.CXSourceLocation, tu C.
|
||||
f := p.fset.AddFile(filename, -1, int(size))
|
||||
f.SetLines(lines)
|
||||
p.tokenFiles[filename] = f
|
||||
// Add dummy file AST, to satisfy the type checker.
|
||||
astFile := &ast.File{
|
||||
Package: f.Pos(0),
|
||||
Name: ast.NewIdent(p.packageName),
|
||||
}
|
||||
setASTFileFields(astFile, f.Pos(0), f.Pos(int(size)))
|
||||
p.cgoFiles = append(p.cgoFiles, astFile)
|
||||
}
|
||||
positionFile := p.tokenFiles[filename]
|
||||
|
||||
@@ -635,13 +646,6 @@ func (p *cgoPackage) addErrorAfter(pos token.Pos, after, msg string) {
|
||||
|
||||
// addErrorAt is a utility function to add an error to the list of errors.
|
||||
func (p *cgoPackage) addErrorAt(position token.Position, msg string) {
|
||||
if filepath.IsAbs(position.Filename) {
|
||||
// Relative paths for readability, like other Go parser errors.
|
||||
relpath, err := filepath.Rel(p.currentDir, position.Filename)
|
||||
if err == nil {
|
||||
position.Filename = relpath
|
||||
}
|
||||
}
|
||||
p.errors = append(p.errors, scanner.Error{
|
||||
Pos: position,
|
||||
Msg: msg,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !byollvm && !llvm15 && !llvm17
|
||||
//go:build !byollvm && llvm16
|
||||
|
||||
package cgo
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
//go:build !byollvm && !llvm15 && !llvm16 && !llvm17
|
||||
|
||||
package cgo
|
||||
|
||||
/*
|
||||
#cgo linux CFLAGS: -I/usr/include/llvm-18 -I/usr/include/llvm-c-18 -I/usr/lib/llvm-18/include
|
||||
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@18/include
|
||||
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@18/include
|
||||
#cgo freebsd CFLAGS: -I/usr/local/llvm18/include
|
||||
#cgo linux LDFLAGS: -L/usr/lib/llvm-18/lib -lclang
|
||||
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@18/lib -lclang
|
||||
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@18/lib -lclang
|
||||
#cgo freebsd LDFLAGS: -L/usr/local/llvm18/lib -lclang
|
||||
*/
|
||||
import "C"
|
||||
Vendored
+13
@@ -13,10 +13,14 @@ typedef someType noType; // undefined type
|
||||
#define SOME_CONST_1 5) // invalid const syntax
|
||||
#define SOME_CONST_2 6) // const not used (so no error)
|
||||
#define SOME_CONST_3 1234 // const too large for byte
|
||||
#define SOME_CONST_b 3 ) // const with lots of weird whitespace (to test error locations)
|
||||
# define SOME_CONST_startspace 3)
|
||||
*/
|
||||
//
|
||||
//
|
||||
// #define SOME_CONST_4 8) // after some empty lines
|
||||
// #cgo CFLAGS: -DSOME_PARAM_CONST_invalid=3/+3
|
||||
// #cgo CFLAGS: -DSOME_PARAM_CONST_valid=3+4
|
||||
import "C"
|
||||
|
||||
// #warning another warning
|
||||
@@ -24,6 +28,7 @@ import "C"
|
||||
|
||||
// Make sure that errors for the following lines won't change with future
|
||||
// additions to the CGo preamble.
|
||||
//
|
||||
//line errors.go:100
|
||||
var (
|
||||
// constant too large
|
||||
@@ -38,4 +43,12 @@ var (
|
||||
_ byte = C.SOME_CONST_3
|
||||
|
||||
_ = C.SOME_CONST_4
|
||||
|
||||
_ = C.SOME_CONST_b
|
||||
|
||||
_ = C.SOME_CONST_startspace
|
||||
|
||||
// constants passed by a command line parameter
|
||||
_ = C.SOME_PARAM_CONST_invalid
|
||||
_ = C.SOME_PARAM_CONST_valid
|
||||
)
|
||||
|
||||
Vendored
+9
-2
@@ -1,9 +1,12 @@
|
||||
// CGo errors:
|
||||
// testdata/errors.go:4:2: warning: some warning
|
||||
// testdata/errors.go:11:9: error: unknown type name 'someType'
|
||||
// testdata/errors.go:22:5: warning: another warning
|
||||
// testdata/errors.go:26:5: warning: another warning
|
||||
// testdata/errors.go:13:23: unexpected token ), expected end of expression
|
||||
// testdata/errors.go:19:26: unexpected token ), expected end of expression
|
||||
// testdata/errors.go:21:26: unexpected token ), expected end of expression
|
||||
// testdata/errors.go:16:33: unexpected token ), expected end of expression
|
||||
// testdata/errors.go:17:34: unexpected token ), expected end of expression
|
||||
// -: unexpected token INT, expected end of expression
|
||||
|
||||
// Type checking errors after CGo processing:
|
||||
// testdata/errors.go:102: cannot use 2 << 10 (untyped int constant 2048) as C.char value in variable declaration (overflows)
|
||||
@@ -11,6 +14,9 @@
|
||||
// testdata/errors.go:108: undefined: C.SOME_CONST_1
|
||||
// testdata/errors.go:110: cannot use C.SOME_CONST_3 (untyped int constant 1234) as byte value in variable declaration (overflows)
|
||||
// testdata/errors.go:112: undefined: C.SOME_CONST_4
|
||||
// testdata/errors.go:114: undefined: C.SOME_CONST_b
|
||||
// testdata/errors.go:116: undefined: C.SOME_CONST_startspace
|
||||
// testdata/errors.go:119: undefined: C.SOME_PARAM_CONST_invalid
|
||||
|
||||
package main
|
||||
|
||||
@@ -58,3 +64,4 @@ type C.struct_point_t struct {
|
||||
type C.point_t = C.struct_point_t
|
||||
|
||||
const C.SOME_CONST_3 = 1234
|
||||
const C.SOME_PARAM_CONST_valid = 3 + 4
|
||||
|
||||
+28
-16
@@ -74,7 +74,13 @@ func (c *Config) GOARM() string {
|
||||
|
||||
// BuildTags returns the complete list of build tags used during this build.
|
||||
func (c *Config) BuildTags() []string {
|
||||
tags := append(c.Target.BuildTags, []string{"tinygo", "math_big_pure_go", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...)
|
||||
tags := append([]string(nil), c.Target.BuildTags...) // copy slice (avoid a race)
|
||||
tags = append(tags, []string{
|
||||
"tinygo", // that's the compiler
|
||||
"purego", // to get various crypto packages to work
|
||||
"math_big_pure_go", // to get math/big to work
|
||||
"gc." + c.GC(), "scheduler." + c.Scheduler(), // used inside the runtime package
|
||||
"serial." + c.Serial()}...) // used inside the machine package
|
||||
for i := 1; i <= c.GoMinorVersion; i++ {
|
||||
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
||||
}
|
||||
@@ -82,12 +88,6 @@ func (c *Config) BuildTags() []string {
|
||||
return tags
|
||||
}
|
||||
|
||||
// CgoEnabled returns true if (and only if) CGo is enabled. It is true by
|
||||
// default and false if CGO_ENABLED is set to "0".
|
||||
func (c *Config) CgoEnabled() bool {
|
||||
return goenv.Get("CGO_ENABLED") == "1"
|
||||
}
|
||||
|
||||
// GC returns the garbage collection strategy in use on this platform. Valid
|
||||
// values are "none", "leaking", "conservative" and "precise".
|
||||
func (c *Config) GC() string {
|
||||
@@ -189,6 +189,15 @@ func (c *Config) StackSize() uint64 {
|
||||
return c.Target.DefaultStackSize
|
||||
}
|
||||
|
||||
// MaxStackAlloc returns the size of the maximum allocation to put on the stack vs heap.
|
||||
func (c *Config) MaxStackAlloc() uint64 {
|
||||
if c.StackSize() > 32*1024 {
|
||||
return 1024
|
||||
}
|
||||
|
||||
return 256
|
||||
}
|
||||
|
||||
// RP2040BootPatch returns whether the RP2040 boot patch should be applied that
|
||||
// calculates and patches in the checksum for the 2nd stage bootloader.
|
||||
func (c *Config) RP2040BootPatch() bool {
|
||||
@@ -203,7 +212,10 @@ func (c *Config) RP2040BootPatch() bool {
|
||||
func MuslArchitecture(triple string) string {
|
||||
arch := strings.Split(triple, "-")[0]
|
||||
if strings.HasPrefix(arch, "arm") || strings.HasPrefix(arch, "thumb") {
|
||||
arch = "arm"
|
||||
return "arm"
|
||||
}
|
||||
if arch == "mipsel" {
|
||||
return "mips"
|
||||
}
|
||||
return arch
|
||||
}
|
||||
@@ -272,10 +284,6 @@ func (c *Config) CFlags(libclang bool) []string {
|
||||
cflags = append(cflags,
|
||||
"-resource-dir="+resourceDir,
|
||||
)
|
||||
if strings.HasPrefix(c.Triple(), "xtensa") {
|
||||
// workaround needed in LLVM 16, see: https://github.com/espressif/llvm-project/issues/83
|
||||
cflags = append(cflags, "-isystem", filepath.Join(resourceDir, "include"))
|
||||
}
|
||||
}
|
||||
switch c.Target.Libc {
|
||||
case "darwin-libSystem":
|
||||
@@ -306,7 +314,11 @@ func (c *Config) CFlags(libclang bool) []string {
|
||||
)
|
||||
case "wasi-libc":
|
||||
root := goenv.Get("TINYGOROOT")
|
||||
cflags = append(cflags, "--sysroot="+root+"/lib/wasi-libc/sysroot")
|
||||
cflags = append(cflags,
|
||||
"-nostdlibinc",
|
||||
"-isystem", root+"/lib/wasi-libc/sysroot/include")
|
||||
case "wasmbuiltins":
|
||||
// nothing to add (library is purely for builtins)
|
||||
case "mingw-w64":
|
||||
root := goenv.Get("TINYGOROOT")
|
||||
path, _ := c.LibcPath("mingw-w64")
|
||||
@@ -471,9 +483,6 @@ func (c *Config) OpenOCDConfiguration() (args []string, err error) {
|
||||
return nil, fmt.Errorf("unknown OpenOCD transport: %#v", c.Target.OpenOCDTransport)
|
||||
}
|
||||
args = []string{"-f", "interface/" + openocdInterface + ".cfg"}
|
||||
for _, cmd := range c.Target.OpenOCDCommands {
|
||||
args = append(args, "-c", cmd)
|
||||
}
|
||||
if c.Target.OpenOCDTransport != "" {
|
||||
transport := c.Target.OpenOCDTransport
|
||||
if transport == "swd" {
|
||||
@@ -485,6 +494,9 @@ func (c *Config) OpenOCDConfiguration() (args []string, err error) {
|
||||
args = append(args, "-c", "transport select "+transport)
|
||||
}
|
||||
args = append(args, "-f", "target/"+c.Target.OpenOCDTarget+".cfg")
|
||||
for _, cmd := range c.Target.OpenOCDCommands {
|
||||
args = append(args, "-c", cmd)
|
||||
}
|
||||
return args, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
var (
|
||||
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
|
||||
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
|
||||
validSerialOptions = []string{"none", "uart", "usb"}
|
||||
validSerialOptions = []string{"none", "uart", "usb", "rtt"}
|
||||
validPrintSizeOptions = []string{"none", "short", "full"}
|
||||
validPanicStrategyOptions = []string{"print", "trap"}
|
||||
validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
|
||||
@@ -23,6 +23,7 @@ type Options struct {
|
||||
GOOS string // environment variable
|
||||
GOARCH string // environment variable
|
||||
GOARM string // environment variable (only used with GOARCH=arm)
|
||||
Directory string // working dir, leave it unset to use the current working dir
|
||||
Target string
|
||||
Opt string
|
||||
GC string
|
||||
@@ -48,11 +49,12 @@ type Options struct {
|
||||
Programmer string
|
||||
OpenOCDCommands []string
|
||||
LLVMFeatures string
|
||||
Directory string
|
||||
PrintJSON bool
|
||||
Monitor bool
|
||||
BaudRate int
|
||||
Timeout time.Duration
|
||||
WITPackage string // pass through to wasm-tools component embed invocation
|
||||
WITWorld string // pass through to wasm-tools component embed -w option
|
||||
}
|
||||
|
||||
// Verify performs a validation on the given options, raising an error if options are not valid.
|
||||
|
||||
+42
-8
@@ -26,7 +26,7 @@ type TargetSpec struct {
|
||||
Inherits []string `json:"inherits,omitempty"`
|
||||
Triple string `json:"llvm-target,omitempty"`
|
||||
CPU string `json:"cpu,omitempty"`
|
||||
ABI string `json:"target-abi,omitempty"` // rougly equivalent to -mabi= flag
|
||||
ABI string `json:"target-abi,omitempty"` // roughly equivalent to -mabi= flag
|
||||
Features string `json:"features,omitempty"`
|
||||
GOOS string `json:"goos,omitempty"`
|
||||
GOARCH string `json:"goarch,omitempty"`
|
||||
@@ -62,6 +62,8 @@ type TargetSpec struct {
|
||||
JLinkDevice string `json:"jlink-device,omitempty"`
|
||||
CodeModel string `json:"code-model,omitempty"`
|
||||
RelocationModel string `json:"relocation-model,omitempty"`
|
||||
WITPackage string `json:"wit-package,omitempty"`
|
||||
WITWorld string `json:"wit-world,omitempty"`
|
||||
}
|
||||
|
||||
// overrideProperties overrides all properties that are set in child into itself using reflection.
|
||||
@@ -191,6 +193,10 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid GOARM=%s, must be 5, 6, or 7", options.GOARM)
|
||||
}
|
||||
case "mips":
|
||||
llvmarch = "mips"
|
||||
case "mipsle":
|
||||
llvmarch = "mipsel"
|
||||
case "wasm":
|
||||
llvmarch = "wasm32"
|
||||
default:
|
||||
@@ -301,10 +307,10 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
switch goarch {
|
||||
case "386":
|
||||
spec.CPU = "pentium4"
|
||||
spec.Features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
||||
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
||||
case "amd64":
|
||||
spec.CPU = "x86-64"
|
||||
spec.Features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
||||
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
||||
case "arm":
|
||||
spec.CPU = "generic"
|
||||
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
|
||||
@@ -319,10 +325,16 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
case "arm64":
|
||||
spec.CPU = "generic"
|
||||
if goos == "darwin" {
|
||||
spec.Features = "+neon"
|
||||
} else { // windows, linux
|
||||
spec.Features = "+neon,-fmv"
|
||||
spec.Features = "+fp-armv8,+neon"
|
||||
} else if goos == "windows" {
|
||||
spec.Features = "+fp-armv8,+neon,-fmv"
|
||||
} else { // linux
|
||||
spec.Features = "+fp-armv8,+neon,-fmv,-outline-atomics"
|
||||
}
|
||||
case "mips", "mipsle":
|
||||
spec.CPU = "mips32r2"
|
||||
spec.Features = "+fpxx,+mips32r2,+nooddspreg,-noabicalls"
|
||||
spec.CFlags = append(spec.CFlags, "-fno-pic")
|
||||
case "wasm":
|
||||
spec.CPU = "generic"
|
||||
spec.Features = "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext"
|
||||
@@ -349,6 +361,20 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
spec.RTLib = "compiler-rt"
|
||||
spec.Libc = "musl"
|
||||
spec.LDFlags = append(spec.LDFlags, "--gc-sections")
|
||||
if goarch == "arm64" {
|
||||
// Disable outline atomics. For details, see:
|
||||
// https://cpufun.substack.com/p/atomics-in-aarch64
|
||||
// A better way would be to fully support outline atomics, which
|
||||
// makes atomics slightly more efficient on systems with many cores.
|
||||
// But the instructions are only supported on newer aarch64 CPUs, so
|
||||
// this feature is normally put in a system library which does
|
||||
// feature detection for you.
|
||||
// We take the lazy way out and simply disable this feature, instead
|
||||
// of enabling it in compiler-rt (which is a bit more complicated).
|
||||
// We don't really need this feature anyway as we don't even support
|
||||
// proper threading.
|
||||
spec.CFlags = append(spec.CFlags, "-mno-outline-atomics")
|
||||
}
|
||||
} else if goos == "windows" {
|
||||
spec.Linker = "ld.lld"
|
||||
spec.Libc = "mingw-w64"
|
||||
@@ -401,8 +427,12 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
// operating systems so we need separate assembly files.
|
||||
suffix = "_windows"
|
||||
}
|
||||
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/asm_"+goarch+suffix+".S")
|
||||
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_stack_"+goarch+suffix+".S")
|
||||
asmGoarch := goarch
|
||||
if goarch == "mips" || goarch == "mipsle" {
|
||||
asmGoarch = "mipsx"
|
||||
}
|
||||
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/asm_"+asmGoarch+suffix+".S")
|
||||
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_stack_"+asmGoarch+suffix+".S")
|
||||
}
|
||||
if goarch != runtime.GOARCH {
|
||||
// Some educated guesses as to how to invoke helper programs.
|
||||
@@ -420,6 +450,10 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
spec.Emulator = "qemu-arm {}"
|
||||
case "arm64":
|
||||
spec.Emulator = "qemu-aarch64 {}"
|
||||
case "mips":
|
||||
spec.Emulator = "qemu-mips {}"
|
||||
case "mipsle":
|
||||
spec.Emulator = "qemu-mipsel {}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -16,14 +16,18 @@ import "tinygo.org/x/go-llvm"
|
||||
|
||||
var stdlibAliases = map[string]string{
|
||||
// crypto packages
|
||||
"crypto/ed25519/internal/edwards25519/field.feMul": "crypto/ed25519/internal/edwards25519/field.feMulGeneric",
|
||||
"crypto/ed25519/internal/edwards25519/field.feSquare": "crypto/ed25519/internal/edwards25519/field.feSquareGeneric",
|
||||
"crypto/ed25519/internal/edwards25519/field.feMul": "crypto/ed25519/internal/edwards25519/field.feMulGeneric",
|
||||
"crypto/internal/edwards25519/field.feSquare": "crypto/ed25519/internal/edwards25519/field.feSquareGeneric",
|
||||
"crypto/md5.block": "crypto/md5.blockGeneric",
|
||||
"crypto/sha1.block": "crypto/sha1.blockGeneric",
|
||||
"crypto/sha1.blockAMD64": "crypto/sha1.blockGeneric",
|
||||
"crypto/sha256.block": "crypto/sha256.blockGeneric",
|
||||
"crypto/sha512.blockAMD64": "crypto/sha512.blockGeneric",
|
||||
|
||||
// AES
|
||||
"crypto/aes.decryptBlockAsm": "crypto/aes.decryptBlock",
|
||||
"crypto/aes.encryptBlockAsm": "crypto/aes.encryptBlock",
|
||||
|
||||
// math package
|
||||
"math.archHypot": "math.hypot",
|
||||
"math.archMax": "math.max",
|
||||
|
||||
+2
-2
@@ -135,7 +135,7 @@ func (b *builder) createChanBoundsCheck(elementSize uint64, bufSize llvm.Value,
|
||||
|
||||
// Calculate (^uintptr(0)) >> 1, which is the max value that fits in an
|
||||
// uintptr if uintptrs were signed.
|
||||
maxBufSize := llvm.ConstLShr(llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)), llvm.ConstInt(b.uintptrType, 1, false))
|
||||
maxBufSize := b.CreateLShr(llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)), llvm.ConstInt(b.uintptrType, 1, false), "")
|
||||
if elementSize > maxBufSize.ZExtValue() {
|
||||
b.addError(pos, fmt.Sprintf("channel element type is too big (%v bytes)", elementSize))
|
||||
return
|
||||
@@ -150,7 +150,7 @@ func (b *builder) createChanBoundsCheck(elementSize uint64, bufSize llvm.Value,
|
||||
|
||||
// Make sure maxBufSize has the same type as bufSize.
|
||||
if maxBufSize.Type() != bufSize.Type() {
|
||||
maxBufSize = llvm.ConstZExt(maxBufSize, bufSize.Type())
|
||||
maxBufSize = b.CreateZExt(maxBufSize, bufSize.Type(), "")
|
||||
}
|
||||
|
||||
// Do the check for a too large (or negative) buffer size.
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
@@ -15,20 +12,6 @@ func (b *builder) createAtomicOp(name string) llvm.Value {
|
||||
case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
|
||||
ptr := b.getValue(b.fn.Params[0], getPos(b.fn))
|
||||
val := b.getValue(b.fn.Params[1], getPos(b.fn))
|
||||
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.GlobalValueType(), fn, []llvm.Value{ptr, val}, "")
|
||||
// Return the new value, not the original value returned.
|
||||
return b.CreateAdd(oldVal, val, "")
|
||||
}
|
||||
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, "")
|
||||
|
||||
+24
-7
@@ -53,8 +53,10 @@ type Config struct {
|
||||
Scheduler string
|
||||
AutomaticStackSize bool
|
||||
DefaultStackSize uint64
|
||||
MaxStackAlloc uint64
|
||||
NeedsStackObjects bool
|
||||
Debug bool // Whether to emit debug information in the LLVM module.
|
||||
PanicStrategy string
|
||||
}
|
||||
|
||||
// compilerContext contains function-independent data that should still be
|
||||
@@ -1844,9 +1846,9 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
return b.emitSV64Call(instr.Args, getPos(instr))
|
||||
case strings.HasPrefix(name, "(device/riscv.CSR)."):
|
||||
return b.emitCSROperation(instr)
|
||||
case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall"):
|
||||
case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall"):
|
||||
return b.createSyscall(instr)
|
||||
case strings.HasPrefix(name, "syscall.rawSyscallNoError"):
|
||||
case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"):
|
||||
return b.createRawSyscallNoError(instr)
|
||||
case name == "runtime.supportsRecover":
|
||||
supportsRecover := uint64(0)
|
||||
@@ -1854,6 +1856,13 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
supportsRecover = 1
|
||||
}
|
||||
return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil
|
||||
case name == "runtime.panicStrategy":
|
||||
// These constants are defined in src/runtime/panic.go.
|
||||
panicStrategy := map[string]uint64{
|
||||
"print": 1, // panicStrategyPrint
|
||||
"trap": 2, // panicStrategyTrap
|
||||
}[b.Config.PanicStrategy]
|
||||
return llvm.ConstInt(b.ctx.Int8Type(), panicStrategy, false), nil
|
||||
case name == "runtime/interrupt.New":
|
||||
return b.createInterruptGlobal(instr)
|
||||
}
|
||||
@@ -1997,8 +2006,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
case *ssa.Alloc:
|
||||
typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
||||
size := b.targetData.TypeAllocSize(typ)
|
||||
// Move all "large" allocations to the heap. This value is also transform.maxStackAlloc.
|
||||
if expr.Heap || size > 256 {
|
||||
// Move all "large" allocations to the heap.
|
||||
if expr.Heap || size > b.MaxStackAlloc {
|
||||
// Calculate ^uintptr(0)
|
||||
maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue()
|
||||
if size > maxSize {
|
||||
@@ -2008,6 +2017,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
||||
layoutValue := b.createObjectLayout(typ, expr.Pos())
|
||||
buf := b.createRuntimeCall("alloc", []llvm.Value{sizeValue, layoutValue}, expr.Comment)
|
||||
align := b.targetData.ABITypeAlignment(typ)
|
||||
buf.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
|
||||
return buf, nil
|
||||
} else {
|
||||
buf := llvmutil.CreateEntryBlockAlloca(b.Builder, typ, expr.Comment)
|
||||
@@ -2172,7 +2183,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
return llvm.Value{}, b.makeError(expr.Pos(), "todo: indexaddr: "+ptrTyp.String())
|
||||
}
|
||||
|
||||
// Make sure index is at least the size of uintptr becuase getelementptr
|
||||
// Make sure index is at least the size of uintptr because getelementptr
|
||||
// assumes index is a signed integer.
|
||||
index = b.extendInteger(index, expr.Index.Type(), b.uintptrType)
|
||||
|
||||
@@ -2214,6 +2225,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
sliceType := expr.Type().Underlying().(*types.Slice)
|
||||
llvmElemType := b.getLLVMType(sliceType.Elem())
|
||||
elemSize := b.targetData.TypeAllocSize(llvmElemType)
|
||||
elemAlign := b.targetData.ABITypeAlignment(llvmElemType)
|
||||
elemSizeValue := llvm.ConstInt(b.uintptrType, elemSize, false)
|
||||
|
||||
maxSize := b.maxSliceSize(llvmElemType)
|
||||
@@ -2237,6 +2249,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
||||
sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap")
|
||||
layoutValue := b.createObjectLayout(llvmElemType, expr.Pos())
|
||||
slicePtr := b.createRuntimeCall("alloc", []llvm.Value{sliceSize, layoutValue}, "makeslice.buf")
|
||||
slicePtr.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elemAlign)))
|
||||
|
||||
// Extend or truncate if necessary. This is safe as we've already done
|
||||
// the bounds check.
|
||||
@@ -2548,7 +2561,7 @@ func (b *builder) createBinOp(op token.Token, typ, ytyp types.Type, x, y llvm.Va
|
||||
sizeY := b.targetData.TypeAllocSize(y.Type())
|
||||
|
||||
// Check if the shift is bigger than the bit-width of the shifted value.
|
||||
// This is UB in LLVM, so it needs to be handled seperately.
|
||||
// This is UB in LLVM, so it needs to be handled separately.
|
||||
// The Go spec indirectly defines the result as 0.
|
||||
// Negative shifts are handled earlier, so we can treat y as unsigned.
|
||||
overshifted := b.CreateICmp(llvm.IntUGE, y, llvm.ConstInt(y.Type(), 8*sizeX, false), "shift.overflow")
|
||||
@@ -3261,7 +3274,11 @@ func (b *builder) createUnOp(unop *ssa.UnOp) (llvm.Value, error) {
|
||||
// Instead of a load from the global, create a bitcast of the
|
||||
// function pointer itself.
|
||||
name := strings.TrimSuffix(unop.X.(*ssa.Global).Name(), "$funcaddr")
|
||||
_, fn := b.getFunction(b.fn.Pkg.Members[name].(*ssa.Function))
|
||||
pkg := b.fn.Pkg
|
||||
if pkg == nil {
|
||||
pkg = b.fn.Origin().Pkg
|
||||
}
|
||||
_, fn := b.getFunction(pkg.Members[name].(*ssa.Function))
|
||||
if fn.IsNil() {
|
||||
return llvm.Value{}, b.makeError(unop.Pos(), "cgo function not found: "+name)
|
||||
}
|
||||
|
||||
@@ -187,6 +187,18 @@ std z+5, r29
|
||||
ldi r24, 0
|
||||
1:`
|
||||
constraints = "={r24},z,~{r0},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{r16},~{r17},~{r18},~{r19},~{r20},~{r21},~{r22},~{r23},~{r25},~{r26},~{r27}"
|
||||
case "mips":
|
||||
// $4 flag (zero or non-zero)
|
||||
// $5 defer frame
|
||||
asmString = `
|
||||
.set noat
|
||||
move $$4, $$zero
|
||||
jal 1f
|
||||
1:
|
||||
addiu $$ra, 8
|
||||
sw $$ra, 4($$5)
|
||||
.set at`
|
||||
constraints = "={$4},{$5},~{$1},~{$2},~{$3},~{$5},~{$6},~{$7},~{$8},~{$9},~{$10},~{$11},~{$12},~{$13},~{$14},~{$15},~{$16},~{$17},~{$18},~{$19},~{$20},~{$21},~{$22},~{$23},~{$24},~{$25},~{$26},~{$27},~{$28},~{$29},~{$30},~{$31},~{$f0},~{$f1},~{$f2},~{$f3},~{$f4},~{$f5},~{$f6},~{$f7},~{$f8},~{$f9},~{$f10},~{$f11},~{$f12},~{$f13},~{$f14},~{$f15},~{$f16},~{$f17},~{$f18},~{$f19},~{$f20},~{$f21},~{$f22},~{$f23},~{$f24},~{$f25},~{$f26},~{$f27},~{$f28},~{$f29},~{$f30},~{$f31},~{memory}"
|
||||
case "riscv32":
|
||||
asmString = `
|
||||
la a2, 1f
|
||||
|
||||
+108
-37
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -124,16 +125,19 @@ func (c *compilerContext) pkgPathPtr(pkgpath string) llvm.Value {
|
||||
func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
ms := c.program.MethodSets.MethodSet(typ)
|
||||
hasMethodSet := ms.Len() != 0
|
||||
if _, ok := typ.Underlying().(*types.Interface); ok {
|
||||
_, isInterface := typ.Underlying().(*types.Interface)
|
||||
if isInterface {
|
||||
hasMethodSet = false
|
||||
}
|
||||
|
||||
// As defined in https://pkg.go.dev/reflect#Type:
|
||||
// NumMethod returns the number of methods accessible using Method.
|
||||
// For a non-interface type, it returns the number of exported methods.
|
||||
// For an interface type, it returns the number of exported and unexported methods.
|
||||
var numMethods int
|
||||
if hasMethodSet {
|
||||
for i := 0; i < ms.Len(); i++ {
|
||||
if ms.At(i).Obj().Exported() {
|
||||
numMethods++
|
||||
}
|
||||
for i := 0; i < ms.Len(); i++ {
|
||||
if isInterface || ms.At(i).Obj().Exported() {
|
||||
numMethods++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,6 +181,15 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
typeFieldTypes := []*types.Var{
|
||||
types.NewVar(token.NoPos, nil, "kind", types.Typ[types.Int8]),
|
||||
}
|
||||
var methods []*types.Func
|
||||
for i := 0; i < ms.Len(); i++ {
|
||||
methods = append(methods, ms.At(i).Obj().(*types.Func))
|
||||
}
|
||||
methodSetType := types.NewStruct([]*types.Var{
|
||||
types.NewVar(token.NoPos, nil, "length", types.Typ[types.Uintptr]),
|
||||
types.NewVar(token.NoPos, nil, "methods", types.NewArray(types.Typ[types.UnsafePointer], int64(len(methods)))),
|
||||
}, nil)
|
||||
methodSetValue := c.getMethodSetValue(methods)
|
||||
switch typ := typ.(type) {
|
||||
case *types.Basic:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
@@ -193,6 +206,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "underlying", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "methods", methodSetType),
|
||||
types.NewVar(token.NoPos, nil, "name", types.NewArray(types.Typ[types.Int8], int64(len(pkgname)+1+len(name)+1))),
|
||||
)
|
||||
case *types.Chan:
|
||||
@@ -211,6 +225,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "methods", methodSetType),
|
||||
)
|
||||
case *types.Array:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
@@ -235,12 +250,13 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
types.NewVar(token.NoPos, nil, "size", types.Typ[types.Uint32]),
|
||||
types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))),
|
||||
types.NewVar(token.NoPos, nil, "methods", methodSetType),
|
||||
)
|
||||
case *types.Interface:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "methods", methodSetType),
|
||||
)
|
||||
// TODO: methods
|
||||
case *types.Signature:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
@@ -291,6 +307,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Underlying()), // underlying
|
||||
pkgPathPtr, // pkgpath pointer
|
||||
methodSetValue, // methods
|
||||
c.ctx.ConstString(pkgname+"."+name+"\x00", false), // name
|
||||
}
|
||||
metabyte |= 1 << 5 // "named" flag
|
||||
@@ -320,6 +337,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||
c.getTypeCode(typ.Elem()),
|
||||
methodSetValue, // methods
|
||||
}
|
||||
case *types.Array:
|
||||
typeFields = []llvm.Value{
|
||||
@@ -401,9 +419,12 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
}))
|
||||
}
|
||||
typeFields = append(typeFields, llvm.ConstArray(structFieldType, fields))
|
||||
typeFields = append(typeFields, methodSetValue)
|
||||
case *types.Interface:
|
||||
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
|
||||
// TODO: methods
|
||||
typeFields = []llvm.Value{
|
||||
c.getTypeCode(types.NewPointer(typ)),
|
||||
methodSetValue,
|
||||
}
|
||||
case *types.Signature:
|
||||
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
|
||||
// TODO: params, return values, etc
|
||||
@@ -511,8 +532,7 @@ var basicTypeNames = [...]string{
|
||||
func getTypeCodeName(t types.Type) (string, bool) {
|
||||
switch t := t.(type) {
|
||||
case *types.Named:
|
||||
// Note: check for `t.Obj().Pkg() != nil` for Go 1.18 only.
|
||||
if t.Obj().Pkg() != nil && t.Obj().Parent() != t.Obj().Pkg().Scope() {
|
||||
if t.Obj().Parent() != t.Obj().Pkg().Scope() {
|
||||
return "named:" + t.String() + "$local", true
|
||||
}
|
||||
return "named:" + t.String(), false
|
||||
@@ -683,20 +703,25 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
||||
assertedType := b.getLLVMType(expr.AssertedType)
|
||||
|
||||
actualTypeNum := b.CreateExtractValue(itf, 0, "interface.type")
|
||||
commaOk := llvm.Value{}
|
||||
if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
|
||||
// Type assert on interface type.
|
||||
// This is a call to an interface type assert function.
|
||||
// The interface lowering pass will define this function by filling it
|
||||
// with a type switch over all concrete types that implement this
|
||||
// interface, and returning whether it's one of the matched types.
|
||||
// This is very different from how interface asserts are implemented in
|
||||
// the main Go compiler, where the runtime checks whether the type
|
||||
// implements each method of the interface. See:
|
||||
// https://research.swtch.com/interfaces
|
||||
fn := b.getInterfaceImplementsFunc(expr.AssertedType)
|
||||
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
|
||||
var commaOk llvm.Value
|
||||
|
||||
if intf, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
|
||||
if intf.Empty() {
|
||||
// intf is the empty interface => no methods
|
||||
// This type assertion always succeeds, so we can just set commaOk to true.
|
||||
commaOk = llvm.ConstInt(b.ctx.Int1Type(), 1, true)
|
||||
} else {
|
||||
// Type assert using interface type with methods.
|
||||
// This is implemented using a runtime call, which checks that the
|
||||
// type implements each method of the interface.
|
||||
// For comparison, here is how the Go compiler does this (which is
|
||||
// very similar):
|
||||
// https://research.swtch.com/interfaces
|
||||
commaOk = b.createRuntimeCall("typeImplementsMethodSet", []llvm.Value{
|
||||
actualTypeNum,
|
||||
b.getInterfaceMethodSet(intf),
|
||||
}, "")
|
||||
}
|
||||
} else {
|
||||
name, _ := getTypeCodeName(expr.AssertedType)
|
||||
globalName := "reflect/types.typeid:" + name
|
||||
@@ -772,20 +797,66 @@ func (c *compilerContext) getMethodsString(itf *types.Interface) string {
|
||||
return strings.Join(methods, "; ")
|
||||
}
|
||||
|
||||
// getInterfaceImplementsFunc returns a declared function that works as a type
|
||||
// switch. The interface lowering pass will define this function.
|
||||
func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) llvm.Value {
|
||||
s, _ := getTypeCodeName(assertedType.Underlying())
|
||||
fnName := s + ".$typeassert"
|
||||
llvmFn := c.mod.NamedFunction(fnName)
|
||||
if llvmFn.IsNil() {
|
||||
llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.dataPtrType}, false)
|
||||
llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType)
|
||||
c.addStandardDeclaredAttributes(llvmFn)
|
||||
methods := c.getMethodsString(assertedType.Underlying().(*types.Interface))
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("tinygo-methods", methods))
|
||||
// Get the global that contains an interface method set, creating it if needed.
|
||||
func (c *compilerContext) getInterfaceMethodSet(t *types.Interface) llvm.Value {
|
||||
s, _ := getTypeCodeName(t)
|
||||
methodSetName := s + "$itfmethods"
|
||||
methodSet := c.mod.NamedFunction(methodSetName)
|
||||
if methodSet.IsNil() {
|
||||
var methods []*types.Func
|
||||
for i := 0; i < t.NumMethods(); i++ {
|
||||
methods = append(methods, t.Method(i))
|
||||
}
|
||||
if len(methods) == 0 {
|
||||
// This *should* be unreachable: the caller checks whether the
|
||||
// interface is empty before creating a method set.
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
methodSetValue := c.getMethodSetValue(methods)
|
||||
methodSet = llvm.AddGlobal(c.mod, methodSetValue.Type(), methodSetName)
|
||||
methodSet.SetInitializer(methodSetValue)
|
||||
methodSet.SetGlobalConstant(true)
|
||||
methodSet.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
methodSet.SetAlignment(c.targetData.ABITypeAlignment(methodSetValue.Type()))
|
||||
methodSet.SetUnnamedAddr(true)
|
||||
}
|
||||
return llvmFn
|
||||
|
||||
return methodSet
|
||||
}
|
||||
|
||||
// Get the method set value that is used in a number of type structs.
|
||||
func (c *compilerContext) getMethodSetValue(methods []*types.Func) llvm.Value {
|
||||
// Create a sorted list of method names.
|
||||
var methodRefNames []string
|
||||
for _, method := range methods {
|
||||
name := method.Name()
|
||||
if !token.IsExported(name) {
|
||||
name = method.Pkg().Path() + "." + name
|
||||
}
|
||||
s, _ := getTypeCodeName(method.Type())
|
||||
methodRefNames = append(methodRefNames, "reflect/types.signature:"+name+":"+s)
|
||||
}
|
||||
sort.Strings(methodRefNames)
|
||||
|
||||
// Turn this slice of strings in a slice of global variables.
|
||||
var methodRefValues []llvm.Value
|
||||
for _, name := range methodRefNames {
|
||||
value := c.mod.NamedGlobal(name)
|
||||
if value.IsNil() {
|
||||
value = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), name)
|
||||
value.SetInitializer(llvm.ConstNull(c.ctx.Int8Type()))
|
||||
value.SetGlobalConstant(true)
|
||||
value.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
value.SetAlignment(1)
|
||||
}
|
||||
methodRefValues = append(methodRefValues, value)
|
||||
}
|
||||
|
||||
return c.ctx.ConstStruct([]llvm.Value{
|
||||
llvm.ConstInt(c.uintptrType, uint64(len(methodRefValues)), false),
|
||||
llvm.ConstArray(c.dataPtrType, methodRefValues),
|
||||
}, false)
|
||||
}
|
||||
|
||||
// getInvokeFunction returns the thunk to call the given interface method. The
|
||||
|
||||
@@ -23,6 +23,8 @@ func (b *builder) defineIntrinsicFunction() {
|
||||
b.createMemoryCopyImpl()
|
||||
case name == "runtime.memzero":
|
||||
b.createMemoryZeroImpl()
|
||||
case name == "runtime.stacksave":
|
||||
b.createStackSaveImpl()
|
||||
case name == "runtime.KeepAlive":
|
||||
b.createKeepAliveImpl()
|
||||
case strings.HasPrefix(name, "runtime/volatile.Load"):
|
||||
@@ -77,6 +79,14 @@ func (b *builder) createMemoryZeroImpl() {
|
||||
b.CreateRetVoid()
|
||||
}
|
||||
|
||||
// createStackSaveImpl creates a call to llvm.stacksave.p0 to read the current
|
||||
// stack pointer.
|
||||
func (b *builder) createStackSaveImpl() {
|
||||
b.createFunctionStart(true)
|
||||
sp := b.readStackPointer()
|
||||
b.CreateRet(sp)
|
||||
}
|
||||
|
||||
// Return the llvm.memset.p0.i8 function declaration.
|
||||
func (c *compilerContext) getMemsetFunc() llvm.Value {
|
||||
fnName := "llvm.memset.p0.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
|
||||
|
||||
+11
-2
@@ -127,12 +127,14 @@ func (b *builder) emitPointerPack(values []llvm.Value) llvm.Value {
|
||||
|
||||
// Packed data is bigger than a pointer, so allocate it on the heap.
|
||||
sizeValue := llvm.ConstInt(b.uintptrType, size, false)
|
||||
align := b.targetData.ABITypeAlignment(packedType)
|
||||
alloc := b.mod.NamedFunction("runtime.alloc")
|
||||
packedAlloc := b.CreateCall(alloc.GlobalValueType(), alloc, []llvm.Value{
|
||||
sizeValue,
|
||||
llvm.ConstNull(b.dataPtrType),
|
||||
llvm.Undef(b.dataPtrType), // unused context parameter
|
||||
}, "")
|
||||
packedAlloc.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align)))
|
||||
if b.NeedsStackObjects {
|
||||
b.trackPointer(packedAlloc)
|
||||
}
|
||||
@@ -427,6 +429,9 @@ func (c *compilerContext) archFamily() string {
|
||||
if strings.HasPrefix(arch, "arm") || strings.HasPrefix(arch, "thumb") {
|
||||
return "arm"
|
||||
}
|
||||
if arch == "mipsel" {
|
||||
return "mips"
|
||||
}
|
||||
return arch
|
||||
}
|
||||
|
||||
@@ -451,10 +456,14 @@ func (c *compilerContext) isThumb() bool {
|
||||
// readStackPointer emits a LLVM intrinsic call that returns the current stack
|
||||
// pointer as an *i8.
|
||||
func (b *builder) readStackPointer() llvm.Value {
|
||||
stacksave := b.mod.NamedFunction("llvm.stacksave")
|
||||
name := "llvm.stacksave.p0"
|
||||
if llvmutil.Version() < 18 {
|
||||
name = "llvm.stacksave" // backwards compatibility with LLVM 17 and below
|
||||
}
|
||||
stacksave := b.mod.NamedFunction(name)
|
||||
if stacksave.IsNil() {
|
||||
fnType := llvm.FunctionType(b.dataPtrType, nil, false)
|
||||
stacksave = llvm.AddFunction(b.mod, "llvm.stacksave", fnType)
|
||||
stacksave = llvm.AddFunction(b.mod, name, fnType)
|
||||
}
|
||||
return b.CreateCall(stacksave.GlobalValueType(), stacksave, nil, "")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Package llvmutil contains utility functions used across multiple compiler
|
||||
// packages. For example, they may be used by both the compiler pacakge and
|
||||
// packages. For example, they may be used by both the compiler package and
|
||||
// transformation packages.
|
||||
//
|
||||
// Normally, utility packages are avoided. However, in this case, the utility
|
||||
@@ -8,6 +8,9 @@
|
||||
package llvmutil
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
@@ -28,7 +31,7 @@ func CreateEntryBlockAlloca(builder llvm.Builder, t llvm.Type, name string) llvm
|
||||
}
|
||||
|
||||
// CreateTemporaryAlloca creates a new alloca in the entry block and adds
|
||||
// lifetime start infromation in the IR signalling that the alloca won't be used
|
||||
// lifetime start information in the IR signalling that the alloca won't be used
|
||||
// before this point.
|
||||
//
|
||||
// This is useful for creating temporary allocas for intrinsics. Don't forget to
|
||||
@@ -173,7 +176,7 @@ func SplitBasicBlock(builder llvm.Builder, afterInst llvm.Value, insertAfter llv
|
||||
return newBlock
|
||||
}
|
||||
|
||||
// Append the given values to a global array like llvm.used. The global might
|
||||
// AppendToGlobal appends the given values to a global array like llvm.used. The global might
|
||||
// not exist yet. The values can be any pointer type, they will be cast to i8*.
|
||||
func AppendToGlobal(mod llvm.Module, globalName string, values ...llvm.Value) {
|
||||
// Read the existing values in the llvm.used array (if it exists).
|
||||
@@ -203,3 +206,13 @@ func AppendToGlobal(mod llvm.Module, globalName string, values ...llvm.Value) {
|
||||
used.SetInitializer(usedInitializer)
|
||||
used.SetLinkage(llvm.AppendingLinkage)
|
||||
}
|
||||
|
||||
// Return the LLVM major version.
|
||||
func Version() int {
|
||||
majorStr := strings.Split(llvm.Version, ".")[0]
|
||||
major, err := strconv.Atoi(majorStr)
|
||||
if err != nil {
|
||||
panic("unexpected error while parsing LLVM version: " + err.Error()) // should not happen
|
||||
}
|
||||
return major
|
||||
}
|
||||
|
||||
+39
-9
@@ -346,7 +346,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
// The list of allowed types is based on this proposal:
|
||||
// https://github.com/golang/go/issues/59149
|
||||
func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
|
||||
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" {
|
||||
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" || c.pkg.Path() == "syscall" {
|
||||
// The runtime is a special case. Allow all kinds of parameters
|
||||
// (importantly, including pointers).
|
||||
return
|
||||
@@ -360,38 +360,68 @@ func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
|
||||
c.addError(f.Signature.Results().At(1).Pos(), fmt.Sprintf("%s: too many return values", pragma))
|
||||
} else if f.Signature.Results().Len() == 1 {
|
||||
result := f.Signature.Results().At(0)
|
||||
if !isValidWasmType(result.Type(), true) {
|
||||
if !isValidWasmType(result.Type(), siteResult) {
|
||||
c.addError(result.Pos(), fmt.Sprintf("%s: unsupported result type %s", pragma, result.Type().String()))
|
||||
}
|
||||
}
|
||||
for _, param := range f.Params {
|
||||
// Check whether the type is allowed.
|
||||
// Only a very limited number of types can be mapped to WebAssembly.
|
||||
if !isValidWasmType(param.Type(), false) {
|
||||
if !isValidWasmType(param.Type(), siteParam) {
|
||||
c.addError(param.Pos(), fmt.Sprintf("%s: unsupported parameter type %s", pragma, param.Type().String()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether the type maps directly to a WebAssembly type, according to:
|
||||
// Check whether the type maps directly to a WebAssembly type.
|
||||
//
|
||||
// This reflects the relaxed type restrictions proposed here (except for structs.HostLayout):
|
||||
// https://github.com/golang/go/issues/66984
|
||||
//
|
||||
// This previously reflected the additional restrictions documented here:
|
||||
// https://github.com/golang/go/issues/59149
|
||||
func isValidWasmType(typ types.Type, isReturn bool) bool {
|
||||
func isValidWasmType(typ types.Type, site wasmSite) bool {
|
||||
switch typ := typ.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
switch typ.Kind() {
|
||||
case types.Int32, types.Uint32, types.Int64, types.Uint64:
|
||||
case types.Bool:
|
||||
return true
|
||||
case types.Int, types.Uint, types.Int8, types.Uint8, types.Int16, types.Uint16, types.Int32, types.Uint32, types.Int64, types.Uint64:
|
||||
return true
|
||||
case types.Float32, types.Float64:
|
||||
return true
|
||||
case types.UnsafePointer:
|
||||
if !isReturn {
|
||||
return true
|
||||
case types.Uintptr, types.UnsafePointer:
|
||||
return true
|
||||
case types.String:
|
||||
// string flattens to two values, so disallowed as a result
|
||||
return site == siteParam || site == siteIndirect
|
||||
}
|
||||
case *types.Array:
|
||||
return site == siteIndirect && isValidWasmType(typ.Elem(), siteIndirect)
|
||||
case *types.Struct:
|
||||
if site != siteIndirect {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < typ.NumFields(); i++ {
|
||||
if !isValidWasmType(typ.Field(i).Type(), siteIndirect) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case *types.Pointer:
|
||||
return isValidWasmType(typ.Elem(), siteIndirect)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type wasmSite int
|
||||
|
||||
const (
|
||||
siteParam wasmSite = iota
|
||||
siteResult
|
||||
siteIndirect // pointer or field
|
||||
)
|
||||
|
||||
// getParams returns the function parameters, including the receiver at the
|
||||
// start. This is an alternative to the Params member of *ssa.Function, which is
|
||||
// not yet populated when the package has not yet been built.
|
||||
|
||||
+99
-4
@@ -12,7 +12,8 @@ import (
|
||||
|
||||
// createRawSyscall creates a system call with the provided system call number
|
||||
// and returns the result as a single integer (the system call result). The
|
||||
// result is not further interpreted.
|
||||
// result is not further interpreted (with the exception of MIPS to use the same
|
||||
// return value everywhere).
|
||||
func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
num := b.getValue(call.Args[0], getPos(call))
|
||||
switch {
|
||||
@@ -33,18 +34,17 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
"{r10}",
|
||||
"{r8}",
|
||||
"{r9}",
|
||||
"{r11}",
|
||||
"{r12}",
|
||||
"{r13}",
|
||||
}[i]
|
||||
llvmValue := b.getValue(arg, getPos(call))
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
// rcx and r11 are clobbered by the syscall, so make sure they are not used
|
||||
constraints += ",~{rcx},~{r11}"
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel, false)
|
||||
return b.CreateCall(fnType, target, args, ""), nil
|
||||
|
||||
case b.GOARCH == "386" && b.GOOS == "linux":
|
||||
// Sources:
|
||||
// syscall(2) man page
|
||||
@@ -71,6 +71,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel, false)
|
||||
return b.CreateCall(fnType, target, args, ""), nil
|
||||
|
||||
case b.GOARCH == "arm" && b.GOOS == "linux":
|
||||
// Implement the EABI system call convention for Linux.
|
||||
// Source: syscall(2) man page.
|
||||
@@ -103,6 +104,7 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0, false)
|
||||
return b.CreateCall(fnType, target, args, ""), nil
|
||||
|
||||
case b.GOARCH == "arm64" && b.GOOS == "linux":
|
||||
// Source: syscall(2) man page.
|
||||
args := []llvm.Value{}
|
||||
@@ -135,6 +137,98 @@ func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0, false)
|
||||
return b.CreateCall(fnType, target, args, ""), nil
|
||||
|
||||
case (b.GOARCH == "mips" || b.GOARCH == "mipsle") && b.GOOS == "linux":
|
||||
// Implement the system call convention for Linux.
|
||||
// Source: syscall(2) man page and musl:
|
||||
// https://git.musl-libc.org/cgit/musl/tree/arch/mips/syscall_arch.h
|
||||
// Also useful:
|
||||
// https://web.archive.org/web/20220529105937/https://www.linux-mips.org/wiki/Syscall
|
||||
// The syscall number goes in r2, the result also in r2.
|
||||
// Register r7 is both an input paramter and an output parameter: if it
|
||||
// is non-zero, the system call failed and r2 is the error code.
|
||||
// The code below implements the O32 syscall ABI, not the N32 ABI. It
|
||||
// could implement both at the same time if needed (like what appears to
|
||||
// be done in musl) by forcing arg5-arg7 into the right registers but
|
||||
// letting the compiler decide the registers should result in _slightly_
|
||||
// faster and smaller code.
|
||||
args := []llvm.Value{num}
|
||||
argTypes := []llvm.Type{b.uintptrType}
|
||||
constraints := "={$2},={$7},0"
|
||||
syscallParams := call.Args[1:]
|
||||
if len(syscallParams) > 7 {
|
||||
// There is one syscall that uses 7 parameters: sync_file_range.
|
||||
// But only 7, not more. Go however only has Syscall6 and Syscall9.
|
||||
// Therefore, we can ignore the remaining parameters.
|
||||
syscallParams = syscallParams[:7]
|
||||
}
|
||||
for i, arg := range syscallParams {
|
||||
constraints += "," + [...]string{
|
||||
"{$4}", // arg1
|
||||
"{$5}", // arg2
|
||||
"{$6}", // arg3
|
||||
"1", // arg4, error return
|
||||
"r", // arg5 on the stack
|
||||
"r", // arg6 on the stack
|
||||
"r", // arg7 on the stack
|
||||
}[i]
|
||||
llvmValue := b.getValue(arg, getPos(call))
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
// Create assembly code.
|
||||
// Parameters beyond the first 4 are passed on the stack instead of in
|
||||
// registers in the O32 syscall ABI.
|
||||
// We need ".set noat" because LLVM might pick register $1 ($at) as the
|
||||
// register for a parameter and apparently this is not allowed on MIPS
|
||||
// unless you use this specific pragma.
|
||||
asm := "syscall"
|
||||
switch len(syscallParams) {
|
||||
case 5:
|
||||
asm = "" +
|
||||
".set noat\n" +
|
||||
"subu $$sp, $$sp, 32\n" +
|
||||
"sw $7, 16($$sp)\n" + // arg5
|
||||
"syscall\n" +
|
||||
"addu $$sp, $$sp, 32\n" +
|
||||
".set at\n"
|
||||
case 6:
|
||||
asm = "" +
|
||||
".set noat\n" +
|
||||
"subu $$sp, $$sp, 32\n" +
|
||||
"sw $7, 16($$sp)\n" + // arg5
|
||||
"sw $8, 20($$sp)\n" + // arg6
|
||||
"syscall\n" +
|
||||
"addu $$sp, $$sp, 32\n" +
|
||||
".set at\n"
|
||||
case 7:
|
||||
asm = "" +
|
||||
".set noat\n" +
|
||||
"subu $$sp, $$sp, 32\n" +
|
||||
"sw $7, 16($$sp)\n" + // arg5
|
||||
"sw $8, 20($$sp)\n" + // arg6
|
||||
"sw $9, 24($$sp)\n" + // arg7
|
||||
"syscall\n" +
|
||||
"addu $$sp, $$sp, 32\n" +
|
||||
".set at\n"
|
||||
}
|
||||
constraints += ",~{$3},~{$4},~{$5},~{$6},~{$8},~{$9},~{$10},~{$11},~{$12},~{$13},~{$14},~{$15},~{$24},~{$25},~{hi},~{lo},~{memory}"
|
||||
returnType := b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType}, false)
|
||||
fnType := llvm.FunctionType(returnType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, asm, constraints, true, true, 0, false)
|
||||
call := b.CreateCall(fnType, target, args, "")
|
||||
resultCode := b.CreateExtractValue(call, 0, "") // r2
|
||||
errorFlag := b.CreateExtractValue(call, 1, "") // r7
|
||||
// Pseudocode to return the result with the same convention as other
|
||||
// archs:
|
||||
// return (errorFlag != 0) ? -resultCode : resultCode;
|
||||
// At least on QEMU with the O32 ABI, the error code is always positive.
|
||||
zero := llvm.ConstInt(b.uintptrType, 0, false)
|
||||
isError := b.CreateICmp(llvm.IntNE, errorFlag, zero, "")
|
||||
negativeResult := b.CreateSub(zero, resultCode, "")
|
||||
result := b.CreateSelect(isError, negativeResult, resultCode, "")
|
||||
return result, nil
|
||||
|
||||
default:
|
||||
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
|
||||
}
|
||||
@@ -217,6 +311,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
retval = b.CreateInsertValue(retval, syscallResult, 0, "")
|
||||
retval = b.CreateInsertValue(retval, errResult, 2, "")
|
||||
return retval, nil
|
||||
|
||||
default:
|
||||
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -81,11 +81,11 @@ entry:
|
||||
%select.send.value = alloca i32, align 4
|
||||
store i32 1, ptr %select.send.value, align 4
|
||||
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %select.states.alloca)
|
||||
store ptr %ch1, ptr %select.states.alloca, align 8
|
||||
store ptr %ch1, ptr %select.states.alloca, align 4
|
||||
%select.states.alloca.repack1 = getelementptr inbounds %runtime.chanSelectState, ptr %select.states.alloca, i32 0, i32 1
|
||||
store ptr %select.send.value, ptr %select.states.alloca.repack1, align 4
|
||||
%0 = getelementptr inbounds [2 x %runtime.chanSelectState], ptr %select.states.alloca, i32 0, i32 1
|
||||
store ptr %ch2, ptr %0, align 8
|
||||
store ptr %ch2, ptr %0, align 4
|
||||
%.repack3 = getelementptr inbounds [2 x %runtime.chanSelectState], ptr %select.states.alloca, i32 0, i32 1, i32 1
|
||||
store ptr null, ptr %.repack3, align 4
|
||||
%select.result = call { i32, i1 } @runtime.tryChanSelect(ptr undef, ptr nonnull %select.states.alloca, i32 2, i32 2, ptr undef) #4
|
||||
|
||||
+3
-3
@@ -25,7 +25,7 @@ entry:
|
||||
%deferPtr = alloca ptr, align 4
|
||||
store ptr null, ptr %deferPtr, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||
%0 = call ptr @llvm.stacksave()
|
||||
%0 = call ptr @llvm.stacksave.p0()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
store i32 0, ptr %defer.alloca, align 4
|
||||
%defer.alloca.repack15 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
|
||||
@@ -113,7 +113,7 @@ rundefers.end3: ; preds = %rundefers.loophead6
|
||||
}
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind willreturn
|
||||
declare ptr @llvm.stacksave() #3
|
||||
declare ptr @llvm.stacksave.p0() #3
|
||||
|
||||
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #2
|
||||
|
||||
@@ -136,7 +136,7 @@ entry:
|
||||
%deferPtr = alloca ptr, align 4
|
||||
store ptr null, ptr %deferPtr, align 4
|
||||
%deferframe.buf = alloca %runtime.deferFrame, align 4
|
||||
%0 = call ptr @llvm.stacksave()
|
||||
%0 = call ptr @llvm.stacksave.p0()
|
||||
call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4
|
||||
store i32 0, ptr %defer.alloca, align 4
|
||||
%defer.alloca.repack22 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1
|
||||
|
||||
Vendored
+48
-14
@@ -13,31 +13,65 @@ func implementation() {
|
||||
|
||||
type Uint uint32
|
||||
|
||||
//go:wasmimport modulename validparam
|
||||
func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint)
|
||||
type S struct {
|
||||
a [4]uint32
|
||||
b uintptr
|
||||
c int
|
||||
d float32
|
||||
e float64
|
||||
}
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type int
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type string
|
||||
//go:wasmimport modulename validparam
|
||||
func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint, f uintptr, g string, h *int32, i *S)
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type [4]uint32
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type []byte
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type *int32
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type struct{a int}
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type chan struct{}
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type func()
|
||||
//
|
||||
//go:wasmimport modulename invalidparam
|
||||
func invalidparam(a int, b string, c []byte, d *int32)
|
||||
func invalidparam(a [4]uint32, b []byte, c struct{ a int }, d chan struct{}, e func())
|
||||
|
||||
//go:wasmimport modulename validreturn
|
||||
func validreturn() int32
|
||||
//go:wasmimport modulename validreturn_int32
|
||||
func validreturn_int32() int32
|
||||
|
||||
//go:wasmimport modulename validreturn_int
|
||||
func validreturn_int() int
|
||||
|
||||
//go:wasmimport modulename validreturn_ptr_int32
|
||||
func validreturn_ptr_int32() *int32
|
||||
|
||||
//go:wasmimport modulename validreturn_ptr_string
|
||||
func validreturn_ptr_string() *string
|
||||
|
||||
//go:wasmimport modulename validreturn_ptr_struct
|
||||
func validreturn_ptr_struct() *S
|
||||
|
||||
//go:wasmimport modulename validreturn_unsafe_pointer
|
||||
func validreturn_unsafe_pointer() unsafe.Pointer
|
||||
|
||||
// ERROR: //go:wasmimport modulename manyreturns: too many return values
|
||||
//
|
||||
//go:wasmimport modulename manyreturns
|
||||
func manyreturns() (int32, int32)
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidreturn: unsupported result type int
|
||||
// ERROR: //go:wasmimport modulename invalidreturn_func: unsupported result type func()
|
||||
//
|
||||
//go:wasmimport modulename invalidreturn
|
||||
func invalidreturn() int
|
||||
//go:wasmimport modulename invalidreturn_func
|
||||
func invalidreturn_func() func()
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidUnsafePointerReturn: unsupported result type unsafe.Pointer
|
||||
// ERROR: //go:wasmimport modulename invalidreturn_slice_byte: unsupported result type []byte
|
||||
//
|
||||
//go:wasmimport modulename invalidUnsafePointerReturn
|
||||
func invalidUnsafePointerReturn() unsafe.Pointer
|
||||
//go:wasmimport modulename invalidreturn_slice_byte
|
||||
func invalidreturn_slice_byte() []byte
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidreturn_chan_int: unsupported result type chan int
|
||||
//
|
||||
//go:wasmimport modulename invalidreturn_chan_int
|
||||
func invalidreturn_chan_int() chan int
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidreturn_string: unsupported result type string
|
||||
//
|
||||
//go:wasmimport modulename invalidreturn_string
|
||||
func invalidreturn_string() string
|
||||
|
||||
Vendored
+26
-26
@@ -16,13 +16,13 @@ target triple = "wasm32-unknown-wasi"
|
||||
@main.struct2 = hidden global ptr null, align 4
|
||||
@main.struct3 = hidden global ptr null, align 4
|
||||
@main.struct4 = hidden global ptr null, align 4
|
||||
@main.slice1 = hidden global { ptr, i32, i32 } zeroinitializer, align 8
|
||||
@main.slice2 = hidden global { ptr, i32, i32 } zeroinitializer, align 8
|
||||
@main.slice3 = hidden global { ptr, i32, i32 } zeroinitializer, align 8
|
||||
@main.slice1 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
|
||||
@main.slice2 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
|
||||
@main.slice3 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
|
||||
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
|
||||
@"runtime/gc.layout:62-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" }
|
||||
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
|
||||
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
|
||||
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr, { i32, [0 x ptr] } } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128", { i32, [0 x ptr] } zeroinitializer }, align 4
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
@@ -39,16 +39,16 @@ entry:
|
||||
define hidden void @main.newScalar(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call dereferenceable(1) ptr @runtime.alloc(i32 1, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%new = call align 1 dereferenceable(1) ptr @runtime.alloc(i32 1, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new, ptr @main.scalar1, align 4
|
||||
%new1 = call dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%new1 = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new1, ptr @main.scalar2, align 4
|
||||
%new2 = call dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%new2 = call align 8 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new2, ptr @main.scalar3, align 4
|
||||
%new3 = call dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%new3 = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new3, ptr @main.scalar4, align 4
|
||||
ret void
|
||||
@@ -58,13 +58,13 @@ entry:
|
||||
define hidden void @main.newArray(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call dereferenceable(3) ptr @runtime.alloc(i32 3, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%new = call align 1 dereferenceable(3) ptr @runtime.alloc(i32 3, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new, ptr @main.array1, align 4
|
||||
%new1 = call dereferenceable(71) ptr @runtime.alloc(i32 71, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%new1 = call align 1 dereferenceable(71) ptr @runtime.alloc(i32 71, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new1, ptr @main.array2, align 4
|
||||
%new2 = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
|
||||
%new2 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new2, ptr @main.array3, align 4
|
||||
ret void
|
||||
@@ -74,16 +74,16 @@ entry:
|
||||
define hidden void @main.newStruct(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%new = call align 1 ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new, ptr @main.struct1, align 4
|
||||
%new1 = call dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%new1 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new1, ptr @main.struct2, align 4
|
||||
%new2 = call dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-2000000000000001", ptr undef) #3
|
||||
%new2 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-2000000000000001", ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new2, ptr @main.struct3, align 4
|
||||
%new3 = call dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0001", ptr undef) #3
|
||||
%new3 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0001", ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new3, ptr @main.struct4, align 4
|
||||
ret void
|
||||
@@ -93,7 +93,7 @@ entry:
|
||||
define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%new = call dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #3
|
||||
%new = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3
|
||||
ret ptr %new
|
||||
}
|
||||
@@ -102,21 +102,21 @@ entry:
|
||||
define hidden void @main.makeSlice(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%makeslice = call dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %makeslice, ptr @main.slice1, align 8
|
||||
store ptr %makeslice, ptr @main.slice1, align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 1), align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 2), align 8
|
||||
%makeslice1 = call dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 2), align 4
|
||||
%makeslice1 = call align 4 dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %makeslice1, ptr @main.slice2, align 8
|
||||
store ptr %makeslice1, ptr @main.slice2, align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 1), align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 2), align 8
|
||||
%makeslice3 = call dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #3
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 2), align 4
|
||||
%makeslice3 = call align 4 dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %makeslice3, ptr @main.slice3, align 8
|
||||
store ptr %makeslice3, ptr @main.slice3, align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 1), align 4
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 2), align 8
|
||||
store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 2), align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ entry:
|
||||
define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3
|
||||
%0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store double %v.r, ptr %0, align 8
|
||||
%.repack1 = getelementptr inbounds { double, double }, ptr %0, i32 0, i32 1
|
||||
|
||||
+4
-4
@@ -63,9 +63,9 @@ entry:
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%n = call dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
|
||||
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
|
||||
store i32 3, ptr %n, align 4
|
||||
%0 = call dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
|
||||
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
|
||||
store ptr %n, ptr %1, align 4
|
||||
@@ -98,7 +98,7 @@ declare void @runtime.printint32(i32, ptr) #2
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
|
||||
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1
|
||||
store ptr %fn.context, ptr %1, align 4
|
||||
@@ -148,7 +148,7 @@ declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #2
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = call dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
|
||||
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
|
||||
store ptr %itf.value, ptr %0, align 4
|
||||
%1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1
|
||||
store ptr @"main$string", ptr %1, align 4
|
||||
|
||||
+4
-4
@@ -66,12 +66,12 @@ entry:
|
||||
define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%n = call dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
|
||||
%n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
|
||||
store i32 3, ptr %n, align 4
|
||||
call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #9
|
||||
%0 = call dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
|
||||
%0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
|
||||
@@ -106,7 +106,7 @@ declare void @runtime.printint32(i32, ptr) #1
|
||||
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
|
||||
%0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
||||
store i32 5, ptr %0, align 4
|
||||
%1 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1
|
||||
@@ -158,7 +158,7 @@ declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #1
|
||||
define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
|
||||
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
|
||||
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
|
||||
store ptr %itf.value, ptr %0, align 4
|
||||
%1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1
|
||||
|
||||
Vendored
+31
-31
@@ -7,15 +7,19 @@ target triple = "wasm32-unknown-wasi"
|
||||
%runtime._string = type { ptr, i32 }
|
||||
|
||||
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
|
||||
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 0, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
|
||||
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr, { i32, [0 x ptr] } } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int", { i32, [0 x ptr] } zeroinitializer }, align 4
|
||||
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr, { i32, [0 x ptr] } } { i8 -43, i16 0, ptr @"reflect/types.type:named:error", { i32, [0 x ptr] } zeroinitializer }, align 4
|
||||
@"reflect/types.signature:Error:func:{}{basic:string}" = linkonce_odr constant i8 0, align 1
|
||||
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, { i32, [1 x ptr] }, [7 x i8] } { i8 116, i16 1, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:Error:func:{}{basic:string}"] }, [7 x i8] c".error\00" }, align 4
|
||||
@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1
|
||||
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr, { i32, [1 x ptr] } } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:Error:func:{}{basic:string}"] } }, align 4
|
||||
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr, { i32, [0 x ptr] } } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", { i32, [0 x ptr] } zeroinitializer }, align 4
|
||||
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr, { i32, [0 x ptr] } } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}", { i32, [0 x ptr] } zeroinitializer }, align 4
|
||||
@"reflect/types.signature:String:func:{}{basic:string}" = linkonce_odr constant i8 0, align 1
|
||||
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr, { i32, [1 x ptr] } } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:String:func:{}{basic:string}"] } }, align 4
|
||||
@"reflect/types.typeid:basic:int" = external constant i8
|
||||
@"interface:{Error:func:{}{basic:string}}$itfmethods" = linkonce_odr unnamed_addr constant { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:Error:func:{}{basic:string}"] }, align 4
|
||||
@"interface:{String:func:{}{basic:string}}$itfmethods" = linkonce_odr unnamed_addr constant { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:String:func:{}{basic:string}"] }, align 4
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
@@ -32,8 +36,8 @@ entry:
|
||||
define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) #5
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret %runtime._interface { ptr @"reflect/types.type:basic:int", ptr null }
|
||||
}
|
||||
|
||||
@@ -41,8 +45,8 @@ entry:
|
||||
define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) #5
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret %runtime._interface { ptr @"reflect/types.type:pointer:basic:int", ptr null }
|
||||
}
|
||||
|
||||
@@ -50,8 +54,8 @@ entry:
|
||||
define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) #5
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret %runtime._interface { ptr @"reflect/types.type:pointer:named:error", ptr null }
|
||||
}
|
||||
|
||||
@@ -59,15 +63,15 @@ entry:
|
||||
define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr nonnull %stackalloc, ptr undef) #5
|
||||
call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret %runtime._interface { ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr null }
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #7
|
||||
%typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #5
|
||||
br i1 %typecode, label %typeassert.ok, label %typeassert.next
|
||||
|
||||
typeassert.next: ; preds = %typeassert.ok, %entry
|
||||
@@ -82,7 +86,7 @@ declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #1
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
|
||||
%0 = call i1 @runtime.typeImplementsMethodSet(ptr %itf.typecode, ptr nonnull @"interface:{Error:func:{}{basic:string}}$itfmethods", ptr undef) #5
|
||||
br i1 %0, label %typeassert.ok, label %typeassert.next
|
||||
|
||||
typeassert.next: ; preds = %typeassert.ok, %entry
|
||||
@@ -92,12 +96,12 @@ typeassert.ok: ; preds = %entry
|
||||
br label %typeassert.next
|
||||
}
|
||||
|
||||
declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #3
|
||||
declare i1 @runtime.typeImplementsMethodSet(ptr, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7
|
||||
%0 = call i1 @runtime.typeImplementsMethodSet(ptr %itf.typecode, ptr nonnull @"interface:{String:func:{}{basic:string}}$itfmethods", ptr undef) #5
|
||||
br i1 %0, label %typeassert.ok, label %typeassert.next
|
||||
|
||||
typeassert.next: ; preds = %typeassert.ok, %entry
|
||||
@@ -107,34 +111,30 @@ typeassert.ok: ; preds = %entry
|
||||
br label %typeassert.next
|
||||
}
|
||||
|
||||
declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #4
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr %itf.value, i32 3, ptr %itf.typecode, ptr undef) #7
|
||||
%0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr %itf.value, i32 3, ptr %itf.typecode, ptr undef) #5
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #5
|
||||
declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #7
|
||||
%0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #5
|
||||
%1 = extractvalue %runtime._string %0, 0
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #7
|
||||
call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret %runtime._string %0
|
||||
}
|
||||
|
||||
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #6
|
||||
declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #4
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #4 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.String() string" }
|
||||
attributes #5 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
||||
attributes #6 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #7 = { nounwind }
|
||||
attributes #3 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
||||
attributes #4 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #5 = { nounwind }
|
||||
|
||||
Vendored
+8
-8
@@ -48,7 +48,7 @@ declare void @runtime.lookupPanic(ptr) #1
|
||||
define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%varargs = call dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%varargs = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store i32 1, ptr %varargs, align 4
|
||||
%0 = getelementptr inbounds [3 x i32], ptr %varargs, i32 0, i32 1
|
||||
@@ -100,7 +100,7 @@ entry:
|
||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.buf = call ptr @runtime.alloc(i32 %len, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%makeslice.buf = call align 1 ptr @runtime.alloc(i32 %len, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
|
||||
@@ -122,8 +122,8 @@ entry:
|
||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.cap = shl i32 %len, 1
|
||||
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%makeslice.cap = shl nuw i32 %len, 1
|
||||
%makeslice.buf = call align 2 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
|
||||
@@ -144,7 +144,7 @@ entry:
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.cap = mul i32 %len, 3
|
||||
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%makeslice.buf = call align 1 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
|
||||
@@ -164,8 +164,8 @@ entry:
|
||||
br i1 %slice.maxcap, label %slice.throw, label %slice.next
|
||||
|
||||
slice.next: ; preds = %entry
|
||||
%makeslice.cap = shl i32 %len, 2
|
||||
%makeslice.buf = call ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%makeslice.cap = shl nuw i32 %len, 2
|
||||
%makeslice.buf = call align 4 ptr @runtime.alloc(i32 %makeslice.cap, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0
|
||||
%1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1
|
||||
%2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2
|
||||
@@ -216,7 +216,7 @@ declare void @runtime.sliceToArrayPointerPanic(ptr) #1
|
||||
define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%stackalloc = alloca i8, align 1
|
||||
%makeslice = call dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
%makeslice = call align 4 dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3
|
||||
br i1 false, label %slicetoarray.throw, label %slicetoarray.next
|
||||
|
||||
|
||||
Vendored
+4
-4
@@ -26,7 +26,7 @@ entry:
|
||||
%2 = insertvalue %main.hasPadding %1, i1 %s.b2, 2
|
||||
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
|
||||
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
|
||||
store %main.hasPadding %2, ptr %hashmap.key, align 8
|
||||
store %main.hasPadding %2, ptr %hashmap.key, align 4
|
||||
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
||||
@@ -59,7 +59,7 @@ entry:
|
||||
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
|
||||
store i32 5, ptr %hashmap.value, align 4
|
||||
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %hashmap.key)
|
||||
store %main.hasPadding %2, ptr %hashmap.key, align 8
|
||||
store %main.hasPadding %2, ptr %hashmap.key, align 4
|
||||
%3 = getelementptr inbounds i8, ptr %hashmap.key, i32 1
|
||||
call void @runtime.memzero(ptr nonnull %3, i32 3, ptr undef) #5
|
||||
%4 = getelementptr inbounds i8, ptr %hashmap.key, i32 9
|
||||
@@ -80,7 +80,7 @@ entry:
|
||||
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %hashmap.value)
|
||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
|
||||
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
||||
store %main.hasPadding %s.elt, ptr %hashmap.key, align 8
|
||||
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
|
||||
%hashmap.key.repack1 = getelementptr inbounds [2 x %main.hasPadding], ptr %hashmap.key, i32 0, i32 1
|
||||
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
|
||||
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
|
||||
@@ -108,7 +108,7 @@ entry:
|
||||
store i32 5, ptr %hashmap.value, align 4
|
||||
call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %hashmap.key)
|
||||
%s.elt = extractvalue [2 x %main.hasPadding] %s, 0
|
||||
store %main.hasPadding %s.elt, ptr %hashmap.key, align 8
|
||||
store %main.hasPadding %s.elt, ptr %hashmap.key, align 4
|
||||
%hashmap.key.repack1 = getelementptr inbounds [2 x %main.hasPadding], ptr %hashmap.key, i32 0, i32 1
|
||||
%s.elt2 = extractvalue [2 x %main.hasPadding] %s, 1
|
||||
store %main.hasPadding %s.elt2, ptr %hashmap.key.repack1, align 4
|
||||
|
||||
+3
-2
@@ -51,6 +51,7 @@ func TestCorpus(t *testing.T) {
|
||||
if *testTarget != "" {
|
||||
target = *testTarget
|
||||
}
|
||||
isWASI := strings.HasPrefix(target, "wasi")
|
||||
|
||||
repos, err := loadRepos(*corpus)
|
||||
if err != nil {
|
||||
@@ -69,7 +70,7 @@ func TestCorpus(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if target == "wasi" && repo.SkipWASI {
|
||||
if isWASI && repo.SkipWASI {
|
||||
t.Skip("skip wasi")
|
||||
}
|
||||
if repo.Slow && testing.Short() {
|
||||
@@ -135,7 +136,7 @@ func TestCorpus(t *testing.T) {
|
||||
t.Run(dir.Pkg, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if target == "wasi" && dir.SkipWASI {
|
||||
if isWASI && dir.SkipWASI {
|
||||
t.Skip("skip wasi")
|
||||
}
|
||||
if dir.Slow && testing.Short() {
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
// Package diagnostics formats compiler errors and prints them in a consistent
|
||||
// way.
|
||||
package diagnostics
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/tinygo-org/tinygo/builder"
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
"github.com/tinygo-org/tinygo/interp"
|
||||
"github.com/tinygo-org/tinygo/loader"
|
||||
)
|
||||
|
||||
// A single diagnostic.
|
||||
type Diagnostic struct {
|
||||
Pos token.Position
|
||||
Msg string
|
||||
}
|
||||
|
||||
// One or multiple errors of a particular package.
|
||||
// It can also represent whole-program errors (like linker errors) that can't
|
||||
// easily be connected to a single package.
|
||||
type PackageDiagnostic struct {
|
||||
ImportPath string // the same ImportPath as in `go list -json`
|
||||
Diagnostics []Diagnostic
|
||||
}
|
||||
|
||||
// Diagnostics of a whole program. This can include errors belonging to multiple
|
||||
// packages, or just a single package.
|
||||
type ProgramDiagnostic []PackageDiagnostic
|
||||
|
||||
// CreateDiagnostics reads the underlying errors in the error object and creates
|
||||
// a set of diagnostics that's sorted and can be readily printed.
|
||||
func CreateDiagnostics(err error) ProgramDiagnostic {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
// Right now, the compiler will only show errors for the first pacakge that
|
||||
// fails to build. This is likely to change in the future.
|
||||
return ProgramDiagnostic{
|
||||
createPackageDiagnostic(err),
|
||||
}
|
||||
}
|
||||
|
||||
// Create diagnostics for a single package (though, in practice, it may also be
|
||||
// used for whole-program diagnostics in some cases).
|
||||
func createPackageDiagnostic(err error) PackageDiagnostic {
|
||||
// Extract diagnostics for this package.
|
||||
var pkgDiag PackageDiagnostic
|
||||
switch err := err.(type) {
|
||||
case *builder.MultiError:
|
||||
if err.ImportPath != "" {
|
||||
pkgDiag.ImportPath = err.ImportPath
|
||||
}
|
||||
for _, err := range err.Errs {
|
||||
diags := createDiagnostics(err)
|
||||
pkgDiag.Diagnostics = append(pkgDiag.Diagnostics, diags...)
|
||||
}
|
||||
case loader.Errors:
|
||||
if err.Pkg != nil {
|
||||
pkgDiag.ImportPath = err.Pkg.ImportPath
|
||||
}
|
||||
for _, err := range err.Errs {
|
||||
diags := createDiagnostics(err)
|
||||
pkgDiag.Diagnostics = append(pkgDiag.Diagnostics, diags...)
|
||||
}
|
||||
case *interp.Error:
|
||||
pkgDiag.ImportPath = err.ImportPath
|
||||
w := &bytes.Buffer{}
|
||||
fmt.Fprintln(w, err.Error())
|
||||
if len(err.Inst) != 0 {
|
||||
fmt.Fprintln(w, err.Inst)
|
||||
}
|
||||
if len(err.Traceback) > 0 {
|
||||
fmt.Fprintln(w, "\ntraceback:")
|
||||
for _, line := range err.Traceback {
|
||||
fmt.Fprintln(w, line.Pos.String()+":")
|
||||
fmt.Fprintln(w, line.Inst)
|
||||
}
|
||||
}
|
||||
pkgDiag.Diagnostics = append(pkgDiag.Diagnostics, Diagnostic{
|
||||
Msg: w.String(),
|
||||
})
|
||||
default:
|
||||
pkgDiag.Diagnostics = createDiagnostics(err)
|
||||
}
|
||||
|
||||
// Sort these diagnostics by file/line/column.
|
||||
sort.SliceStable(pkgDiag.Diagnostics, func(i, j int) bool {
|
||||
posI := pkgDiag.Diagnostics[i].Pos
|
||||
posJ := pkgDiag.Diagnostics[j].Pos
|
||||
if posI.Filename != posJ.Filename {
|
||||
return posI.Filename < posJ.Filename
|
||||
}
|
||||
if posI.Line != posJ.Line {
|
||||
return posI.Line < posJ.Line
|
||||
}
|
||||
return posI.Column < posJ.Column
|
||||
})
|
||||
|
||||
return pkgDiag
|
||||
}
|
||||
|
||||
// Extract diagnostics from the given error message and return them as a slice
|
||||
// of errors (which in many cases will just be a single diagnostic).
|
||||
func createDiagnostics(err error) []Diagnostic {
|
||||
switch err := err.(type) {
|
||||
case types.Error:
|
||||
return []Diagnostic{
|
||||
{
|
||||
Pos: err.Fset.Position(err.Pos),
|
||||
Msg: err.Msg,
|
||||
},
|
||||
}
|
||||
case scanner.Error:
|
||||
return []Diagnostic{
|
||||
{
|
||||
Pos: err.Pos,
|
||||
Msg: err.Msg,
|
||||
},
|
||||
}
|
||||
case scanner.ErrorList:
|
||||
var diags []Diagnostic
|
||||
for _, err := range err {
|
||||
diags = append(diags, createDiagnostics(*err)...)
|
||||
}
|
||||
return diags
|
||||
case loader.Error:
|
||||
if err.Err.Pos.Filename != "" {
|
||||
// Probably a syntax error in a dependency.
|
||||
return createDiagnostics(err.Err)
|
||||
} else {
|
||||
// Probably an "import cycle not allowed" error.
|
||||
buf := &bytes.Buffer{}
|
||||
fmt.Fprintln(buf, "package", err.ImportStack[0])
|
||||
for i := 1; i < len(err.ImportStack); i++ {
|
||||
pkgPath := err.ImportStack[i]
|
||||
if i == len(err.ImportStack)-1 {
|
||||
// last package
|
||||
fmt.Fprintln(buf, "\timports", pkgPath+": "+err.Err.Error())
|
||||
} else {
|
||||
// not the last pacakge
|
||||
fmt.Fprintln(buf, "\timports", pkgPath)
|
||||
}
|
||||
}
|
||||
return []Diagnostic{
|
||||
{Msg: buf.String()},
|
||||
}
|
||||
}
|
||||
default:
|
||||
return []Diagnostic{
|
||||
{Msg: err.Error()},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write program diagnostics to the given writer with 'wd' as the relative
|
||||
// working directory.
|
||||
func (progDiag ProgramDiagnostic) WriteTo(w io.Writer, wd string) {
|
||||
for _, pkgDiag := range progDiag {
|
||||
pkgDiag.WriteTo(w, wd)
|
||||
}
|
||||
}
|
||||
|
||||
// Write package diagnostics to the given writer with 'wd' as the relative
|
||||
// working directory.
|
||||
func (pkgDiag PackageDiagnostic) WriteTo(w io.Writer, wd string) {
|
||||
if pkgDiag.ImportPath != "" {
|
||||
fmt.Fprintln(w, "#", pkgDiag.ImportPath)
|
||||
}
|
||||
for _, diag := range pkgDiag.Diagnostics {
|
||||
diag.WriteTo(w, wd)
|
||||
}
|
||||
}
|
||||
|
||||
// Write this diagnostic to the given writer with 'wd' as the relative working
|
||||
// directory.
|
||||
func (diag Diagnostic) WriteTo(w io.Writer, wd string) {
|
||||
if diag.Pos == (token.Position{}) {
|
||||
fmt.Fprintln(w, diag.Msg)
|
||||
return
|
||||
}
|
||||
pos := diag.Pos // make a copy
|
||||
if !strings.HasPrefix(pos.Filename, filepath.Join(goenv.Get("GOROOT"), "src")) && !strings.HasPrefix(pos.Filename, filepath.Join(goenv.Get("TINYGOROOT"), "src")) {
|
||||
// This file is not from the standard library (either the GOROOT or the
|
||||
// TINYGOROOT). Make the path relative, for easier reading. Ignore any
|
||||
// errors in the process (falling back to the absolute path).
|
||||
pos.Filename = tryToMakePathRelative(pos.Filename, wd)
|
||||
}
|
||||
fmt.Fprintf(w, "%s: %s\n", pos, diag.Msg)
|
||||
}
|
||||
|
||||
// try to make the path relative to the current working directory. If any error
|
||||
// occurs, this error is ignored and the absolute path is returned instead.
|
||||
func tryToMakePathRelative(dir, wd string) string {
|
||||
if wd == "" {
|
||||
return dir // working directory not found
|
||||
}
|
||||
relpath, err := filepath.Rel(wd, dir)
|
||||
if err != nil {
|
||||
return dir
|
||||
}
|
||||
return relpath
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A pair is a pair of values tracked for both the x and y side of a diff.
|
||||
// It is typically a pair of line indexes.
|
||||
type pair struct{ x, y int }
|
||||
|
||||
// Diff returns an anchored diff of the two texts old and new
|
||||
// in the “unified diff” format. If old and new are identical,
|
||||
// Diff returns a nil slice (no output).
|
||||
//
|
||||
// Unix diff implementations typically look for a diff with
|
||||
// the smallest number of lines inserted and removed,
|
||||
// which can in the worst case take time quadratic in the
|
||||
// number of lines in the texts. As a result, many implementations
|
||||
// either can be made to run for a long time or cut off the search
|
||||
// after a predetermined amount of work.
|
||||
//
|
||||
// In contrast, this implementation looks for a diff with the
|
||||
// smallest number of “unique” lines inserted and removed,
|
||||
// where unique means a line that appears just once in both old and new.
|
||||
// We call this an “anchored diff” because the unique lines anchor
|
||||
// the chosen matching regions. An anchored diff is usually clearer
|
||||
// than a standard diff, because the algorithm does not try to
|
||||
// reuse unrelated blank lines or closing braces.
|
||||
// The algorithm also guarantees to run in O(n log n) time
|
||||
// instead of the standard O(n²) time.
|
||||
//
|
||||
// Some systems call this approach a “patience diff,” named for
|
||||
// the “patience sorting” algorithm, itself named for a solitaire card game.
|
||||
// We avoid that name for two reasons. First, the name has been used
|
||||
// for a few different variants of the algorithm, so it is imprecise.
|
||||
// Second, the name is frequently interpreted as meaning that you have
|
||||
// to wait longer (to be patient) for the diff, meaning that it is a slower algorithm,
|
||||
// when in fact the algorithm is faster than the standard one.
|
||||
func Diff(oldName string, old []byte, newName string, new []byte) []byte {
|
||||
if bytes.Equal(old, new) {
|
||||
return nil
|
||||
}
|
||||
x := lines(old)
|
||||
y := lines(new)
|
||||
|
||||
// Print diff header.
|
||||
var out bytes.Buffer
|
||||
fmt.Fprintf(&out, "diff %s %s\n", oldName, newName)
|
||||
fmt.Fprintf(&out, "--- %s\n", oldName)
|
||||
fmt.Fprintf(&out, "+++ %s\n", newName)
|
||||
|
||||
// Loop over matches to consider,
|
||||
// expanding each match to include surrounding lines,
|
||||
// and then printing diff chunks.
|
||||
// To avoid setup/teardown cases outside the loop,
|
||||
// tgs returns a leading {0,0} and trailing {len(x), len(y)} pair
|
||||
// in the sequence of matches.
|
||||
var (
|
||||
done pair // printed up to x[:done.x] and y[:done.y]
|
||||
chunk pair // start lines of current chunk
|
||||
count pair // number of lines from each side in current chunk
|
||||
ctext []string // lines for current chunk
|
||||
)
|
||||
for _, m := range tgs(x, y) {
|
||||
if m.x < done.x {
|
||||
// Already handled scanning forward from earlier match.
|
||||
continue
|
||||
}
|
||||
|
||||
// Expand matching lines as far as possible,
|
||||
// establishing that x[start.x:end.x] == y[start.y:end.y].
|
||||
// Note that on the first (or last) iteration we may (or definitely do)
|
||||
// have an empty match: start.x==end.x and start.y==end.y.
|
||||
start := m
|
||||
for start.x > done.x && start.y > done.y && x[start.x-1] == y[start.y-1] {
|
||||
start.x--
|
||||
start.y--
|
||||
}
|
||||
end := m
|
||||
for end.x < len(x) && end.y < len(y) && x[end.x] == y[end.y] {
|
||||
end.x++
|
||||
end.y++
|
||||
}
|
||||
|
||||
// Emit the mismatched lines before start into this chunk.
|
||||
// (No effect on first sentinel iteration, when start = {0,0}.)
|
||||
for _, s := range x[done.x:start.x] {
|
||||
ctext = append(ctext, "-"+s)
|
||||
count.x++
|
||||
}
|
||||
for _, s := range y[done.y:start.y] {
|
||||
ctext = append(ctext, "+"+s)
|
||||
count.y++
|
||||
}
|
||||
|
||||
// If we're not at EOF and have too few common lines,
|
||||
// the chunk includes all the common lines and continues.
|
||||
const C = 3 // number of context lines
|
||||
if (end.x < len(x) || end.y < len(y)) &&
|
||||
(end.x-start.x < C || (len(ctext) > 0 && end.x-start.x < 2*C)) {
|
||||
for _, s := range x[start.x:end.x] {
|
||||
ctext = append(ctext, " "+s)
|
||||
count.x++
|
||||
count.y++
|
||||
}
|
||||
done = end
|
||||
continue
|
||||
}
|
||||
|
||||
// End chunk with common lines for context.
|
||||
if len(ctext) > 0 {
|
||||
n := end.x - start.x
|
||||
if n > C {
|
||||
n = C
|
||||
}
|
||||
for _, s := range x[start.x : start.x+n] {
|
||||
ctext = append(ctext, " "+s)
|
||||
count.x++
|
||||
count.y++
|
||||
}
|
||||
done = pair{start.x + n, start.y + n}
|
||||
|
||||
// Format and emit chunk.
|
||||
// Convert line numbers to 1-indexed.
|
||||
// Special case: empty file shows up as 0,0 not 1,0.
|
||||
if count.x > 0 {
|
||||
chunk.x++
|
||||
}
|
||||
if count.y > 0 {
|
||||
chunk.y++
|
||||
}
|
||||
fmt.Fprintf(&out, "@@ -%d,%d +%d,%d @@\n", chunk.x, count.x, chunk.y, count.y)
|
||||
for _, s := range ctext {
|
||||
out.WriteString(s)
|
||||
}
|
||||
count.x = 0
|
||||
count.y = 0
|
||||
ctext = ctext[:0]
|
||||
}
|
||||
|
||||
// If we reached EOF, we're done.
|
||||
if end.x >= len(x) && end.y >= len(y) {
|
||||
break
|
||||
}
|
||||
|
||||
// Otherwise start a new chunk.
|
||||
chunk = pair{end.x - C, end.y - C}
|
||||
for _, s := range x[chunk.x:end.x] {
|
||||
ctext = append(ctext, " "+s)
|
||||
count.x++
|
||||
count.y++
|
||||
}
|
||||
done = end
|
||||
}
|
||||
|
||||
return out.Bytes()
|
||||
}
|
||||
|
||||
// lines returns the lines in the file x, including newlines.
|
||||
// If the file does not end in a newline, one is supplied
|
||||
// along with a warning about the missing newline.
|
||||
func lines(x []byte) []string {
|
||||
l := strings.SplitAfter(string(x), "\n")
|
||||
if l[len(l)-1] == "" {
|
||||
l = l[:len(l)-1]
|
||||
} else {
|
||||
// Treat last line as having a message about the missing newline attached,
|
||||
// using the same text as BSD/GNU diff (including the leading backslash).
|
||||
l[len(l)-1] += "\n\\ No newline at end of file\n"
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// tgs returns the pairs of indexes of the longest common subsequence
|
||||
// of unique lines in x and y, where a unique line is one that appears
|
||||
// once in x and once in y.
|
||||
//
|
||||
// The longest common subsequence algorithm is as described in
|
||||
// Thomas G. Szymanski, “A Special Case of the Maximal Common
|
||||
// Subsequence Problem,” Princeton TR #170 (January 1975),
|
||||
// available at https://research.swtch.com/tgs170.pdf.
|
||||
func tgs(x, y []string) []pair {
|
||||
// Count the number of times each string appears in a and b.
|
||||
// We only care about 0, 1, many, counted as 0, -1, -2
|
||||
// for the x side and 0, -4, -8 for the y side.
|
||||
// Using negative numbers now lets us distinguish positive line numbers later.
|
||||
m := make(map[string]int)
|
||||
for _, s := range x {
|
||||
if c := m[s]; c > -2 {
|
||||
m[s] = c - 1
|
||||
}
|
||||
}
|
||||
for _, s := range y {
|
||||
if c := m[s]; c > -8 {
|
||||
m[s] = c - 4
|
||||
}
|
||||
}
|
||||
|
||||
// Now unique strings can be identified by m[s] = -1+-4.
|
||||
//
|
||||
// Gather the indexes of those strings in x and y, building:
|
||||
// xi[i] = increasing indexes of unique strings in x.
|
||||
// yi[i] = increasing indexes of unique strings in y.
|
||||
// inv[i] = index j such that x[xi[i]] = y[yi[j]].
|
||||
var xi, yi, inv []int
|
||||
for i, s := range y {
|
||||
if m[s] == -1+-4 {
|
||||
m[s] = len(yi)
|
||||
yi = append(yi, i)
|
||||
}
|
||||
}
|
||||
for i, s := range x {
|
||||
if j, ok := m[s]; ok && j >= 0 {
|
||||
xi = append(xi, i)
|
||||
inv = append(inv, j)
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Algorithm A from Szymanski's paper.
|
||||
// In those terms, A = J = inv and B = [0, n).
|
||||
// We add sentinel pairs {0,0}, and {len(x),len(y)}
|
||||
// to the returned sequence, to help the processing loop.
|
||||
J := inv
|
||||
n := len(xi)
|
||||
T := make([]int, n)
|
||||
L := make([]int, n)
|
||||
for i := range T {
|
||||
T[i] = n + 1
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
k := sort.Search(n, func(k int) bool {
|
||||
return T[k] >= J[i]
|
||||
})
|
||||
T[k] = J[i]
|
||||
L[i] = k + 1
|
||||
}
|
||||
k := 0
|
||||
for _, v := range L {
|
||||
if k < v {
|
||||
k = v
|
||||
}
|
||||
}
|
||||
seq := make([]pair, 2+k)
|
||||
seq[1+k] = pair{len(x), len(y)} // sentinel at end
|
||||
lastj := n
|
||||
for i := n - 1; i >= 0; i-- {
|
||||
if L[i] == k && J[i] < lastj {
|
||||
seq[k] = pair{xi[i], yi[J[i]]}
|
||||
k--
|
||||
}
|
||||
}
|
||||
seq[0] = pair{0, 0} // sentinel at start
|
||||
return seq
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"github.com/tinygo-org/tinygo/diagnostics"
|
||||
)
|
||||
|
||||
// Test the error messages of the TinyGo compiler.
|
||||
func TestErrors(t *testing.T) {
|
||||
for _, name := range []string{
|
||||
"cgo",
|
||||
"compiler",
|
||||
"interp",
|
||||
"loader-importcycle",
|
||||
"loader-invaliddep",
|
||||
"loader-invalidpackage",
|
||||
"loader-nopackage",
|
||||
"optimizer",
|
||||
"syntax",
|
||||
"types",
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
testErrorMessages(t, "./testdata/errors/"+name+".go")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testErrorMessages(t *testing.T, filename string) {
|
||||
// Parse expected error messages.
|
||||
expected := readErrorMessages(t, filename)
|
||||
|
||||
// Try to build a binary (this should fail with an error).
|
||||
tmpdir := t.TempDir()
|
||||
err := Build(filename, tmpdir+"/out", &compileopts.Options{
|
||||
Target: "wasip1",
|
||||
Semaphore: sema,
|
||||
InterpTimeout: 180 * time.Second,
|
||||
Debug: true,
|
||||
VerifyIR: true,
|
||||
Opt: "z",
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected to get a compiler error")
|
||||
}
|
||||
|
||||
// Get the full ./testdata/errors directory.
|
||||
wd, absErr := filepath.Abs("testdata/errors")
|
||||
if absErr != nil {
|
||||
t.Fatal(absErr)
|
||||
}
|
||||
|
||||
// Write error message out as plain text.
|
||||
var buf bytes.Buffer
|
||||
diagnostics.CreateDiagnostics(err).WriteTo(&buf, wd)
|
||||
actual := strings.TrimRight(buf.String(), "\n")
|
||||
|
||||
// Check whether the error is as expected.
|
||||
if !matchErrors(t, expected, actual) {
|
||||
t.Errorf("expected error:\n%s\ngot:\n%s", indentText(expected, "> "), indentText(actual, "> "))
|
||||
}
|
||||
}
|
||||
|
||||
func matchErrors(t *testing.T, pattern, actual string) bool {
|
||||
patternLines := strings.Split(pattern, "\n")
|
||||
actualLines := strings.Split(actual, "\n")
|
||||
if len(patternLines) != len(actualLines) {
|
||||
return false
|
||||
}
|
||||
for i, patternLine := range patternLines {
|
||||
indices := regexp.MustCompile(`\{\{.*?\}\}`).FindAllStringIndex(patternLine, -1)
|
||||
patternParts := []string{"^"}
|
||||
lastStop := 0
|
||||
for _, startstop := range indices {
|
||||
start := startstop[0]
|
||||
stop := startstop[1]
|
||||
patternParts = append(patternParts,
|
||||
regexp.QuoteMeta(patternLine[lastStop:start]),
|
||||
patternLine[start+2:stop-2])
|
||||
lastStop = stop
|
||||
}
|
||||
patternParts = append(patternParts, regexp.QuoteMeta(patternLine[lastStop:]), "$")
|
||||
pattern := strings.Join(patternParts, "")
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
t.Fatalf("could not compile regexp for %#v: %v", patternLine, err)
|
||||
}
|
||||
if !re.MatchString(actualLines[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Indent the given text with a given indentation string.
|
||||
func indentText(text, indent string) string {
|
||||
return indent + strings.ReplaceAll(text, "\n", "\n"+indent)
|
||||
}
|
||||
|
||||
// Read "// ERROR:" prefixed messages from the given file.
|
||||
func readErrorMessages(t *testing.T, file string) string {
|
||||
data, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
t.Fatal("could not read input file:", err)
|
||||
}
|
||||
|
||||
var errors []string
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
if strings.HasPrefix(line, "// ERROR: ") {
|
||||
errors = append(errors, strings.TrimRight(line[len("// ERROR: "):], "\r\n"))
|
||||
}
|
||||
}
|
||||
return strings.Join(errors, "\n")
|
||||
}
|
||||
Generated
+4
-4
@@ -20,16 +20,16 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1696983906,
|
||||
"narHash": "sha256-L7GyeErguS7Pg4h8nK0wGlcUTbfUMDu+HMf1UcyP72k=",
|
||||
"lastModified": 1703068421,
|
||||
"narHash": "sha256-WSw5Faqlw75McIflnl5v7qVD/B3S2sLh+968bpOGrWA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "bd1cde45c77891214131cbbea5b1203e485a9d51",
|
||||
"rev": "d65bceaee0fb1e64363f7871bc43dc1c6ecad99f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-23.05",
|
||||
"ref": "nixos-23.11",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
#
|
||||
# But you'll need a bit more to make TinyGo actually able to compile code:
|
||||
#
|
||||
# make llvm-source # fetch compiler-rt
|
||||
# git submodule update --init --recursive # fetch lots of other libraries and SVD files
|
||||
# make gen-device -j4 # build src/device/*/*.go files
|
||||
# make wasi-libc # build support for wasi/wasm
|
||||
# make llvm-source # fetch compiler-rt
|
||||
# git submodule update --init # fetch lots of other libraries and SVD files
|
||||
# make gen-device -j4 # build src/device/*/*.go files
|
||||
# make wasi-libc # build support for wasi/wasm
|
||||
#
|
||||
# With this, you should have an environment that can compile anything - except
|
||||
# for the Xtensa architecture (ESP8266/ESP32) because support for that lives in
|
||||
@@ -35,7 +35,7 @@
|
||||
inputs = {
|
||||
# Use a recent stable release, but fix the version to make it reproducible.
|
||||
# This version should be updated from time to time.
|
||||
nixpkgs.url = "nixpkgs/nixos-23.05";
|
||||
nixpkgs.url = "nixpkgs/nixos-23.11";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
@@ -49,11 +49,11 @@
|
||||
buildInputs = [
|
||||
# These dependencies are required for building tinygo (go install).
|
||||
go
|
||||
llvmPackages_16.llvm
|
||||
llvmPackages_16.libclang
|
||||
llvmPackages_17.llvm
|
||||
llvmPackages_17.libclang
|
||||
# Additional dependencies needed at runtime, for building and/or
|
||||
# flashing.
|
||||
llvmPackages_16.lld
|
||||
llvmPackages_17.lld
|
||||
avrdude
|
||||
binaryen
|
||||
# Additional dependencies needed for on-chip debugging.
|
||||
@@ -68,7 +68,7 @@
|
||||
# Without setting these explicitly, Homebrew versions might be used
|
||||
# or the default `ar` and `nm` tools might be used (which don't
|
||||
# support wasi).
|
||||
export CLANG="clang-16 -resource-dir ${llvmPackages_16.clang.cc.lib}/lib/clang/16"
|
||||
export CLANG="clang-17 -resource-dir ${llvmPackages_17.clang.cc.lib}/lib/clang/17"
|
||||
export LLVM_AR=llvm-ar
|
||||
export LLVM_NM=llvm-nm
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
export MD5SUM=md5sum
|
||||
|
||||
# Ugly hack to make the Clang resources directory available.
|
||||
export GOFLAGS="\"-ldflags=-X github.com/tinygo-org/tinygo/goenv.clangResourceDir=${llvmPackages_16.clang.cc.lib}/lib/clang/16"\"
|
||||
export GOFLAGS="\"-ldflags=-X github.com/tinygo-org/tinygo/goenv.clangResourceDir=${llvmPackages_17.clang.cc.lib}/lib/clang/17\" -tags=llvm17"
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,33 +1,47 @@
|
||||
module github.com/tinygo-org/tinygo
|
||||
|
||||
go 1.18
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20220616010729-4a0a888aebdc
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c
|
||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
|
||||
github.com/chromedp/chromedp v0.7.6
|
||||
github.com/client9/misspell v0.3.4
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
|
||||
github.com/mattn/go-colorable v0.1.8
|
||||
github.com/mattn/go-colorable v0.1.13
|
||||
github.com/mattn/go-tty v0.0.4
|
||||
github.com/mgechev/revive v1.3.7
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
||||
go.bug.st/serial v1.6.0
|
||||
golang.org/x/sys v0.11.0
|
||||
golang.org/x/tools v0.12.0
|
||||
golang.org/x/net v0.26.0
|
||||
golang.org/x/sys v0.21.0
|
||||
golang.org/x/tools v0.22.1-0.20240621165957-db513b091504
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
tinygo.org/x/go-llvm v0.0.0-20231014233752-75a8a9fe6f74
|
||||
tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||
github.com/chavacava/garif v0.1.0 // indirect
|
||||
github.com/chromedp/sysutil v1.0.0 // indirect
|
||||
github.com/creack/goselect v0.1.2 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/fatih/structtag v1.2.0 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20220616010729-4a0a888aebdc h1:Yp49g+qqgQRPk/gcRSmAsXgnT16XPJ6Y5JM1poc6gYM=
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20220616010729-4a0a888aebdc/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c h1:4T0Vj1UkGgcpkRrmn7SbokebnlfxJcMZPgWtOYACAAA=
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20240312204833-50275154210c/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/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
|
||||
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
|
||||
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=
|
||||
@@ -9,9 +13,17 @@ github.com/chromedp/chromedp v0.7.6 h1:2juGaktzjwULlsn+DnvIZXFUckEp5xs+GOBroaea+
|
||||
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/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
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/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
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=
|
||||
@@ -31,39 +43,68 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
|
||||
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.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
|
||||
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
|
||||
github.com/mgechev/revive v1.3.7 h1:502QY0vQGe9KtYJ9FpxMz9rL+Fc/P13CI5POL4uHCcE=
|
||||
github.com/mgechev/revive v1.3.7/go.mod h1:RJ16jUbF0OWC3co/+XTxmFNgEpUPwnnA0BRllX2aDNA=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
|
||||
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
|
||||
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/tools v0.22.1-0.20240621165957-db513b091504 h1:MMsD8mMfluf/578+3wrTn22pjI/Xkzm+gPW47SYfspY=
|
||||
golang.org/x/tools v0.22.1-0.20240621165957-db513b091504/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
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.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
tinygo.org/x/go-llvm v0.0.0-20231014233752-75a8a9fe6f74 h1:tW8XhLI9gUZLL+2pG0HYb5dc6bpMj1aqtESpizXPnMY=
|
||||
tinygo.org/x/go-llvm v0.0.0-20231014233752-75a8a9fe6f74/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8 h1:bLsZXRUBavt++CJlMN7sppNziqu3LyamESLhFJcpqFQ=
|
||||
tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||
|
||||
+7
-5
@@ -142,11 +142,8 @@ func Get(name string) string {
|
||||
}
|
||||
return filepath.Join(dir, "tinygo")
|
||||
case "CGO_ENABLED":
|
||||
val := os.Getenv("CGO_ENABLED")
|
||||
if val == "1" || val == "0" {
|
||||
return val
|
||||
}
|
||||
// Default to enabling CGo.
|
||||
// Always enable CGo. It is required by a number of targets, including
|
||||
// macOS and the rp2040.
|
||||
return "1"
|
||||
case "TINYGOROOT":
|
||||
return sourceDir()
|
||||
@@ -162,6 +159,11 @@ func Get(name string) string {
|
||||
}
|
||||
|
||||
return findWasmOpt()
|
||||
case "WASMTOOLS":
|
||||
if path := os.Getenv("WASMTOOLS"); path != "" {
|
||||
return path
|
||||
}
|
||||
return "wasm-tools"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
// Version of TinyGo.
|
||||
// Update this value before release of new version of software.
|
||||
const version = "0.31.0-dev"
|
||||
const version = "0.33.0-dev"
|
||||
|
||||
var (
|
||||
// This variable is set at build time using -ldflags parameters.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
# Docker hub does a recursive clone, then checks the branch out,
|
||||
# so when a PR adds a submodule (or updates it), it fails.
|
||||
git submodule update --init --recursive
|
||||
git submodule update --init
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
//go:build tools
|
||||
|
||||
// Install tools specified in go.mod.
|
||||
// See https://marcofranssen.nl/manage-go-tools-via-go-modules for idiom.
|
||||
package tools
|
||||
|
||||
import (
|
||||
_ "github.com/client9/misspell"
|
||||
_ "github.com/mgechev/revive"
|
||||
)
|
||||
|
||||
//go:generate go install github.com/client9/misspell/cmd/misspell
|
||||
//go:generate go install github.com/mgechev/revive
|
||||
@@ -0,0 +1,5 @@
|
||||
# wasm-tools directory
|
||||
|
||||
This directory has a separate `go.mod` file because the `wasm-tools-go` module requires Go 1.22, while TinyGo itself supports Go 1.19.
|
||||
|
||||
When the minimum Go version for TinyGo is 1.22, this directory can be folded into `internal/tools` and the `go.mod` and `go.sum` files deleted.
|
||||
@@ -0,0 +1,12 @@
|
||||
module github.com/tinygo-org/tinygo/internal/tools
|
||||
|
||||
go 1.22.4
|
||||
|
||||
require github.com/ydnar/wasm-tools-go v0.1.4
|
||||
|
||||
require (
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/urfave/cli/v3 v3.0.0-alpha9 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
golang.org/x/mod v0.19.0 // indirect
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/urfave/cli/v3 v3.0.0-alpha9 h1:P0RMy5fQm1AslQS+XCmy9UknDXctOmG/q/FZkUFnJSo=
|
||||
github.com/urfave/cli/v3 v3.0.0-alpha9/go.mod h1:0kK/RUFHyh+yIKSfWxwheGndfnrvYSmYFVeKCh03ZUc=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/ydnar/wasm-tools-go v0.1.4 h1:+25WqBj0AhLx8OFvZvrs7bQO6L3WtQ7t6JzQEYsXQb8=
|
||||
github.com/ydnar/wasm-tools-go v0.1.4/go.mod h1:lQfv2Tde3tRgZDSYriro0EmdSHzP1mrHPMmYNahSS/g=
|
||||
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -0,0 +1,11 @@
|
||||
//go:build tools
|
||||
|
||||
// Install tools specified in go.mod.
|
||||
// See https://marcofranssen.nl/manage-go-tools-via-go-modules for idiom.
|
||||
package tools
|
||||
|
||||
import (
|
||||
_ "github.com/ydnar/wasm-tools-go/cmd/wit-bindgen-go"
|
||||
)
|
||||
|
||||
//go:generate go install github.com/ydnar/wasm-tools-go/cmd/wit-bindgen-go
|
||||
+26
-52
@@ -239,7 +239,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
// already be emitted in initAll.
|
||||
continue
|
||||
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet" || callFn.name == "runtime.hashmapInterfaceHash" ||
|
||||
callFn.name == "os.runtime_args" || callFn.name == "internal/task.start" || callFn.name == "internal/task.Current":
|
||||
callFn.name == "os.runtime_args" || callFn.name == "internal/task.start" || callFn.name == "internal/task.Current" ||
|
||||
callFn.name == "time.startTimer" || callFn.name == "time.stopTimer" || callFn.name == "time.resetTimer":
|
||||
// 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.)
|
||||
@@ -252,6 +253,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
// at runtime.
|
||||
// * internal/task.start, internal/task.Current: start and read shcheduler state,
|
||||
// which is modified elsewhere.
|
||||
// * Timer functions access runtime internal state which may
|
||||
// not be initialized.
|
||||
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
||||
if err != nil {
|
||||
return nil, mem, err
|
||||
@@ -414,49 +417,10 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
} else {
|
||||
locals[inst.localIndex] = literalValue{uint8(0)}
|
||||
}
|
||||
case strings.HasSuffix(callFn.name, ".$typeassert"):
|
||||
if r.debug {
|
||||
fmt.Fprintln(os.Stderr, indent+"interface assert:", operands[1:])
|
||||
}
|
||||
|
||||
// Load various values for the interface implements check below.
|
||||
typecodePtr, err := operands[1].asPointer(r)
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
methodSetPtr, err := mem.load(typecodePtr.addOffset(-int64(r.pointerSize)), r.pointerSize).asPointer(r)
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
methodSet := mem.get(methodSetPtr.index()).llvmGlobal.Initializer()
|
||||
numMethods := int(r.builder.CreateExtractValue(methodSet, 0, "").ZExtValue())
|
||||
llvmFn := inst.llvmInst.CalledValue()
|
||||
methodSetAttr := llvmFn.GetStringAttributeAtIndex(-1, "tinygo-methods")
|
||||
methodSetString := methodSetAttr.GetStringValue()
|
||||
|
||||
// Make a set of all the methods on the concrete type, for
|
||||
// easier checking in the next step.
|
||||
concreteTypeMethods := map[string]struct{}{}
|
||||
for i := 0; i < numMethods; i++ {
|
||||
methodInfo := r.builder.CreateExtractValue(methodSet, 1, "")
|
||||
name := r.builder.CreateExtractValue(methodInfo, i, "").Name()
|
||||
concreteTypeMethods[name] = struct{}{}
|
||||
}
|
||||
|
||||
// Check whether all interface methods are also in the list
|
||||
// of defined methods calculated above. This is the interface
|
||||
// assert itself.
|
||||
assertOk := uint8(1) // i1 true
|
||||
for _, name := range strings.Split(methodSetString, "; ") {
|
||||
if _, ok := concreteTypeMethods[name]; !ok {
|
||||
// There is a method on the interface that is not
|
||||
// implemented by the type. The assertion will fail.
|
||||
assertOk = 0 // i1 false
|
||||
break
|
||||
}
|
||||
}
|
||||
// If assertOk is still 1, the assertion succeeded.
|
||||
locals[inst.localIndex] = literalValue{assertOk}
|
||||
case callFn.name == "__tinygo_interp_raise_test_error":
|
||||
// Special function that will trigger an error.
|
||||
// This is used to test error reporting.
|
||||
return nil, mem, r.errorAt(inst, errors.New("test error"))
|
||||
case strings.HasSuffix(callFn.name, "$invoke"):
|
||||
// This thunk is the interface method dispatcher: it is called
|
||||
// with all regular parameters and a type code. It will then
|
||||
@@ -470,7 +434,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
methodSetPtr, err := mem.load(typecodePtr.addOffset(-int64(r.pointerSize)), r.pointerSize).asPointer(r)
|
||||
typecodePtrOffset, err := typecodePtr.addOffset(-int64(r.pointerSize))
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
methodSetPtr, err := mem.load(typecodePtrOffset, r.pointerSize).asPointer(r)
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
@@ -633,11 +601,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
case llvm.GetElementPtr:
|
||||
// GetElementPtr does pointer arithmetic, changing the offset of the
|
||||
// pointer into the underlying object.
|
||||
var offset uint64
|
||||
var offset int64
|
||||
for i := 1; i < len(operands); i += 2 {
|
||||
index := operands[i].Uint()
|
||||
elementSize := operands[i+1].Uint()
|
||||
if int64(elementSize) < 0 {
|
||||
index := operands[i].Int()
|
||||
elementSize := operands[i+1].Int()
|
||||
if elementSize < 0 {
|
||||
// This is a struct field.
|
||||
offset += index
|
||||
} else {
|
||||
@@ -651,11 +619,14 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
// GEP on fixed pointer value (for example, memory-mapped I/O).
|
||||
ptrValue := operands[0].Uint() + offset
|
||||
ptrValue := operands[0].Uint() + uint64(offset)
|
||||
locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
|
||||
continue
|
||||
}
|
||||
ptr = ptr.addOffset(int64(offset))
|
||||
ptr, err = ptr.addOffset(int64(offset))
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
locals[inst.localIndex] = ptr
|
||||
if r.debug {
|
||||
fmt.Fprintln(os.Stderr, indent+"gep:", operands, "->", ptr)
|
||||
@@ -753,7 +724,10 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
if inst.opcode == llvm.Add {
|
||||
// This likely means this is part of a
|
||||
// unsafe.Pointer(uintptr(ptr) + offset) pattern.
|
||||
lhsPtr = lhsPtr.addOffset(int64(rhs.Uint()))
|
||||
lhsPtr, err = lhsPtr.addOffset(int64(rhs.Uint()))
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
locals[inst.localIndex] = lhsPtr
|
||||
} else if inst.opcode == llvm.Xor && rhs.Uint() == 0 {
|
||||
// Special workaround for strings.noescape, see
|
||||
|
||||
+3
-3
@@ -517,12 +517,12 @@ func (v pointerValue) offset() uint32 {
|
||||
// addOffset essentially does a GEP operation (pointer arithmetic): it adds the
|
||||
// offset to the pointer. It also checks that the offset doesn't overflow the
|
||||
// maximum offset size (which is 4GB).
|
||||
func (v pointerValue) addOffset(offset int64) pointerValue {
|
||||
func (v pointerValue) addOffset(offset int64) (pointerValue, error) {
|
||||
result := pointerValue{v.pointer + uint64(offset)}
|
||||
if checks && v.index() != result.index() {
|
||||
panic("interp: offset out of range")
|
||||
return result, fmt.Errorf("interp: offset %d out of range for object %v", offset, v)
|
||||
}
|
||||
return result
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (v pointerValue) len(r *runner) uint32 {
|
||||
|
||||
Vendored
+7
@@ -10,6 +10,8 @@ target triple = "x86_64--linux"
|
||||
@main.exposedValue1 = global i16 0
|
||||
@main.exposedValue2 = global i16 0
|
||||
@main.insertedValue = global {i8, i32, {float, {i64, i16}}} zeroinitializer
|
||||
@main.gepArray = global [8 x i8] zeroinitializer
|
||||
@main.negativeGEP = global ptr null
|
||||
|
||||
declare void @runtime.printint64(i64) unnamed_addr
|
||||
|
||||
@@ -88,6 +90,11 @@ entry:
|
||||
%agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0
|
||||
store {i8, i32, {float, {i64, i16}}} %agg2, ptr @main.insertedValue
|
||||
|
||||
; negative GEP instruction
|
||||
%ngep1 = getelementptr [8 x i8], ptr @main.negativeGEP, i32 0, i32 5
|
||||
%ngep2 = getelementptr [8 x i8], ptr %ngep1, i32 0, i32 -3
|
||||
store ptr %ngep2, ptr @main.negativeGEP
|
||||
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
Vendored
+2
@@ -9,6 +9,8 @@ target triple = "x86_64--linux"
|
||||
@main.exposedValue1 = global i16 0
|
||||
@main.exposedValue2 = local_unnamed_addr global i16 0
|
||||
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
|
||||
@main.gepArray = local_unnamed_addr global [8 x i8] zeroinitializer
|
||||
@main.negativeGEP = global ptr getelementptr inbounds (i8, ptr @main.negativeGEP, i64 2)
|
||||
|
||||
declare void @runtime.printint64(i64) unnamed_addr
|
||||
|
||||
|
||||
+1
-1
Submodule lib/cmsis-svd updated: df75ff974c...40327a4d2d
Submodule
+1
Submodule lib/wasi-cli added at 6ae8261709
+1
-1
Submodule lib/wasi-libc updated: 30094b6ed0...1dfe5c302d
+7
-1
@@ -214,7 +214,7 @@ func listGorootMergeLinks(goroot, tinygoroot string, overrides map[string]bool)
|
||||
return merges, nil
|
||||
}
|
||||
|
||||
// needsSyscallPackage returns whether the syscall package should be overriden
|
||||
// needsSyscallPackage returns whether the syscall package should be overridden
|
||||
// with the TinyGo version. This is the case on some targets.
|
||||
func needsSyscallPackage(buildTags []string) bool {
|
||||
for _, tag := range buildTags {
|
||||
@@ -232,16 +232,22 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
|
||||
"": true,
|
||||
"crypto/": true,
|
||||
"crypto/rand/": false,
|
||||
"crypto/tls/": false,
|
||||
"device/": false,
|
||||
"examples/": false,
|
||||
"internal/": true,
|
||||
"internal/binary/": false,
|
||||
"internal/bytealg/": false,
|
||||
"internal/cm/": false,
|
||||
"internal/fuzz/": false,
|
||||
"internal/reflectlite/": false,
|
||||
"internal/task/": false,
|
||||
"internal/wasi/": false,
|
||||
"machine/": false,
|
||||
"net/": true,
|
||||
"net/http/": false,
|
||||
"os/": true,
|
||||
"os/user/": false,
|
||||
"reflect/": false,
|
||||
"runtime/": false,
|
||||
"sync/": true,
|
||||
|
||||
+1
-5
@@ -22,12 +22,8 @@ func List(config *compileopts.Config, extraArgs, pkgs []string) (*exec.Cmd, erro
|
||||
args = append(args, "-tags", strings.Join(config.BuildTags(), " "))
|
||||
}
|
||||
args = append(args, pkgs...)
|
||||
cgoEnabled := "0"
|
||||
if config.CgoEnabled() {
|
||||
cgoEnabled = "1"
|
||||
}
|
||||
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)
|
||||
cmd.Env = append(os.Environ(), "GOROOT="+goroot, "GOOS="+config.GOOS(), "GOARCH="+config.GOARCH(), "CGO_ENABLED=1")
|
||||
if config.Options.Directory != "" {
|
||||
cmd.Dir = config.Options.Directory
|
||||
}
|
||||
|
||||
+40
-5
@@ -27,6 +27,8 @@ import (
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
)
|
||||
|
||||
var initFileVersions = func(info *types.Info) {}
|
||||
|
||||
// Program holds all packages and some metadata about the program as a whole.
|
||||
type Program struct {
|
||||
config *compileopts.Config
|
||||
@@ -126,7 +128,7 @@ func Load(config *compileopts.Config, inputPkg string, typeChecker types.Config)
|
||||
}
|
||||
|
||||
// List the dependencies of this package, in raw JSON format.
|
||||
extraArgs := []string{"-json", "-deps"}
|
||||
extraArgs := []string{"-json", "-deps", "-e"}
|
||||
if config.TestConfig.CompileTestBinary {
|
||||
extraArgs = append(extraArgs, "-test")
|
||||
}
|
||||
@@ -147,6 +149,7 @@ func Load(config *compileopts.Config, inputPkg string, typeChecker types.Config)
|
||||
|
||||
// Parse the returned json from `go list`.
|
||||
decoder := json.NewDecoder(buf)
|
||||
var pkgErrors []error
|
||||
for {
|
||||
pkg := &Package{
|
||||
program: p,
|
||||
@@ -186,6 +189,12 @@ func Load(config *compileopts.Config, inputPkg string, typeChecker types.Config)
|
||||
pos.Filename = strings.Join(fields[:len(fields)-1], ":")
|
||||
pos.Line, _ = strconv.Atoi(fields[len(fields)-1])
|
||||
}
|
||||
if abs, err := filepath.Abs(pos.Filename); err == nil {
|
||||
// Make the path absolute, so that error messages will be
|
||||
// prettier (it will be turned back into a relative path
|
||||
// when printing the error).
|
||||
pos.Filename = abs
|
||||
}
|
||||
pos.Filename = p.getOriginalPath(pos.Filename)
|
||||
}
|
||||
err := scanner.Error{
|
||||
@@ -193,10 +202,11 @@ func Load(config *compileopts.Config, inputPkg string, typeChecker types.Config)
|
||||
Msg: pkg.Error.Err,
|
||||
}
|
||||
if len(pkg.Error.ImportStack) != 0 {
|
||||
return nil, Error{
|
||||
pkgErrors = append(pkgErrors, Error{
|
||||
ImportStack: pkg.Error.ImportStack,
|
||||
Err: err,
|
||||
}
|
||||
})
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
@@ -239,6 +249,13 @@ func Load(config *compileopts.Config, inputPkg string, typeChecker types.Config)
|
||||
p.Packages[pkg.ImportPath] = pkg
|
||||
}
|
||||
|
||||
if len(pkgErrors) != 0 {
|
||||
// TODO: use errors.Join in Go 1.20.
|
||||
return nil, Errors{
|
||||
Errs: pkgErrors,
|
||||
}
|
||||
}
|
||||
|
||||
if config.TestConfig.CompileTestBinary && !strings.HasSuffix(p.sorted[len(p.sorted)-1].ImportPath, ".test") {
|
||||
// Trying to compile a test binary but there are no test files in this
|
||||
// package.
|
||||
@@ -378,6 +395,24 @@ func (p *Package) Check() error {
|
||||
typeErrors = append(typeErrors, err)
|
||||
}
|
||||
checker.Importer = p
|
||||
if p.Module.GoVersion != "" {
|
||||
// Setting the Go version for a module makes sure the type checker
|
||||
// errors out on language features not supported in that particular
|
||||
// version.
|
||||
checker.GoVersion = "go" + p.Module.GoVersion
|
||||
} else {
|
||||
// Version is not known, so use the currently installed Go version.
|
||||
// This is needed for `tinygo run` for example.
|
||||
// Normally we'd use goenv.GorootVersionString(), but for compatibility
|
||||
// with Go 1.20 and below we need a version in the form of "go1.12" (no
|
||||
// patch version).
|
||||
major, minor, err := goenv.GetGorootVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
checker.GoVersion = fmt.Sprintf("go%d.%d", major, minor)
|
||||
}
|
||||
initFileVersions(&p.info)
|
||||
|
||||
// Do typechecking of the package.
|
||||
packageName := p.ImportPath
|
||||
@@ -410,7 +445,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
||||
var files []*ast.File
|
||||
var fileErrs []error
|
||||
|
||||
// Parse all files (incuding CgoFiles).
|
||||
// Parse all files (including CgoFiles).
|
||||
parseFile := func(file string) {
|
||||
if !filepath.IsAbs(file) {
|
||||
file = filepath.Join(p.Dir, file)
|
||||
@@ -447,7 +482,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
||||
if errs != nil {
|
||||
fileErrs = append(fileErrs, errs...)
|
||||
}
|
||||
files = append(files, generated)
|
||||
files = append(files, generated...)
|
||||
p.program.LDFlags = append(p.program.LDFlags, ldflags...)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
//go:build go1.22
|
||||
|
||||
// types.Info.FileVersions was added in Go 1.22, so we can only initialize it
|
||||
// when built with Go 1.22.
|
||||
|
||||
package loader
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
initFileVersions = func(info *types.Info) {
|
||||
info.FileVersions = make(map[*ast.File]string)
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,6 @@ import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/scanner"
|
||||
"go/types"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -30,8 +28,8 @@ import (
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/tinygo-org/tinygo/builder"
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"github.com/tinygo-org/tinygo/diagnostics"
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
"github.com/tinygo-org/tinygo/interp"
|
||||
"github.com/tinygo-org/tinygo/loader"
|
||||
"golang.org/x/tools/go/buildutil"
|
||||
"tinygo.org/x/go-llvm"
|
||||
@@ -285,7 +283,7 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
// Tests are always run in the package directory.
|
||||
cmd.Dir = result.MainDir
|
||||
|
||||
// wasmtime is the default emulator used for `-target=wasi`. wasmtime
|
||||
// wasmtime is the default emulator used for `-target=wasip1`. wasmtime
|
||||
// is a WebAssembly runtime CLI with WASI enabled by default. However,
|
||||
// only stdio are allowed by default. For example, while STDOUT routes
|
||||
// to the host, other files don't. It also does not inherit environment
|
||||
@@ -306,16 +304,25 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
// reads any files.
|
||||
//
|
||||
// Ex. run --dir=.. --dir=../.. --dir=../../..
|
||||
dirs := dirsToModuleRoot(result.MainDir, result.ModuleRoot)
|
||||
var dirs []string
|
||||
switch config.Options.Target {
|
||||
case "wasip1":
|
||||
dirs = dirsToModuleRootRel(result.MainDir, result.ModuleRoot)
|
||||
case "wasip2":
|
||||
dirs = dirsToModuleRootAbs(result.MainDir, result.ModuleRoot)
|
||||
default:
|
||||
return fmt.Errorf("unknown GOOS target: %v", config.Options.Target)
|
||||
}
|
||||
|
||||
args := []string{"run"}
|
||||
for _, d := range dirs[1:] {
|
||||
for _, d := range dirs {
|
||||
args = append(args, "--dir="+d)
|
||||
}
|
||||
|
||||
// The below re-organizes the arguments so that the current
|
||||
// directory is added last.
|
||||
args = append(args, "--env=PWD="+cmd.Dir)
|
||||
|
||||
args = append(args, cmd.Args[1:]...)
|
||||
cmd.Args = append(cmd.Args[:1:1], args...)
|
||||
cmd.Args = args
|
||||
}
|
||||
|
||||
// Run the test.
|
||||
@@ -338,6 +345,11 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
}
|
||||
return err
|
||||
})
|
||||
|
||||
if testConfig.CompileOnly {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
importPath := strings.TrimSuffix(result.ImportPath, ".test")
|
||||
|
||||
var w io.Writer = stdout
|
||||
@@ -348,7 +360,7 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
fmt.Fprintf(w, "? \t%s\t[no test files]\n", err.ImportPath)
|
||||
// Pretend the test passed - it at least didn't fail.
|
||||
return true, nil
|
||||
} else if passed && !testConfig.CompileOnly {
|
||||
} else if passed {
|
||||
fmt.Fprintf(w, "ok \t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
} else {
|
||||
fmt.Fprintf(w, "FAIL\t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
@@ -356,8 +368,8 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
return passed, err
|
||||
}
|
||||
|
||||
func dirsToModuleRoot(maindir, modroot string) []string {
|
||||
var dirs = []string{"."}
|
||||
func dirsToModuleRootRel(maindir, modroot string) []string {
|
||||
var dirs []string
|
||||
last := ".."
|
||||
// strip off path elements until we hit the module root
|
||||
// adding `..`, `../..`, `../../..` until we're done
|
||||
@@ -366,6 +378,20 @@ func dirsToModuleRoot(maindir, modroot string) []string {
|
||||
last = filepath.Join(last, "..")
|
||||
maindir = filepath.Dir(maindir)
|
||||
}
|
||||
dirs = append(dirs, ".")
|
||||
return dirs
|
||||
}
|
||||
|
||||
func dirsToModuleRootAbs(maindir, modroot string) []string {
|
||||
var dirs = []string{maindir}
|
||||
last := filepath.Join(maindir, "..")
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -532,7 +558,7 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
return fmt.Errorf("unknown flash method: %s", flashMethod)
|
||||
}
|
||||
if options.Monitor {
|
||||
return Monitor(result.Executable, "", options)
|
||||
return Monitor(result.Executable, "", config)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -785,6 +811,9 @@ func Run(pkgName string, options *compileopts.Options, cmdArgs []string) error {
|
||||
// passes command line arguments and evironment variables in a way appropriate
|
||||
// for the given emulator.
|
||||
func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, cmdArgs, environmentVars []string, timeout time.Duration, run func(cmd *exec.Cmd, result builder.BuildResult) error) (builder.BuildResult, error) {
|
||||
|
||||
isSingleFile := strings.HasSuffix(pkgName, ".go")
|
||||
|
||||
// Determine whether we're on a system that supports environment variables
|
||||
// and command line parameters (operating systems, WASI) or not (baremetal,
|
||||
// WebAssembly in the browser). If we're on a system without an environment,
|
||||
@@ -818,9 +847,6 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
}
|
||||
}
|
||||
} else if config.EmulatorName() == "wasmtime" {
|
||||
// Wasmtime needs some special flags to pass environment variables
|
||||
// and allow reading from the current directory.
|
||||
emuArgs = append(emuArgs, "--dir=.")
|
||||
for _, v := range environmentVars {
|
||||
emuArgs = append(emuArgs, "--env", v)
|
||||
}
|
||||
@@ -876,7 +902,26 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
name = emulator[0]
|
||||
|
||||
if name == "wasmtime" {
|
||||
// Wasmtime needs some special flags to pass environment variables
|
||||
// and allow reading from the current directory.
|
||||
switch config.Options.Target {
|
||||
case "wasip1":
|
||||
emuArgs = append(emuArgs, "--dir=.")
|
||||
case "wasip2":
|
||||
dir := result.MainDir
|
||||
if isSingleFile {
|
||||
cwd, _ := os.Getwd()
|
||||
dir = cwd
|
||||
}
|
||||
emuArgs = append(emuArgs, "--dir="+dir)
|
||||
emuArgs = append(emuArgs, "--env=PWD="+dir)
|
||||
}
|
||||
}
|
||||
|
||||
emuArgs = append(emuArgs, emulator[1:]...)
|
||||
args = append(emuArgs, args...)
|
||||
}
|
||||
@@ -1030,12 +1075,14 @@ func findFATMounts(options *compileopts.Options) ([]mountPoint, error) {
|
||||
continue
|
||||
}
|
||||
fstype := fields[2]
|
||||
if fstype != "vfat" {
|
||||
// chromeos bind mounts use 9p
|
||||
if !(fstype == "vfat" || fstype == "9p") {
|
||||
continue
|
||||
}
|
||||
fspath := strings.ReplaceAll(fields[1], "\\040", " ")
|
||||
points = append(points, mountPoint{
|
||||
name: filepath.Base(fields[1]),
|
||||
path: fields[1],
|
||||
name: filepath.Base(fspath),
|
||||
path: fspath,
|
||||
})
|
||||
}
|
||||
return points, nil
|
||||
@@ -1225,6 +1272,7 @@ func usage(command string) {
|
||||
fmt.Fprintln(os.Stderr, " gdb: run/flash and immediately enter GDB")
|
||||
fmt.Fprintln(os.Stderr, " lldb: run/flash and immediately enter LLDB")
|
||||
fmt.Fprintln(os.Stderr, " monitor: open communication port")
|
||||
fmt.Fprintln(os.Stderr, " ports: list available serial ports")
|
||||
fmt.Fprintln(os.Stderr, " env: list environment variables used during build")
|
||||
fmt.Fprintln(os.Stderr, " list: run go list using the TinyGo root")
|
||||
fmt.Fprintln(os.Stderr, " clean: empty cache directory ("+goenv.Get("GOCACHE")+")")
|
||||
@@ -1242,83 +1290,13 @@ func usage(command string) {
|
||||
}
|
||||
}
|
||||
|
||||
// try to make the path relative to the current working directory. If any error
|
||||
// occurs, this error is ignored and the absolute path is returned instead.
|
||||
func tryToMakePathRelative(dir string) string {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return dir
|
||||
}
|
||||
relpath, err := filepath.Rel(wd, dir)
|
||||
if err != nil {
|
||||
return dir
|
||||
}
|
||||
return relpath
|
||||
}
|
||||
|
||||
// printCompilerError prints compiler errors using the provided logger function
|
||||
// (similar to fmt.Println).
|
||||
//
|
||||
// There is one exception: interp errors may print to stderr unconditionally due
|
||||
// to limitations in the LLVM bindings.
|
||||
func printCompilerError(logln func(...interface{}), err error) {
|
||||
switch err := err.(type) {
|
||||
case types.Error:
|
||||
printCompilerError(logln, scanner.Error{
|
||||
Pos: err.Fset.Position(err.Pos),
|
||||
Msg: err.Msg,
|
||||
})
|
||||
case scanner.Error:
|
||||
if !strings.HasPrefix(err.Pos.Filename, filepath.Join(goenv.Get("GOROOT"), "src")) && !strings.HasPrefix(err.Pos.Filename, filepath.Join(goenv.Get("TINYGOROOT"), "src")) {
|
||||
// This file is not from the standard library (either the GOROOT or
|
||||
// the TINYGOROOT). Make the path relative, for easier reading.
|
||||
// Ignore any errors in the process (falling back to the absolute
|
||||
// path).
|
||||
err.Pos.Filename = tryToMakePathRelative(err.Pos.Filename)
|
||||
}
|
||||
logln(err)
|
||||
case scanner.ErrorList:
|
||||
for _, scannerErr := range err {
|
||||
printCompilerError(logln, *scannerErr)
|
||||
}
|
||||
case *interp.Error:
|
||||
logln("#", err.ImportPath)
|
||||
logln(err.Error())
|
||||
if len(err.Inst) != 0 {
|
||||
logln(err.Inst)
|
||||
}
|
||||
if len(err.Traceback) > 0 {
|
||||
logln("\ntraceback:")
|
||||
for _, line := range err.Traceback {
|
||||
logln(line.Pos.String() + ":")
|
||||
logln(line.Inst)
|
||||
}
|
||||
}
|
||||
case loader.Errors:
|
||||
logln("#", err.Pkg.ImportPath)
|
||||
for _, err := range err.Errs {
|
||||
printCompilerError(logln, err)
|
||||
}
|
||||
case loader.Error:
|
||||
logln(err.Err.Error())
|
||||
logln("package", err.ImportStack[0])
|
||||
for _, pkgPath := range err.ImportStack[1:] {
|
||||
logln("\timports", pkgPath)
|
||||
}
|
||||
case *builder.MultiError:
|
||||
for _, err := range err.Errs {
|
||||
printCompilerError(logln, err)
|
||||
}
|
||||
default:
|
||||
logln("error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func handleCompilerError(err error) {
|
||||
if err != nil {
|
||||
printCompilerError(func(args ...interface{}) {
|
||||
fmt.Fprintln(os.Stderr, args...)
|
||||
}, err)
|
||||
wd, getwdErr := os.Getwd()
|
||||
if getwdErr != nil {
|
||||
wd = ""
|
||||
}
|
||||
diagnostics.CreateDiagnostics(err).WriteTo(os.Stderr, wd)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -1410,7 +1388,7 @@ func main() {
|
||||
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, tasks, asyncify)")
|
||||
serial := flag.String("serial", "", "which serial output to use (none, uart, usb)")
|
||||
serial := flag.String("serial", "", "which serial output to use (none, uart, usb, rtt)")
|
||||
work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit")
|
||||
interpTimeout := flag.Duration("interp-timeout", 180*time.Second, "interp optimization pass timeout")
|
||||
var tags buildutil.TagsFlag
|
||||
@@ -1437,7 +1415,6 @@ func main() {
|
||||
llvmFeatures := flag.String("llvm-features", "", "comma separated LLVM features to enable")
|
||||
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
|
||||
monitor := flag.Bool("monitor", false, "enable serial monitor")
|
||||
info := flag.Bool("info", false, "print information")
|
||||
baudrate := flag.Int("baudrate", 115200, "baudrate of serial monitor")
|
||||
|
||||
// Internal flags, that are only intended for TinyGo development.
|
||||
@@ -1464,6 +1441,12 @@ func main() {
|
||||
flag.StringVar(&outpath, "o", "", "output filename")
|
||||
}
|
||||
|
||||
var witPackage, witWorld string
|
||||
if command == "help" || command == "build" || command == "test" || command == "run" {
|
||||
flag.StringVar(&witPackage, "wit-package", "", "wit package for wasm component embedding")
|
||||
flag.StringVar(&witWorld, "wit-world", "", "wit world for wasm component embedding")
|
||||
}
|
||||
|
||||
var testConfig compileopts.TestConfig
|
||||
if command == "help" || command == "test" {
|
||||
flag.BoolVar(&testConfig.CompileOnly, "c", false, "compile the test binary but do not run it")
|
||||
@@ -1543,6 +1526,8 @@ func main() {
|
||||
Monitor: *monitor,
|
||||
BaudRate: *baudrate,
|
||||
Timeout: *timeout,
|
||||
WITPackage: witPackage,
|
||||
WITWorld: witWorld,
|
||||
}
|
||||
if *printCommands {
|
||||
options.PrintCommands = printCommand
|
||||
@@ -1713,9 +1698,11 @@ func main() {
|
||||
stderr := (*testStderr)(buf)
|
||||
passed, err := Test(pkgName, stdout, stderr, options, outpath)
|
||||
if err != nil {
|
||||
printCompilerError(func(args ...interface{}) {
|
||||
fmt.Fprintln(stderr, args...)
|
||||
}, err)
|
||||
wd, getwdErr := os.Getwd()
|
||||
if getwdErr != nil {
|
||||
wd = ""
|
||||
}
|
||||
diagnostics.CreateDiagnostics(err).WriteTo(os.Stderr, wd)
|
||||
}
|
||||
if !passed {
|
||||
select {
|
||||
@@ -1733,15 +1720,19 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
case "monitor":
|
||||
if *info {
|
||||
serialPortInfo, err := ListSerialPorts()
|
||||
handleCompilerError(err)
|
||||
for _, s := range serialPortInfo {
|
||||
fmt.Printf("%s %4s %4s %s\n", s.Name, s.VID, s.PID, s.Target)
|
||||
}
|
||||
} else {
|
||||
err := Monitor("", *port, options)
|
||||
handleCompilerError(err)
|
||||
config, err := builder.NewConfig(options)
|
||||
handleCompilerError(err)
|
||||
err = Monitor("", *port, config)
|
||||
handleCompilerError(err)
|
||||
case "ports":
|
||||
serialPortInfo, err := ListSerialPorts()
|
||||
handleCompilerError(err)
|
||||
if len(serialPortInfo) == 0 {
|
||||
fmt.Println("No serial ports found.")
|
||||
}
|
||||
fmt.Printf("%-20s %-9s %s\n", "Port", "ID", "Boards")
|
||||
for _, s := range serialPortInfo {
|
||||
fmt.Printf("%-20s %4s:%4s %s\n", s.Name, s.VID, s.PID, s.Target)
|
||||
}
|
||||
case "targets":
|
||||
specs, err := compileopts.GetTargetSpecs()
|
||||
|
||||
+106
-7
@@ -15,13 +15,16 @@ import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aykevl/go-wasm"
|
||||
"github.com/tinygo-org/tinygo/builder"
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"github.com/tinygo-org/tinygo/diagnostics"
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
)
|
||||
|
||||
@@ -34,6 +37,7 @@ var supportedLinuxArches = map[string]string{
|
||||
"X86Linux": "linux/386",
|
||||
"ARMLinux": "linux/arm/6",
|
||||
"ARM64Linux": "linux/arm64",
|
||||
"MIPSLinux": "linux/mipsle",
|
||||
"WASIp1": "wasip1/wasm",
|
||||
}
|
||||
|
||||
@@ -69,6 +73,7 @@ func TestBuild(t *testing.T) {
|
||||
"json.go",
|
||||
"map.go",
|
||||
"math.go",
|
||||
"oldgo/",
|
||||
"print.go",
|
||||
"reflect.go",
|
||||
"slice.go",
|
||||
@@ -90,6 +95,9 @@ func TestBuild(t *testing.T) {
|
||||
if minor >= 21 {
|
||||
tests = append(tests, "go1.21.go")
|
||||
}
|
||||
if minor >= 22 {
|
||||
tests = append(tests, "go1.22/")
|
||||
}
|
||||
|
||||
if *testTarget != "" {
|
||||
// This makes it possible to run one specific test (instead of all),
|
||||
@@ -173,7 +181,11 @@ func TestBuild(t *testing.T) {
|
||||
})
|
||||
t.Run("WASI", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
runPlatTests(optionsFromTarget("wasi", sema), tests, t)
|
||||
runPlatTests(optionsFromTarget("wasip1", sema), tests, t)
|
||||
})
|
||||
t.Run("WASIp2", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
runPlatTests(optionsFromTarget("wasip2", sema), tests, t)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -186,7 +198,10 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
t.Fatal("failed to load target spec:", err)
|
||||
}
|
||||
|
||||
isWebAssembly := options.Target == "wasi" || options.Target == "wasm" || (options.Target == "" && options.GOARCH == "wasm")
|
||||
// FIXME: this should really be:
|
||||
// isWebAssembly := strings.HasPrefix(spec.Triple, "wasm")
|
||||
isWASI := strings.HasPrefix(options.Target, "wasi")
|
||||
isWebAssembly := isWASI || strings.HasPrefix(options.Target, "wasm") || (options.Target == "" && strings.HasPrefix(options.GOARCH, "wasm"))
|
||||
|
||||
for _, name := range tests {
|
||||
if options.GOOS == "linux" && (options.GOARCH == "arm" || options.GOARCH == "386") {
|
||||
@@ -197,6 +212,12 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if options.GOOS == "linux" && (options.GOARCH == "mips" || options.GOARCH == "mipsle") {
|
||||
if name == "atomic.go" {
|
||||
// 64-bit atomic operations aren't currently supported on MIPS.
|
||||
continue
|
||||
}
|
||||
}
|
||||
if options.Target == "simavr" {
|
||||
// Not all tests are currently supported on AVR.
|
||||
// Skip the ones that aren't.
|
||||
@@ -226,6 +247,14 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
default:
|
||||
}
|
||||
}
|
||||
if options.Target == "wasip2" {
|
||||
switch name {
|
||||
case "cgo/":
|
||||
// waisp2 use our own libc; cgo tests fail
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
name := name // redefine to avoid race condition
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
@@ -246,13 +275,13 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
runTest("alias.go", options, t, nil, nil)
|
||||
})
|
||||
}
|
||||
if options.Target == "" || options.Target == "wasi" {
|
||||
if options.Target == "" || isWASI {
|
||||
t.Run("filesystem.go", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
runTest("filesystem.go", options, t, nil, nil)
|
||||
})
|
||||
}
|
||||
if options.Target == "" || options.Target == "wasi" || options.Target == "wasm" {
|
||||
if options.Target == "" || options.Target == "wasm" || isWASI {
|
||||
t.Run("rand.go", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
runTest("rand.go", options, t, nil, nil)
|
||||
@@ -288,6 +317,10 @@ func emuCheck(t *testing.T, options compileopts.Options) {
|
||||
}
|
||||
|
||||
func optionsFromTarget(target string, sema chan struct{}) compileopts.Options {
|
||||
separators := strings.Count(target, "/")
|
||||
if (separators == 1 || separators == 2) && !strings.HasSuffix(target, ".json") {
|
||||
return optionsFromOSARCH(target, sema)
|
||||
}
|
||||
return compileopts.Options{
|
||||
// GOOS/GOARCH are only used if target == ""
|
||||
GOOS: goenv.Get("GOOS"),
|
||||
@@ -333,8 +366,11 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
path := TESTDATA + "/" + name
|
||||
// Get the expected output for this test.
|
||||
txtpath := path[:len(path)-3] + ".txt"
|
||||
pkgName := "./" + path
|
||||
if path[len(path)-1] == '/' {
|
||||
txtpath = path + "out.txt"
|
||||
options.Directory = path
|
||||
pkgName = "."
|
||||
}
|
||||
expected, err := os.ReadFile(txtpath)
|
||||
if err != nil {
|
||||
@@ -348,11 +384,15 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
|
||||
// Build the test binary.
|
||||
stdout := &bytes.Buffer{}
|
||||
_, err = buildAndRun("./"+path, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
_, err = buildAndRun(pkgName, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
return cmd.Run()
|
||||
})
|
||||
if err != nil {
|
||||
printCompilerError(t.Log, err)
|
||||
w := &bytes.Buffer{}
|
||||
diagnostics.CreateDiagnostics(err).WriteTo(w, "")
|
||||
for _, line := range strings.Split(strings.TrimRight(w.String(), "\n"), "\n") {
|
||||
t.Log(line)
|
||||
}
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
@@ -381,6 +421,7 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
fail = true
|
||||
} else if !bytes.Equal(expected, actual) {
|
||||
t.Logf("output did not match (expected %d bytes, got %d bytes):", len(expected), len(actual))
|
||||
t.Logf(string(Diff("expected", expected, "actual", actual)))
|
||||
fail = true
|
||||
}
|
||||
|
||||
@@ -397,6 +438,64 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
}
|
||||
}
|
||||
|
||||
// Test WebAssembly files for certain properties.
|
||||
func TestWebAssembly(t *testing.T) {
|
||||
t.Parallel()
|
||||
type testCase struct {
|
||||
name string
|
||||
panicStrategy string
|
||||
imports []string
|
||||
}
|
||||
for _, tc := range []testCase{
|
||||
// Test whether there really are no imports when using -panic=trap. This
|
||||
// tests the bugfix for https://github.com/tinygo-org/tinygo/issues/4161.
|
||||
{name: "panic-default", imports: []string{"wasi_snapshot_preview1.fd_write"}},
|
||||
{name: "panic-trap", panicStrategy: "trap", imports: []string{}},
|
||||
} {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpdir := t.TempDir()
|
||||
options := optionsFromTarget("wasi", sema)
|
||||
options.PanicStrategy = tc.panicStrategy
|
||||
config, err := builder.NewConfig(&options)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
result, err := builder.Build("testdata/trivialpanic.go", ".wasm", tmpdir, config)
|
||||
if err != nil {
|
||||
t.Fatal("failed to build binary:", err)
|
||||
}
|
||||
f, err := os.Open(result.Binary)
|
||||
if err != nil {
|
||||
t.Fatal("could not open output binary:", err)
|
||||
}
|
||||
defer f.Close()
|
||||
module, err := wasm.Parse(f)
|
||||
if err != nil {
|
||||
t.Fatal("could not parse output binary:", err)
|
||||
}
|
||||
|
||||
// Test the list of imports.
|
||||
if tc.imports != nil {
|
||||
var imports []string
|
||||
for _, section := range module.Sections {
|
||||
switch section := section.(type) {
|
||||
case *wasm.SectionImport:
|
||||
for _, symbol := range section.Entries {
|
||||
imports = append(imports, symbol.Module+"."+symbol.Field)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !slices.Equal(imports, tc.imports) {
|
||||
t.Errorf("import list not as expected!\nexpected: %v\nactual: %v", tc.imports, imports)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTest(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -425,7 +524,7 @@ func TestTest(t *testing.T) {
|
||||
|
||||
// Node/Wasmtime
|
||||
targ{"WASM", optionsFromTarget("wasm", sema)},
|
||||
targ{"WASI", optionsFromTarget("wasi", sema)},
|
||||
targ{"WASI", optionsFromTarget("wasip1", sema)},
|
||||
)
|
||||
}
|
||||
for _, targ := range targs {
|
||||
|
||||
+143
-32
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"debug/dwarf"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
@@ -9,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
@@ -17,7 +19,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-tty"
|
||||
"github.com/tinygo-org/tinygo/builder"
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
|
||||
"go.bug.st/serial"
|
||||
@@ -25,44 +26,151 @@ import (
|
||||
)
|
||||
|
||||
// Monitor connects to the given port and reads/writes the serial port.
|
||||
func Monitor(executable, port string, options *compileopts.Options) error {
|
||||
config, err := builder.NewConfig(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func Monitor(executable, port string, config *compileopts.Config) error {
|
||||
const timeout = time.Second * 3
|
||||
var exit func() // function to be called before exiting
|
||||
var serialConn io.ReadWriter
|
||||
|
||||
wait := 300
|
||||
for i := 0; i <= wait; i++ {
|
||||
port, err = getDefaultPort(port, config.Target.SerialPort)
|
||||
if config.Options.Serial == "rtt" {
|
||||
// Use the RTT interface, which is documented (in part) here:
|
||||
// https://wiki.segger.com/RTT
|
||||
|
||||
// Try to find the "machine.rttSerialInstance" symbol, which is the RTT
|
||||
// control block.
|
||||
file, err := elf.Open(executable)
|
||||
if err != nil {
|
||||
if i < wait {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
continue
|
||||
return fmt.Errorf("could not open ELF file to determine RTT control block: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
symbols, err := file.Symbols()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read ELF symbol table to determine RTT control block: %w", err)
|
||||
}
|
||||
var address uint64
|
||||
for _, symbol := range symbols {
|
||||
if symbol.Name == "machine.rttSerialInstance" {
|
||||
address = symbol.Value
|
||||
break
|
||||
}
|
||||
}
|
||||
if address == 0 {
|
||||
return fmt.Errorf("could not find RTT control block in ELF file")
|
||||
}
|
||||
|
||||
// Start an openocd process in the background.
|
||||
args, err := config.OpenOCDConfiguration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
br := options.BaudRate
|
||||
if br <= 0 {
|
||||
br = 115200
|
||||
}
|
||||
|
||||
wait = 300
|
||||
var p serial.Port
|
||||
for i := 0; i <= wait; i++ {
|
||||
p, err = serial.Open(port, &serial.Mode{BaudRate: br})
|
||||
args = append(args,
|
||||
"-c", fmt.Sprintf("rtt setup 0x%x 16 \"SEGGER RTT\"", address),
|
||||
"-c", "init",
|
||||
"-c", "rtt server start 0 0")
|
||||
cmd := executeCommand(config.Options, "openocd", args...)
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
if i < wait {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
break
|
||||
cmd.Stdout = os.Stdout
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cmd.Process.Kill()
|
||||
exit = func() {
|
||||
// Make sure the openocd process is terminated at exit.
|
||||
// This does not happen through the defer above when exiting through
|
||||
// os.Exit.
|
||||
cmd.Process.Kill()
|
||||
}
|
||||
|
||||
// Read the stderr, which logs various important messages we need.
|
||||
r := bufio.NewReader(stderr)
|
||||
var telnet net.Conn
|
||||
var timeoutAt time.Time
|
||||
for {
|
||||
// Read the next line from the openocd process.
|
||||
lineBytes, err := r.ReadBytes('\n')
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
line := string(lineBytes)
|
||||
|
||||
if line == "Info : rtt: No control block found\n" {
|
||||
// Message that is sent back when OpenOCD can't find the control
|
||||
// block after a 'rtt start' message.
|
||||
if time.Now().After(timeoutAt) {
|
||||
return fmt.Errorf("RTT timeout (could not locate RTT control block at 0x%08x)", address)
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
telnet.Write([]byte("rtt start\r\n"))
|
||||
} else if strings.HasPrefix(line, "Info : Listening on port") {
|
||||
// We need two different ports for controlling OpenOCD
|
||||
// (typically port 4444) and the RTT channel 0 socket (arbitrary
|
||||
// port).
|
||||
var port int
|
||||
var protocol string
|
||||
fmt.Sscanf(line, "Info : Listening on port %d for %s connections\n", &port, &protocol)
|
||||
if protocol == "telnet" && telnet == nil {
|
||||
// Connect to the "telnet" command line interface.
|
||||
telnet, err = net.Dial("tcp4", fmt.Sprintf("localhost:%d", port))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Tell OpenOCD to start scanning for the RTT control block.
|
||||
telnet.Write([]byte("rtt start\r\n"))
|
||||
// Also make sure we will time out if the control block just
|
||||
// can't be found.
|
||||
timeoutAt = time.Now().Add(timeout)
|
||||
} else if protocol == "rtt" {
|
||||
// Connect to the RTT channel, for both stdin and stdout.
|
||||
conn, err := net.Dial("tcp4", fmt.Sprintf("localhost:%d", port))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serialConn = conn
|
||||
}
|
||||
} else if strings.HasPrefix(line, "Info : rtt: Control block found at") {
|
||||
// Connection established!
|
||||
break
|
||||
}
|
||||
}
|
||||
} else { // -serial=uart or -serial=usb
|
||||
var err error
|
||||
wait := 300
|
||||
for i := 0; i <= wait; i++ {
|
||||
port, err = getDefaultPort(port, config.Target.SerialPort)
|
||||
if err != nil {
|
||||
if i < wait {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
br := config.Options.BaudRate
|
||||
if br <= 0 {
|
||||
br = 115200
|
||||
}
|
||||
|
||||
wait = 300
|
||||
var p serial.Port
|
||||
for i := 0; i <= wait; i++ {
|
||||
p, err = serial.Open(port, &serial.Mode{BaudRate: br})
|
||||
if err != nil {
|
||||
if i < wait {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
serialConn = p
|
||||
break
|
||||
}
|
||||
defer p.Close()
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
tty, err := tty.Open()
|
||||
if err != nil {
|
||||
@@ -77,6 +185,9 @@ func Monitor(executable, port string, options *compileopts.Options) error {
|
||||
go func() {
|
||||
<-sig
|
||||
tty.Close()
|
||||
if exit != nil {
|
||||
exit()
|
||||
}
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
@@ -88,7 +199,7 @@ func Monitor(executable, port string, options *compileopts.Options) error {
|
||||
buf := make([]byte, 100*1024)
|
||||
var line []byte
|
||||
for {
|
||||
n, err := p.Read(buf)
|
||||
n, err := serialConn.Read(buf)
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("read error: %w", err)
|
||||
return
|
||||
@@ -124,7 +235,7 @@ func Monitor(executable, port string, options *compileopts.Options) error {
|
||||
if r == 0 {
|
||||
continue
|
||||
}
|
||||
p.Write([]byte(string(r)))
|
||||
serialConn.Write([]byte(string(r)))
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
ignoreGeneratedHeader = false
|
||||
severity = "warning"
|
||||
confidence = 0.8
|
||||
errorCode = 0
|
||||
warningCode = 0
|
||||
|
||||
# Enable these as we fix them
|
||||
[rule.blank-imports]
|
||||
Exclude=["src/os/file_other.go"]
|
||||
[rule.context-as-argument]
|
||||
[rule.context-keys-type]
|
||||
[rule.dot-imports]
|
||||
Exclude=["**/*_test.go"]
|
||||
[rule.error-return]
|
||||
[rule.error-strings]
|
||||
[rule.error-naming]
|
||||
[rule.exported]
|
||||
Exclude=["src/reflect/*.go"]
|
||||
[rule.increment-decrement]
|
||||
[rule.var-naming]
|
||||
Exclude=["src/os/*.go"]
|
||||
[rule.var-declaration]
|
||||
#[rule.package-comments]
|
||||
[rule.range]
|
||||
[rule.receiver-naming]
|
||||
[rule.time-naming]
|
||||
[rule.unexported-return]
|
||||
#[rule.indent-error-flow]
|
||||
[rule.errorf]
|
||||
#[rule.empty-block]
|
||||
[rule.superfluous-else]
|
||||
#[rule.unused-parameter]
|
||||
[rule.unreachable-code]
|
||||
Exclude=["src/reflect/visiblefields_test.go", "src/reflect/all_test.go"]
|
||||
#[rule.redefines-builtin-id]
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build darwin || tinygo.wasm
|
||||
//go:build darwin || wasip1 || wasip2 || wasm
|
||||
|
||||
// This implementation of crypto/rand uses the arc4random_buf function
|
||||
// (available on both MacOS and WASI) to generate random numbers.
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
//go:build nrf || stm32 || (sam && atsamd51) || (sam && atsame5x)
|
||||
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3
|
||||
|
||||
// If you update the above build constraint, you'll probably also need to update
|
||||
// src/runtime/rand_hwrng.go.
|
||||
|
||||
package rand
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build linux && !baremetal && !wasi
|
||||
//go:build linux && !baremetal && !wasip1 && !wasip2
|
||||
|
||||
// This implementation of crypto/rand uses the /dev/urandom pseudo-file to
|
||||
// generate random numbers.
|
||||
|
||||
@@ -0,0 +1,460 @@
|
||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package tls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CurveID is the type of a TLS identifier for an elliptic curve. See
|
||||
// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8.
|
||||
//
|
||||
// In TLS 1.3, this type is called NamedGroup, but at this time this library
|
||||
// only supports Elliptic Curve based groups. See RFC 8446, Section 4.2.7.
|
||||
type CurveID uint16
|
||||
|
||||
// CipherSuiteName returns the standard name for the passed cipher suite ID
|
||||
//
|
||||
// Not Implemented.
|
||||
func CipherSuiteName(id uint16) string {
|
||||
return fmt.Sprintf("0x%04X", id)
|
||||
}
|
||||
|
||||
// ConnectionState records basic TLS details about the connection.
|
||||
type ConnectionState struct {
|
||||
// TINYGO: empty; TLS connection offloaded to device
|
||||
//
|
||||
// Minimum (empty) fields for fortio.org/log http logging and others
|
||||
// to compile and run.
|
||||
PeerCertificates []*x509.Certificate
|
||||
CipherSuite uint16
|
||||
}
|
||||
|
||||
// ClientAuthType declares the policy the server will follow for
|
||||
// TLS Client Authentication.
|
||||
type ClientAuthType int
|
||||
|
||||
// ClientSessionCache is a cache of ClientSessionState objects that can be used
|
||||
// by a client to resume a TLS session with a given server. ClientSessionCache
|
||||
// implementations should expect to be called concurrently from different
|
||||
// goroutines. Up to TLS 1.2, only ticket-based resumption is supported, not
|
||||
// SessionID-based resumption. In TLS 1.3 they were merged into PSK modes, which
|
||||
// are supported via this interface.
|
||||
type ClientSessionCache interface {
|
||||
// Get searches for a ClientSessionState associated with the given key.
|
||||
// On return, ok is true if one was found.
|
||||
Get(sessionKey string) (session *ClientSessionState, ok bool)
|
||||
|
||||
// Put adds the ClientSessionState to the cache with the given key. It might
|
||||
// get called multiple times in a connection if a TLS 1.3 server provides
|
||||
// more than one session ticket. If called with a nil *ClientSessionState,
|
||||
// it should remove the cache entry.
|
||||
Put(sessionKey string, cs *ClientSessionState)
|
||||
}
|
||||
|
||||
//go:generate stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go
|
||||
|
||||
// SignatureScheme identifies a signature algorithm supported by TLS. See
|
||||
// RFC 8446, Section 4.2.3.
|
||||
type SignatureScheme uint16
|
||||
|
||||
// ClientHelloInfo contains information from a ClientHello message in order to
|
||||
// guide application logic in the GetCertificate and GetConfigForClient callbacks.
|
||||
type ClientHelloInfo struct {
|
||||
// CipherSuites lists the CipherSuites supported by the client (e.g.
|
||||
// TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).
|
||||
CipherSuites []uint16
|
||||
|
||||
// ServerName indicates the name of the server requested by the client
|
||||
// in order to support virtual hosting. ServerName is only set if the
|
||||
// client is using SNI (see RFC 4366, Section 3.1).
|
||||
ServerName string
|
||||
|
||||
// SupportedCurves lists the elliptic curves supported by the client.
|
||||
// SupportedCurves is set only if the Supported Elliptic Curves
|
||||
// Extension is being used (see RFC 4492, Section 5.1.1).
|
||||
SupportedCurves []CurveID
|
||||
|
||||
// SupportedPoints lists the point formats supported by the client.
|
||||
// SupportedPoints is set only if the Supported Point Formats Extension
|
||||
// is being used (see RFC 4492, Section 5.1.2).
|
||||
SupportedPoints []uint8
|
||||
|
||||
// SignatureSchemes lists the signature and hash schemes that the client
|
||||
// is willing to verify. SignatureSchemes is set only if the Signature
|
||||
// Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1).
|
||||
SignatureSchemes []SignatureScheme
|
||||
|
||||
// SupportedProtos lists the application protocols supported by the client.
|
||||
// SupportedProtos is set only if the Application-Layer Protocol
|
||||
// Negotiation Extension is being used (see RFC 7301, Section 3.1).
|
||||
//
|
||||
// Servers can select a protocol by setting Config.NextProtos in a
|
||||
// GetConfigForClient return value.
|
||||
SupportedProtos []string
|
||||
|
||||
// SupportedVersions lists the TLS versions supported by the client.
|
||||
// For TLS versions less than 1.3, this is extrapolated from the max
|
||||
// version advertised by the client, so values other than the greatest
|
||||
// might be rejected if used.
|
||||
SupportedVersions []uint16
|
||||
|
||||
// Conn is the underlying net.Conn for the connection. Do not read
|
||||
// from, or write to, this connection; that will cause the TLS
|
||||
// connection to fail.
|
||||
Conn net.Conn
|
||||
|
||||
// config is embedded by the GetCertificate or GetConfigForClient caller,
|
||||
// for use with SupportsCertificate.
|
||||
config *Config
|
||||
|
||||
// ctx is the context of the handshake that is in progress.
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// CertificateRequestInfo contains information from a server's
|
||||
// CertificateRequest message, which is used to demand a certificate and proof
|
||||
// of control from a client.
|
||||
type CertificateRequestInfo struct {
|
||||
// AcceptableCAs contains zero or more, DER-encoded, X.501
|
||||
// Distinguished Names. These are the names of root or intermediate CAs
|
||||
// that the server wishes the returned certificate to be signed by. An
|
||||
// empty slice indicates that the server has no preference.
|
||||
AcceptableCAs [][]byte
|
||||
|
||||
// SignatureSchemes lists the signature schemes that the server is
|
||||
// willing to verify.
|
||||
SignatureSchemes []SignatureScheme
|
||||
|
||||
// Version is the TLS version that was negotiated for this connection.
|
||||
Version uint16
|
||||
|
||||
// ctx is the context of the handshake that is in progress.
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// RenegotiationSupport enumerates the different levels of support for TLS
|
||||
// renegotiation. TLS renegotiation is the act of performing subsequent
|
||||
// handshakes on a connection after the first. This significantly complicates
|
||||
// the state machine and has been the source of numerous, subtle security
|
||||
// issues. Initiating a renegotiation is not supported, but support for
|
||||
// accepting renegotiation requests may be enabled.
|
||||
//
|
||||
// Even when enabled, the server may not change its identity between handshakes
|
||||
// (i.e. the leaf certificate must be the same). Additionally, concurrent
|
||||
// handshake and application data flow is not permitted so renegotiation can
|
||||
// only be used with protocols that synchronise with the renegotiation, such as
|
||||
// HTTPS.
|
||||
//
|
||||
// Renegotiation is not defined in TLS 1.3.
|
||||
type RenegotiationSupport int
|
||||
|
||||
// A Config structure is used to configure a TLS client or server.
|
||||
// After one has been passed to a TLS function it must not be
|
||||
// modified. A Config may be reused; the tls package will also not
|
||||
// modify it.
|
||||
type Config struct {
|
||||
// Rand provides the source of entropy for nonces and RSA blinding.
|
||||
// If Rand is nil, TLS uses the cryptographic random reader in package
|
||||
// crypto/rand.
|
||||
// The Reader must be safe for use by multiple goroutines.
|
||||
Rand io.Reader
|
||||
|
||||
// Time returns the current time as the number of seconds since the epoch.
|
||||
// If Time is nil, TLS uses time.Now.
|
||||
Time func() time.Time
|
||||
|
||||
// Certificates contains one or more certificate chains to present to the
|
||||
// other side of the connection. The first certificate compatible with the
|
||||
// peer's requirements is selected automatically.
|
||||
//
|
||||
// Server configurations must set one of Certificates, GetCertificate or
|
||||
// GetConfigForClient. Clients doing client-authentication may set either
|
||||
// Certificates or GetClientCertificate.
|
||||
//
|
||||
// Note: if there are multiple Certificates, and they don't have the
|
||||
// optional field Leaf set, certificate selection will incur a significant
|
||||
// per-handshake performance cost.
|
||||
Certificates []Certificate
|
||||
|
||||
// NameToCertificate maps from a certificate name to an element of
|
||||
// Certificates. Note that a certificate name can be of the form
|
||||
// '*.example.com' and so doesn't have to be a domain name as such.
|
||||
//
|
||||
// Deprecated: NameToCertificate only allows associating a single
|
||||
// certificate with a given name. Leave this field nil to let the library
|
||||
// select the first compatible chain from Certificates.
|
||||
NameToCertificate map[string]*Certificate
|
||||
|
||||
// GetCertificate returns a Certificate based on the given
|
||||
// ClientHelloInfo. It will only be called if the client supplies SNI
|
||||
// information or if Certificates is empty.
|
||||
//
|
||||
// If GetCertificate is nil or returns nil, then the certificate is
|
||||
// retrieved from NameToCertificate. If NameToCertificate is nil, the
|
||||
// best element of Certificates will be used.
|
||||
//
|
||||
// Once a Certificate is returned it should not be modified.
|
||||
GetCertificate func(*ClientHelloInfo) (*Certificate, error)
|
||||
|
||||
// GetClientCertificate, if not nil, is called when a server requests a
|
||||
// certificate from a client. If set, the contents of Certificates will
|
||||
// be ignored.
|
||||
//
|
||||
// If GetClientCertificate returns an error, the handshake will be
|
||||
// aborted and that error will be returned. Otherwise
|
||||
// GetClientCertificate must return a non-nil Certificate. If
|
||||
// Certificate.Certificate is empty then no certificate will be sent to
|
||||
// the server. If this is unacceptable to the server then it may abort
|
||||
// the handshake.
|
||||
//
|
||||
// GetClientCertificate may be called multiple times for the same
|
||||
// connection if renegotiation occurs or if TLS 1.3 is in use.
|
||||
//
|
||||
// Once a Certificate is returned it should not be modified.
|
||||
GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
|
||||
|
||||
// GetConfigForClient, if not nil, is called after a ClientHello is
|
||||
// received from a client. It may return a non-nil Config in order to
|
||||
// change the Config that will be used to handle this connection. If
|
||||
// the returned Config is nil, the original Config will be used. The
|
||||
// Config returned by this callback may not be subsequently modified.
|
||||
//
|
||||
// If GetConfigForClient is nil, the Config passed to Server() will be
|
||||
// used for all connections.
|
||||
//
|
||||
// If SessionTicketKey was explicitly set on the returned Config, or if
|
||||
// SetSessionTicketKeys was called on the returned Config, those keys will
|
||||
// be used. Otherwise, the original Config keys will be used (and possibly
|
||||
// rotated if they are automatically managed).
|
||||
GetConfigForClient func(*ClientHelloInfo) (*Config, error)
|
||||
|
||||
// VerifyPeerCertificate, if not nil, is called after normal
|
||||
// certificate verification by either a TLS client or server. It
|
||||
// receives the raw ASN.1 certificates provided by the peer and also
|
||||
// any verified chains that normal processing found. If it returns a
|
||||
// non-nil error, the handshake is aborted and that error results.
|
||||
//
|
||||
// If normal verification fails then the handshake will abort before
|
||||
// considering this callback. If normal verification is disabled (on the
|
||||
// client when InsecureSkipVerify is set, or on a server when ClientAuth is
|
||||
// RequestClientCert or RequireAnyClientCert), then this callback will be
|
||||
// considered but the verifiedChains argument will always be nil. When
|
||||
// ClientAuth is NoClientCert, this callback is not called on the server.
|
||||
// rawCerts may be empty on the server if ClientAuth is RequestClientCert or
|
||||
// VerifyClientCertIfGiven.
|
||||
//
|
||||
// This callback is not invoked on resumed connections, as certificates are
|
||||
// not re-verified on resumption.
|
||||
//
|
||||
// verifiedChains and its contents should not be modified.
|
||||
VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
|
||||
|
||||
// VerifyConnection, if not nil, is called after normal certificate
|
||||
// verification and after VerifyPeerCertificate by either a TLS client
|
||||
// or server. If it returns a non-nil error, the handshake is aborted
|
||||
// and that error results.
|
||||
//
|
||||
// If normal verification fails then the handshake will abort before
|
||||
// considering this callback. This callback will run for all connections,
|
||||
// including resumptions, regardless of InsecureSkipVerify or ClientAuth
|
||||
// settings.
|
||||
VerifyConnection func(ConnectionState) error
|
||||
|
||||
// RootCAs defines the set of root certificate authorities
|
||||
// that clients use when verifying server certificates.
|
||||
// If RootCAs is nil, TLS uses the host's root CA set.
|
||||
RootCAs *x509.CertPool
|
||||
|
||||
// NextProtos is a list of supported application level protocols, in
|
||||
// order of preference. If both peers support ALPN, the selected
|
||||
// protocol will be one from this list, and the connection will fail
|
||||
// if there is no mutually supported protocol. If NextProtos is empty
|
||||
// or the peer doesn't support ALPN, the connection will succeed and
|
||||
// ConnectionState.NegotiatedProtocol will be empty.
|
||||
NextProtos []string
|
||||
|
||||
// ServerName is used to verify the hostname on the returned
|
||||
// certificates unless InsecureSkipVerify is given. It is also included
|
||||
// in the client's handshake to support virtual hosting unless it is
|
||||
// an IP address.
|
||||
ServerName string
|
||||
|
||||
// ClientAuth determines the server's policy for
|
||||
// TLS Client Authentication. The default is NoClientCert.
|
||||
ClientAuth ClientAuthType
|
||||
|
||||
// ClientCAs defines the set of root certificate authorities
|
||||
// that servers use if required to verify a client certificate
|
||||
// by the policy in ClientAuth.
|
||||
ClientCAs *x509.CertPool
|
||||
|
||||
// InsecureSkipVerify controls whether a client verifies the server's
|
||||
// certificate chain and host name. If InsecureSkipVerify is true, crypto/tls
|
||||
// accepts any certificate presented by the server and any host name in that
|
||||
// certificate. In this mode, TLS is susceptible to machine-in-the-middle
|
||||
// attacks unless custom verification is used. This should be used only for
|
||||
// testing or in combination with VerifyConnection or VerifyPeerCertificate.
|
||||
InsecureSkipVerify bool
|
||||
|
||||
// CipherSuites is a list of enabled TLS 1.0–1.2 cipher suites. The order of
|
||||
// the list is ignored. Note that TLS 1.3 ciphersuites are not configurable.
|
||||
//
|
||||
// If CipherSuites is nil, a safe default list is used. The default cipher
|
||||
// suites might change over time.
|
||||
CipherSuites []uint16
|
||||
|
||||
// PreferServerCipherSuites is a legacy field and has no effect.
|
||||
//
|
||||
// It used to control whether the server would follow the client's or the
|
||||
// server's preference. Servers now select the best mutually supported
|
||||
// cipher suite based on logic that takes into account inferred client
|
||||
// hardware, server hardware, and security.
|
||||
//
|
||||
// Deprecated: PreferServerCipherSuites is ignored.
|
||||
PreferServerCipherSuites bool
|
||||
|
||||
// SessionTicketsDisabled may be set to true to disable session ticket and
|
||||
// PSK (resumption) support. Note that on clients, session ticket support is
|
||||
// also disabled if ClientSessionCache is nil.
|
||||
SessionTicketsDisabled bool
|
||||
|
||||
// SessionTicketKey is used by TLS servers to provide session resumption.
|
||||
// See RFC 5077 and the PSK mode of RFC 8446. If zero, it will be filled
|
||||
// with random data before the first server handshake.
|
||||
//
|
||||
// Deprecated: if this field is left at zero, session ticket keys will be
|
||||
// automatically rotated every day and dropped after seven days. For
|
||||
// customizing the rotation schedule or synchronizing servers that are
|
||||
// terminating connections for the same host, use SetSessionTicketKeys.
|
||||
SessionTicketKey [32]byte
|
||||
|
||||
// ClientSessionCache is a cache of ClientSessionState entries for TLS
|
||||
// session resumption. It is only used by clients.
|
||||
ClientSessionCache ClientSessionCache
|
||||
|
||||
// UnwrapSession is called on the server to turn a ticket/identity
|
||||
// previously produced by [WrapSession] into a usable session.
|
||||
//
|
||||
// UnwrapSession will usually either decrypt a session state in the ticket
|
||||
// (for example with [Config.EncryptTicket]), or use the ticket as a handle
|
||||
// to recover a previously stored state. It must use [ParseSessionState] to
|
||||
// deserialize the session state.
|
||||
//
|
||||
// If UnwrapSession returns an error, the connection is terminated. If it
|
||||
// returns (nil, nil), the session is ignored. crypto/tls may still choose
|
||||
// not to resume the returned session.
|
||||
UnwrapSession func(identity []byte, cs ConnectionState) (*SessionState, error)
|
||||
|
||||
// WrapSession is called on the server to produce a session ticket/identity.
|
||||
//
|
||||
// WrapSession must serialize the session state with [SessionState.Bytes].
|
||||
// It may then encrypt the serialized state (for example with
|
||||
// [Config.DecryptTicket]) and use it as the ticket, or store the state and
|
||||
// return a handle for it.
|
||||
//
|
||||
// If WrapSession returns an error, the connection is terminated.
|
||||
//
|
||||
// Warning: the return value will be exposed on the wire and to clients in
|
||||
// plaintext. The application is in charge of encrypting and authenticating
|
||||
// it (and rotating keys) or returning high-entropy identifiers. Failing to
|
||||
// do so correctly can compromise current, previous, and future connections
|
||||
// depending on the protocol version.
|
||||
WrapSession func(ConnectionState, *SessionState) ([]byte, error)
|
||||
|
||||
// MinVersion contains the minimum TLS version that is acceptable.
|
||||
//
|
||||
// By default, TLS 1.2 is currently used as the minimum when acting as a
|
||||
// client, and TLS 1.0 when acting as a server. TLS 1.0 is the minimum
|
||||
// supported by this package, both as a client and as a server.
|
||||
//
|
||||
// The client-side default can temporarily be reverted to TLS 1.0 by
|
||||
// including the value "x509sha1=1" in the GODEBUG environment variable.
|
||||
// Note that this option will be removed in Go 1.19 (but it will still be
|
||||
// possible to set this field to VersionTLS10 explicitly).
|
||||
MinVersion uint16
|
||||
|
||||
// MaxVersion contains the maximum TLS version that is acceptable.
|
||||
//
|
||||
// By default, the maximum version supported by this package is used,
|
||||
// which is currently TLS 1.3.
|
||||
MaxVersion uint16
|
||||
|
||||
// CurvePreferences contains the elliptic curves that will be used in
|
||||
// an ECDHE handshake, in preference order. If empty, the default will
|
||||
// be used. The client will use the first preference as the type for
|
||||
// its key share in TLS 1.3. This may change in the future.
|
||||
CurvePreferences []CurveID
|
||||
|
||||
// DynamicRecordSizingDisabled disables adaptive sizing of TLS records.
|
||||
// When true, the largest possible TLS record size is always used. When
|
||||
// false, the size of TLS records may be adjusted in an attempt to
|
||||
// improve latency.
|
||||
DynamicRecordSizingDisabled bool
|
||||
|
||||
// Renegotiation controls what types of renegotiation are supported.
|
||||
// The default, none, is correct for the vast majority of applications.
|
||||
Renegotiation RenegotiationSupport
|
||||
|
||||
// KeyLogWriter optionally specifies a destination for TLS master secrets
|
||||
// in NSS key log format that can be used to allow external programs
|
||||
// such as Wireshark to decrypt TLS connections.
|
||||
// See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
|
||||
// Use of KeyLogWriter compromises security and should only be
|
||||
// used for debugging.
|
||||
KeyLogWriter io.Writer
|
||||
|
||||
// mutex protects sessionTicketKeys and autoSessionTicketKeys.
|
||||
mutex sync.RWMutex
|
||||
// sessionTicketKeys contains zero or more ticket keys. If set, it means
|
||||
// the keys were set with SessionTicketKey or SetSessionTicketKeys. The
|
||||
// first key is used for new tickets and any subsequent keys can be used to
|
||||
// decrypt old tickets. The slice contents are not protected by the mutex
|
||||
// and are immutable.
|
||||
sessionTicketKeys []ticketKey
|
||||
// autoSessionTicketKeys is like sessionTicketKeys but is owned by the
|
||||
// auto-rotation logic. See Config.ticketKeys.
|
||||
autoSessionTicketKeys []ticketKey
|
||||
}
|
||||
|
||||
// ticketKey is the internal representation of a session ticket key.
|
||||
type ticketKey struct {
|
||||
aesKey [16]byte
|
||||
hmacKey [16]byte
|
||||
// created is the time at which this ticket key was created. See Config.ticketKeys.
|
||||
created time.Time
|
||||
}
|
||||
|
||||
// A Certificate is a chain of one or more certificates, leaf first.
|
||||
type Certificate struct {
|
||||
Certificate [][]byte
|
||||
// PrivateKey contains the private key corresponding to the public key in
|
||||
// Leaf. This must implement crypto.Signer with an RSA, ECDSA or Ed25519 PublicKey.
|
||||
// For a server up to TLS 1.2, it can also implement crypto.Decrypter with
|
||||
// an RSA PublicKey.
|
||||
PrivateKey crypto.PrivateKey
|
||||
// SupportedSignatureAlgorithms is an optional list restricting what
|
||||
// signature algorithms the PrivateKey can be used for.
|
||||
SupportedSignatureAlgorithms []SignatureScheme
|
||||
// OCSPStaple contains an optional OCSP response which will be served
|
||||
// to clients that request it.
|
||||
OCSPStaple []byte
|
||||
// SignedCertificateTimestamps contains an optional list of Signed
|
||||
// Certificate Timestamps which will be served to clients that request it.
|
||||
SignedCertificateTimestamps [][]byte
|
||||
// Leaf is the parsed form of the leaf certificate, which may be initialized
|
||||
// using x509.ParseCertificate to reduce per-handshake processing. If nil,
|
||||
// the leaf certificate will be parsed as needed.
|
||||
Leaf *x509.Certificate
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user